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.
144 lines
5.9 KiB
144 lines
5.9 KiB
<?php
|
|
|
|
namespace App\Jobs;
|
|
|
|
use App\Exceptions\ApiException;
|
|
use App\Models\ContractEntrust;
|
|
use App\Models\ContractPair;
|
|
use App\Models\ContractPosition;
|
|
use App\Models\ContractStrategy;
|
|
use App\Services\ContractService;
|
|
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\DB;
|
|
|
|
class TriggerStrategy implements ShouldQueue
|
|
{
|
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
|
|
/**
|
|
* 任务可以尝试的最大次数。
|
|
*
|
|
* @var int
|
|
*/
|
|
public $tries = 3;
|
|
|
|
private $data;
|
|
|
|
/**
|
|
* Create a new job instance.
|
|
* @param array $data [$symbol,$realtime_price]
|
|
*/
|
|
public function __construct(array $data)
|
|
{
|
|
$this->data = $data;
|
|
}
|
|
|
|
/**
|
|
* Execute the job.
|
|
*
|
|
* @return void
|
|
* @throws ApiException
|
|
*/
|
|
public function handle()
|
|
{
|
|
$symbol = $this->data['symbol'];
|
|
$realtime_price = $this->data['realtime_price'];
|
|
|
|
$strategys = ContractStrategy::query()
|
|
->where('symbol', $symbol)
|
|
->where('status', 1)
|
|
->where(function ($q) use ($realtime_price) {
|
|
$q->where([['position_side', '=', 1], ['tp_trigger_price', '<>', ''], ['tp_trigger_price', '<=', $realtime_price]])
|
|
->orWhere([['position_side', '=', 1], ['sl_trigger_price', '<>', ''], ['sl_trigger_price', '>=', $realtime_price]])
|
|
->orWhere([['position_side', '=', 2], ['tp_trigger_price', '<>', ''], ['tp_trigger_price', '>=', $realtime_price]])
|
|
->orWhere([['position_side', '=', 2], ['sl_trigger_price', '<>', ''], ['sl_trigger_price', '<=', $realtime_price]]);
|
|
})->cursor();
|
|
|
|
foreach ($strategys as $strategy) {
|
|
|
|
$position = ContractPosition::getPosition(['user_id' => $strategy['user_id'], 'contract_id' => $strategy['contract_id'], 'side' => $strategy['position_side']]);
|
|
if (blank($position)) continue;
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
|
|
$strategy->update(['status' => 0]);
|
|
|
|
$avail_position = $position->avail_position; // 可平数量
|
|
if ($avail_position > 0) {
|
|
$pair = ContractPair::query()->where('symbol', $position['symbol'])->first();
|
|
if (blank($pair)) continue;
|
|
// 记录仓位保证金(平仓时直接抵消掉)
|
|
$margin = ($position['position_margin'] / $position['hold_position']) * $position['avail_position'];
|
|
$unit_fee = PriceCalculate($pair['unit_amount'], '*', $pair['maker_fee_rate'], 5); // 单张合约手续费
|
|
$fee = PriceCalculate($position['avail_position'], '*', $unit_fee, 5);
|
|
|
|
$entrust_price = null;
|
|
if ($position['side'] == 1) {
|
|
if ($strategy['tp_trigger_price'] != '' && $strategy['tp_trigger_price'] <= $realtime_price) {
|
|
$entrust_price = $strategy['tp_trigger_price'];
|
|
} elseif ($strategy['sl_trigger_price'] != '' && $strategy['sl_trigger_price'] >= $realtime_price) {
|
|
$entrust_price = $strategy['sl_trigger_price'];
|
|
}
|
|
} else {
|
|
if ($strategy['tp_trigger_price'] != '' && $strategy['tp_trigger_price'] >= $realtime_price) {
|
|
$entrust_price = $strategy['tp_trigger_price'];
|
|
} elseif ($strategy['sl_trigger_price'] != '' && $strategy['sl_trigger_price'] <= $realtime_price) {
|
|
$entrust_price = $strategy['sl_trigger_price'];
|
|
}
|
|
}
|
|
if (empty($entrust_price)) continue;
|
|
|
|
//创建订单
|
|
$order_data = [
|
|
'user_id' => $position['user_id'],
|
|
'order_no' => get_order_sn('PCB'),
|
|
'contract_id' => $pair['id'],
|
|
'contract_coin_id' => $pair['contract_coin_id'],
|
|
'margin_coin_id' => $pair['margin_coin_id'],
|
|
'symbol' => $pair['symbol'],
|
|
'unit_amount' => $position['unit_amount'],
|
|
'order_type' => 2,
|
|
'side' => $position['side'] == 1 ? 2 : 1,
|
|
'type' => 1,
|
|
'entrust_price' => $entrust_price,
|
|
'amount' => $avail_position,
|
|
'lever_rate' => $position['lever_rate'],
|
|
'margin' => $margin,
|
|
'fee' => $fee,
|
|
'hang_status' => 1,
|
|
'trigger_price' => null,
|
|
'ts' => time(),
|
|
];
|
|
$entrust = ContractEntrust::query()->create($order_data);
|
|
|
|
// 冻结持仓数量
|
|
$position->update([
|
|
'avail_position' => $position->avail_position - $avail_position,
|
|
'freeze_position' => $position->freeze_position + $avail_position,
|
|
]);
|
|
|
|
// 执行成交平仓
|
|
$service = new ContractService();
|
|
if ($entrust['order_type'] == 2 && $entrust['side'] == 1) {
|
|
// 买入平空
|
|
$service->handleFlatBuyOrder($entrust);
|
|
} elseif ($entrust['order_type'] == 2 && $entrust['side'] == 2) {
|
|
// 卖出平多
|
|
$service->handleFlatSellOrder($entrust);
|
|
}
|
|
}
|
|
|
|
DB::commit();
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
info($e);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|