You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
353 lines
16 KiB
353 lines
16 KiB
<?php
|
|
|
|
namespace App\Jobs;
|
|
|
|
use App\Models\InsideTradeBuy;
|
|
use App\Models\InsideTradeOrder;
|
|
use App\Models\InsideTradeSell;
|
|
use App\Models\User;
|
|
use App\Models\UserWallet;
|
|
use App\Services\InsideTradeService;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Bus\Queueable;
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
use Illuminate\Foundation\Bus\Dispatchable;
|
|
use Illuminate\Queue\InteractsWithQueue;
|
|
use Illuminate\Queue\SerializesModels;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class HandleEntrust implements ShouldQueue
|
|
{
|
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
|
|
/**
|
|
* 任务可以尝试的最大次数。
|
|
*
|
|
* @var int
|
|
*/
|
|
public $tries = 3;
|
|
|
|
private $entrust;
|
|
|
|
/**
|
|
* Create a new job instance.
|
|
*
|
|
* @param $entrust
|
|
*/
|
|
public function __construct($entrust)
|
|
{
|
|
$this->entrust = $entrust;
|
|
}
|
|
|
|
/**
|
|
* Execute the job.
|
|
*
|
|
* @return void
|
|
* @throws \Exception
|
|
*/
|
|
public function handle()
|
|
{
|
|
$entrust = $this->entrust;
|
|
if (blank($entrust)) return;
|
|
|
|
$where_data = [
|
|
'quote_coin_id' => $entrust['quote_coin_id'],
|
|
'base_coin_id' => $entrust['base_coin_id'],
|
|
'entrust_price' => $entrust['entrust_price'],
|
|
'user_id' => $entrust['user_id'],
|
|
];
|
|
if ($entrust['entrust_type'] == 1) {
|
|
if (!$entrust->can_trade()) return;
|
|
//限价交易 获取可交易卖单 撮单
|
|
//市价交易 吃单
|
|
//获取可交易列表
|
|
$sellList = InsideTradeSell::getSellTradeList($entrust['type'], $where_data);
|
|
if (blank($sellList)) {
|
|
//卖单盘口 没有可交易订单
|
|
$flag = false;
|
|
if ($entrust['type'] == 1 || $entrust['type'] == 3) {
|
|
// 获取最新一条成交记录 即实时最新价格
|
|
$cacheKey = 'market:' . strtolower(str_before($entrust['symbol'], '/') . str_after($entrust['symbol'], '/')) . '_newPrice';
|
|
$realtime_price = Cache::store('redis')->get($cacheKey)['price'] ?? null;
|
|
if ($entrust['entrust_price'] >= $realtime_price) $flag = true;
|
|
} else {
|
|
$flag = true;
|
|
}
|
|
if ($flag) {
|
|
(new InsideTradeService())->handleBuyOrder($entrust);
|
|
}
|
|
} else {
|
|
//有可交易订单 撮单
|
|
DB::beginTransaction();
|
|
try {
|
|
|
|
$this->handleBuyTrade($entrust, $sellList);
|
|
|
|
DB::commit();
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
throw $e;
|
|
}
|
|
}
|
|
} else {
|
|
if (!$entrust->can_trade()) return;
|
|
//限价交易 获取可交易买单 撮单
|
|
//市价交易 吃单
|
|
//获取可交易列表
|
|
$buyList = InsideTradeBuy::getBuyTradeList($entrust['type'], $where_data);
|
|
if (blank($buyList)) {
|
|
//卖单盘口 没有可交易订单
|
|
$flag = false;
|
|
if ($entrust['type'] == 1 || $entrust['type'] == 3) {
|
|
// 获取最新一条成交记录 即实时最新价格
|
|
$cacheKey = 'market:' . strtolower(str_before($entrust['symbol'], '/') . str_after($entrust['symbol'], '/')) . '_newPrice';
|
|
$realtime_price = Cache::store('redis')->get($cacheKey)['price'] ?? null;
|
|
if ($entrust['entrust_price'] <= $realtime_price) $flag = true;
|
|
} else {
|
|
$flag = true;
|
|
}
|
|
if ($flag) {
|
|
(new InsideTradeService())->handleSellOrder($entrust);
|
|
}
|
|
} else {
|
|
//有可交易订单 撮单
|
|
DB::beginTransaction();
|
|
try {
|
|
|
|
$this->handleSellTrade($entrust, $buyList);
|
|
|
|
DB::commit();
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
throw $e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public function handleBuyTrade($entrust, $sellList)
|
|
{
|
|
$maker_fee_rate = get_setting_value('maker_fee_rate', 'exchange', 0.002); //交易手续费比率
|
|
$taker_fee_rate = get_setting_value('taker_fee_rate', 'exchange', 0.002); //交易手续费比率
|
|
$entrust_amount = $entrust['amount'];
|
|
$entrust_money = $entrust['money'];
|
|
$entrust_traded_amount = $entrust['traded_amount']; //交易量 单位:exchange_coin
|
|
$entrust_traded_money = $entrust['traded_money']; //交易额 单位:base_coin
|
|
foreach ($sellList as $tradeSell) {
|
|
//获取可交易量、可交易额
|
|
if ($entrust['type'] == 1 || $entrust['type'] == 3) {
|
|
//买单限价委托 可与卖单限价委托和市价委托交易
|
|
$entrust_surplus_amount = $entrust['amount'] - $entrust_traded_amount; //剩余交易量 计量单位
|
|
$exchange_amount = min($entrust_surplus_amount, $tradeSell['surplus_amount']);
|
|
if ($tradeSell['type'] == 1 || $tradeSell['type'] == 3) {
|
|
$unit_price = min($entrust['entrust_price'], $tradeSell['entrust_price']); //成交价
|
|
} else {
|
|
$unit_price = $entrust['entrust_price']; //成交价
|
|
}
|
|
$exchange_money = $exchange_amount * $unit_price;
|
|
$entrust_amount -= $exchange_amount;
|
|
$entrust_money -= $exchange_money;
|
|
$entrust_traded_amount += $exchange_amount;
|
|
$entrust_traded_money += $exchange_money;
|
|
} else {
|
|
//买单市价委托 只可与卖单限价委托交易
|
|
$entrust_surplus_money = $entrust['money'] - $entrust_traded_money; //剩余交易额 计量单位
|
|
$buy_amount = $entrust_surplus_money / $tradeSell['entrust_price']; //剩余交易量
|
|
$exchange_amount = min($buy_amount, $tradeSell['surplus_amount']);
|
|
$unit_price = $tradeSell['entrust_price']; //成交价
|
|
$exchange_money = $exchange_amount * $unit_price;
|
|
$entrust_amount -= $exchange_amount;
|
|
$entrust_money -= $exchange_money;
|
|
$entrust_traded_amount += $exchange_amount;
|
|
$entrust_traded_money += $exchange_money;
|
|
}
|
|
|
|
//更新卖单
|
|
$sell_traded_amount = $tradeSell['traded_amount'] + $exchange_amount;
|
|
$sell_traded_money = $tradeSell['traded_money'] + $exchange_money;
|
|
if ($sell_traded_amount == $tradeSell['amount']) {
|
|
//卖单全部成交
|
|
$tradeSell->update([
|
|
'traded_amount' => $sell_traded_amount,
|
|
'traded_money' => $sell_traded_money,
|
|
'status' => InsideTradeSell::status_completed,
|
|
]);
|
|
} else {
|
|
//卖单部分成交
|
|
$tradeSell->update([
|
|
'traded_amount' => $sell_traded_amount,
|
|
'traded_money' => $sell_traded_money,
|
|
'status' => InsideTradeSell::status_trading,
|
|
]);
|
|
}
|
|
|
|
$buy_fee = PriceCalculate($exchange_amount, '*', $taker_fee_rate, 8);
|
|
$sell_fee = PriceCalculate($exchange_money, '*', $maker_fee_rate, 8);
|
|
//增加委托成交匹配记录
|
|
InsideTradeOrder::query()->create([
|
|
'buy_order_no' => $entrust['order_no'],
|
|
'sell_order_no' => $tradeSell['order_no'],
|
|
'buy_id' => $entrust['id'],
|
|
'sell_id' => $tradeSell['id'],
|
|
'buy_user_id' => $entrust['user_id'],
|
|
'sell_user_id' => $tradeSell['user_id'],
|
|
'unit_price' => $unit_price,
|
|
'symbol' => $entrust['symbol'],
|
|
'quote_coin_id' => $entrust['quote_coin_id'],
|
|
'base_coin_id' => $entrust['base_coin_id'],
|
|
'trade_amount' => $exchange_amount,
|
|
'trade_money' => $exchange_money,
|
|
'trade_buy_fee' => $buy_fee,
|
|
'trade_sell_fee' => $sell_fee,
|
|
]);
|
|
|
|
//更新用户钱包
|
|
$buy_user = User::query()->find($entrust['user_id']);
|
|
$sell_user = User::query()->find($tradeSell['user_id']);
|
|
//买家得到base_coin_id 扣除quote_coin_id
|
|
$buy_user->update_wallet_and_log($entrust['quote_coin_id'], 'freeze_balance', -$exchange_money, UserWallet::asset_account, 'entrust_exchange');
|
|
$buy_user->update_wallet_and_log($entrust['base_coin_id'], 'usable_balance', $exchange_amount - $buy_fee, UserWallet::asset_account, 'entrust_exchange');
|
|
//卖家得到quote_coin_id 扣除base_coin_id
|
|
$sell_user->update_wallet_and_log($entrust['quote_coin_id'], 'usable_balance', $exchange_money - $sell_fee, UserWallet::asset_account, 'entrust_exchange');
|
|
$sell_user->update_wallet_and_log($entrust['base_coin_id'], 'freeze_balance', -$exchange_amount, UserWallet::asset_account, 'entrust_exchange');
|
|
|
|
//买单委托交易完成 退出循环 更新买单
|
|
if ($entrust['type'] == 1 || $entrust['type'] == 3) {
|
|
if ($entrust_amount == 0) {
|
|
$entrust_update_data = [
|
|
'traded_amount' => $entrust_traded_amount,
|
|
'traded_money' => $entrust_traded_money,
|
|
'status' => InsideTradeBuy::status_completed,
|
|
];
|
|
if (($entrust_surplus_money = $entrust['money'] - $entrust_traded_money) > 0) {
|
|
//买家多余冻结余额返还
|
|
$buy_user->update_wallet_and_log($entrust['quote_coin_id'], 'usable_balance', $entrust_surplus_money, UserWallet::asset_account, 'entrust_exchange');
|
|
$buy_user->update_wallet_and_log($entrust['quote_coin_id'], 'freeze_balance', -$entrust_surplus_money, UserWallet::asset_account, 'entrust_exchange');
|
|
}
|
|
|
|
$entrust->update($entrust_update_data);
|
|
|
|
break;
|
|
} else {
|
|
$entrust->update([
|
|
'traded_amount' => $entrust_traded_amount,
|
|
'traded_money' => $entrust_traded_money,
|
|
'status' => InsideTradeBuy::status_trading,
|
|
]);
|
|
}
|
|
} else {
|
|
if ($entrust_money == 0) {
|
|
$entrust->update([
|
|
'traded_amount' => $entrust_traded_amount,
|
|
'traded_money' => $entrust_traded_money,
|
|
'status' => InsideTradeBuy::status_completed,
|
|
]);
|
|
break;
|
|
} else {
|
|
$entrust->update([
|
|
'traded_amount' => $entrust_traded_amount,
|
|
'traded_money' => $entrust_traded_money,
|
|
'status' => InsideTradeBuy::status_trading,
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public function handleSellTrade($entrust, $buyList)
|
|
{
|
|
$maker_fee_rate = get_setting_value('maker_fee_rate', 'exchange', 0.002); //交易手续费比率
|
|
$taker_fee_rate = get_setting_value('taker_fee_rate', 'exchange', 0.002); //交易手续费比率
|
|
$entrust_amount = $entrust['amount'];
|
|
$entrust_traded_amount = $entrust['traded_amount']; //交易量 单位:exchange_coin
|
|
$entrust_traded_money = $entrust['traded_money']; //交易额 单位:base_coin
|
|
foreach ($buyList as $tradeBuy) {
|
|
//卖单限价委托 可与买单限价委托和市价委托交易 (卖单委托计量单位都是交易量amount)
|
|
//卖单市价委托 只可与买单限价委托交易
|
|
$entrust_surplus_amount = $entrust['amount'] - $entrust_traded_amount; //剩余交易量 计量单位
|
|
if ($tradeBuy['type'] == 1 || $tradeBuy['type'] == 3) {
|
|
if ($entrust['type'] == 1 || $entrust['type'] == 3) {
|
|
// $unit_price = max($entrust['entrust_price'],$tradeBuy['entrust_price']);
|
|
$unit_price = min($entrust['entrust_price'], $tradeBuy['entrust_price']);
|
|
} else {
|
|
$unit_price = $tradeBuy['entrust_price'];
|
|
}
|
|
$exchange_amount = min($entrust_surplus_amount, $tradeBuy['surplus_amount']);
|
|
} else {
|
|
$unit_price = $entrust['entrust_price'];
|
|
$buy_surplus_amount = $tradeBuy['money'] / $unit_price; //计算买单可交易量
|
|
$exchange_amount = min($entrust_surplus_amount, $buy_surplus_amount);
|
|
}
|
|
$exchange_money = $exchange_amount * $unit_price;
|
|
$entrust_amount -= $exchange_amount;
|
|
$entrust_traded_amount += $exchange_amount;
|
|
$entrust_traded_money += $exchange_money;
|
|
|
|
$buy_traded_amount = $tradeBuy['traded_amount'] + $exchange_amount;
|
|
$buy_traded_money = $tradeBuy['traded_money'] + $exchange_money;
|
|
|
|
if (($tradeBuy['type'] == 1 && $buy_traded_amount == $tradeBuy['amount']) || ($tradeBuy['type'] == 2 && $buy_traded_money == $tradeBuy['money'])) {
|
|
//买单全部成交
|
|
$tradeBuy->update([
|
|
'traded_amount' => $buy_traded_amount,
|
|
'traded_money' => $buy_traded_money,
|
|
'status' => InsideTradeBuy::status_completed,
|
|
]);
|
|
} else {
|
|
//买单部分成交
|
|
$tradeBuy->update([
|
|
'traded_amount' => $buy_traded_amount,
|
|
'traded_money' => $buy_traded_money,
|
|
'status' => InsideTradeBuy::status_trading,
|
|
]);
|
|
}
|
|
|
|
$buy_fee = PriceCalculate($exchange_amount, '*', $maker_fee_rate, 8);
|
|
$sell_fee = PriceCalculate($exchange_money, '*', $taker_fee_rate, 8);
|
|
//增加委托成交匹配记录
|
|
InsideTradeOrder::query()->create([
|
|
'buy_order_no' => $tradeBuy['order_no'],
|
|
'sell_order_no' => $entrust['order_no'],
|
|
'buy_id' => $tradeBuy['id'],
|
|
'sell_id' => $entrust['id'],
|
|
'buy_user_id' => $tradeBuy['user_id'],
|
|
'sell_user_id' => $entrust['user_id'],
|
|
'unit_price' => $unit_price,
|
|
'symbol' => $entrust['symbol'],
|
|
'quote_coin_id' => $entrust['quote_coin_id'],
|
|
'base_coin_id' => $entrust['base_coin_id'],
|
|
'trade_amount' => $exchange_amount,
|
|
'trade_money' => $exchange_money,
|
|
'trade_buy_fee' => $buy_fee,
|
|
'trade_sell_fee' => $sell_fee,
|
|
]);
|
|
|
|
//更新用户钱包
|
|
$buy_user = User::query()->find($tradeBuy['user_id']);
|
|
$sell_user = User::query()->find($entrust['user_id']);
|
|
//买家得到base_coin_id 扣除quote_coin_id
|
|
$buy_user->update_wallet_and_log($entrust['quote_coin_id'], 'freeze_balance', -$exchange_money, UserWallet::asset_account, 'entrust_exchange');
|
|
$buy_user->update_wallet_and_log($entrust['base_coin_id'], 'usable_balance', $exchange_amount - $buy_fee, UserWallet::asset_account, 'entrust_exchange');
|
|
//卖家得到quote_coin_id 扣除base_coin_id
|
|
$sell_user->update_wallet_and_log($entrust['quote_coin_id'], 'usable_balance', $exchange_money - $sell_fee, UserWallet::asset_account, 'entrust_exchange');
|
|
$sell_user->update_wallet_and_log($entrust['base_coin_id'], 'freeze_balance', -$exchange_amount, UserWallet::asset_account, 'entrust_exchange');
|
|
|
|
//卖单委托交易完成 退出循环
|
|
if ($entrust_amount == 0) {
|
|
$entrust->update([
|
|
'traded_amount' => $entrust_traded_amount,
|
|
'traded_money' => $entrust_traded_money,
|
|
'status' => InsideTradeSell::status_completed,
|
|
]);
|
|
break;
|
|
} else {
|
|
$entrust->update([
|
|
'traded_amount' => $entrust_traded_amount,
|
|
'traded_money' => $entrust_traded_money,
|
|
'status' => InsideTradeSell::status_trading,
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|