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.
1636 lines
82 KiB
1636 lines
82 KiB
<?php
|
|
|
|
|
|
namespace App\Services;
|
|
|
|
|
|
use App\Exceptions\ApiException;
|
|
use App\Handlers\ContractTool;
|
|
use App\Jobs\HandleContractEntrust;
|
|
use App\Jobs\HandleFlatPosition;
|
|
use App\Models\Coins;
|
|
use App\Models\ContractEntrust;
|
|
use App\Models\ContractOrder;
|
|
use App\Models\ContractPair;
|
|
use App\Models\ContractPosition;
|
|
use App\Models\ContractShare;
|
|
use App\Models\ContractStrategy;
|
|
use App\Models\SustainableAccount;
|
|
use App\Models\User;
|
|
use App\Models\UserWallet;
|
|
use App\Models\UserWalletLog;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class ContractService
|
|
{
|
|
public function positionShare($user, $params)
|
|
{
|
|
$position = ContractPosition::query()
|
|
->where('user_id', $user['user_id'])
|
|
->where('symbol', $params['symbol'])
|
|
->where('side', $params['position_side'])
|
|
->where('hold_position', '>', 0)
|
|
->first();
|
|
if (blank($position)) {
|
|
$realtime_price = Cache::store('redis')->get('swap:' . 'trade_detail_' . $position['symbol'])['price'] ?? null;
|
|
$data['price1'] = '--';
|
|
$data['price2'] = $realtime_price;
|
|
$data['symbol'] = '--';
|
|
$data['lever_rate'] = '--';
|
|
$data['profit'] = 0;
|
|
$data['profitRate'] = '0%';
|
|
} else {
|
|
$contract = ContractPair::query()->find($position['contract_id']);
|
|
// 获取最新一条成交记录 即实时最新价格
|
|
$realtime_price = Cache::store('redis')->get('swap:' . 'trade_detail_' . $position['symbol'])['price'] ?? null;
|
|
$unRealProfit = ContractTool::unRealProfit($position, $contract, $realtime_price);
|
|
$data['price1'] = empty($position['avg_price']) ? '--' : (float)$position['avg_price'];
|
|
$data['price2'] = $realtime_price;
|
|
$data['symbol'] = $position['symbol'] ?? '--';
|
|
$data['lever_rate'] = $position['lever_rate'] ?? 100;
|
|
$data['profit'] = $unRealProfit;
|
|
$data['profitRate'] = PriceCalculate($unRealProfit, '/', $position['position_margin'], 4) * 100 . '%';
|
|
}
|
|
|
|
$items = ContractShare::with('translations')
|
|
->where('status', 1)->get()->map(function ($v, $k) {
|
|
$m['title'] = $v['translations']->where('locale', app()->getLocale())->first()->title ?? ($v['translations']->where('locale', 'en')->first()->title ?? '');
|
|
$m['type'] = $v['type'];
|
|
$m['bg_img'] = getFullPath($v['bg_img']);
|
|
$m['text_img'] = getFullPath($v['text_img']);
|
|
$m['peri_img'] = getFullPath($v['peri_img']);
|
|
return $m;
|
|
});
|
|
$data['share_imgs'] = $items;
|
|
return $data;
|
|
}
|
|
|
|
public function entrustShare($user, $params)
|
|
{
|
|
$entrust = ContractEntrust::query()->where('order_type', 2)->where('user_id', $user['user_id'])->where('id', $params['entrust_id'])->first();
|
|
if (blank($entrust)) throw new ApiException('参数错误');
|
|
|
|
$position_side = $entrust['side'] == 1 ? 2 : 1;
|
|
$open_position_price = ContractPosition::query()->where(['user_id' => $entrust['user_id'], 'contract_id' => $entrust['contract_id'], 'side' => $position_side])->value('avg_price');
|
|
$data['price1'] = empty($open_position_price) ? '--' : (float)$open_position_price;
|
|
$data['price2'] = $entrust['avg_price'] ?? '--';
|
|
$data['symbol'] = $entrust['symbol'] ?? '--';
|
|
$data['lever_rate'] = $entrust['lever_rate'] ?? 100;
|
|
$data['profit'] = $entrust['profit'];
|
|
$data['profitRate'] = PriceCalculate($entrust['profit'], '/', $entrust['margin'], 4) * 100 . '%';
|
|
|
|
$items = ContractShare::query()->where('status', 1)->get()->map(function ($v, $k) {
|
|
$m['bg_img'] = getFullPath($v['bg_img']);
|
|
$m['text_img'] = getFullPath($v['text_img']);
|
|
$m['peri_img'] = getFullPath($v['peri_img']);
|
|
return $m;
|
|
});
|
|
$data['share_imgs'] = $items;
|
|
return $data;
|
|
}
|
|
|
|
public function getSymbolDetail($params)
|
|
{
|
|
$pair = ContractPair::query()->where('symbol', $params['symbol'])->first();
|
|
if (blank($pair)) throw new ApiException('合约不存在');
|
|
return $pair;
|
|
}
|
|
|
|
// public function contractAccountList($user)
|
|
// {
|
|
// $data = [];
|
|
// $totalAssetsUsd = 0;
|
|
// $totalUnRealProfit = 0;
|
|
// $data['accountList'] = [];
|
|
// $contracts = ContractPair::query()->where('status',1)->get();
|
|
// $wallet = SustainableAccount::query()->where('user_id' , $user['user_id'])->first();
|
|
// foreach ($contracts as $k => $contract){
|
|
// // 获取最新一条成交记录 即实时最新价格
|
|
// $trade_detail = Cache::store('redis')->get('swap:' . 'trade_detail_' . $contract['symbol']);
|
|
// $realtime_price = $trade_detail['price'];
|
|
// $buy_position = ContractPosition::getPosition(['user_id' => $user['user_id'], 'contract_id' => $contract['id'], 'side' => 1]);
|
|
// $sell_position = ContractPosition::getPosition(['user_id' => $user['user_id'], 'contract_id' => $contract['id'], 'side' => 2]);
|
|
// $buy_position_profit = ContractTool::unRealProfit($buy_position,$contract,$realtime_price); // 多仓盈亏
|
|
// $sell_position_profit = ContractTool::unRealProfit($sell_position,$contract,$realtime_price); // 空仓盈亏
|
|
//
|
|
// $account = [];
|
|
// $account['contract_id'] = $contract['id'];
|
|
// $account['symbol'] = $contract['symbol'];
|
|
// $account['symbolName'] = $contract['symbol'] . '/' . $contract['type'];
|
|
// $account['icon'] = Coins::icon($contract['symbol']);
|
|
// $account['usable_balance'] = $wallet['usable_balance'];
|
|
// $account['used_balance'] = $wallet['used_balance'];
|
|
// $account['freeze_balance'] = $wallet['freeze_balance'];
|
|
// $account['unRealProfit'] = $buy_position_profit + $sell_position_profit; // 未实现盈亏
|
|
// $account['account_equity'] = custom_number_format($account['usable_balance'] + $account['used_balance'] + $account['freeze_balance'] + $account['unRealProfit'],4); // 永续账户权益 = 账户可用余额 + 持仓保证金 + 委托冻结保证金 + 未实现盈亏
|
|
// // 风险率 用以衡量当前合约账户风险程度的指标。风险率越低,账户风险越高,当风险率=10.0%时,将会被强制平仓。风险率=账户权益/(持仓保证金+委托冻结)*100%
|
|
// $riskRate = ContractTool::riskRate($account);
|
|
// $account['riskRate'] = $riskRate * 100 . '%';
|
|
// // 预估强平价 合约账户风险率=10.0%时的预估价格。此价格仅供参考,实际强平价以发生强平事件时成交的价格为准
|
|
// $account['flatPrice'] = ContractTool::flatPrice($account,$buy_position,$sell_position,$contract);
|
|
// $account['lever_rate'] = $buy_position['lever_rate'];
|
|
// $account['buy_hold_position'] = $buy_position['hold_position'];
|
|
// $account['sell_hold_position'] = $sell_position['hold_position'];
|
|
//
|
|
// $data['accountList'][$k] = $account;
|
|
//
|
|
// $totalUnRealProfit += $account['unRealProfit'];
|
|
// }
|
|
// $totalAssetsUsd = ($wallet['usable_balance'] + $wallet['used_balance'] + $wallet['freeze_balance']);
|
|
// $data['totalAssetsUsd'] = $totalAssetsUsd;
|
|
// $data['totalUnRealProfit'] = $totalUnRealProfit;
|
|
// $data['symbol'] = 'USDT';
|
|
// return $data;
|
|
// }
|
|
|
|
public function contractAccountFlow($user, $params)
|
|
{
|
|
$builder = UserWalletLog::query()
|
|
->where('user_id', $user['user_id'])
|
|
->where('rich_type', 'usable_balance')
|
|
->where('account_type', UserWallet::sustainable_account);
|
|
|
|
if (!empty($params['symbol'])) {
|
|
$pair = ContractPair::query()->where('symbol', $params['symbol'])->first();
|
|
if (!blank($pair)) {
|
|
$builder->where('sub_account', $pair['id']);
|
|
}
|
|
}
|
|
|
|
return $builder->orderByDesc('id')->paginate();
|
|
}
|
|
|
|
// public function contractAccount($user,$params)
|
|
// {
|
|
// $pair = ContractPair::query()->where('symbol',$params['symbol'])->first();
|
|
// if(blank($pair)) throw new ApiException('合约不存在');
|
|
// // 合约保证金账户
|
|
// $wallet = SustainableAccount::query()->where(['user_id' => $user->user_id,'coin_id' => $pair['margin_coin_id']])->first();
|
|
// if(blank($wallet)) throw new ApiException('账户类型错误');
|
|
//
|
|
// // 获取最新一条成交记录 即实时最新价格
|
|
// $trade_detail = Cache::store('redis')->get('swap:' . 'trade_detail_' . $pair['symbol']);
|
|
// $realtime_price = $trade_detail['price'];
|
|
// $buy_position = ContractPosition::getPosition(['user_id' => $user['user_id'], 'contract_id' => $pair['id'], 'side' => 1]);
|
|
// $sell_position = ContractPosition::getPosition(['user_id' => $user['user_id'], 'contract_id' => $pair['id'], 'side' => 2]);
|
|
// $buy_position_profit = ContractTool::unRealProfit($buy_position,$pair,$realtime_price); // 多仓盈亏
|
|
// $sell_position_profit = ContractTool::unRealProfit($sell_position,$pair,$realtime_price); // 空仓盈亏
|
|
//
|
|
// $account = [];
|
|
// $account['contract_id'] = $pair['id'];
|
|
// $account['usable_balance'] = $wallet['usable_balance'];
|
|
// $account['used_balance'] = $wallet['used_balance'];
|
|
// $account['freeze_balance'] = $wallet['freeze_balance'];
|
|
// $account['unRealProfit'] = $buy_position_profit + $sell_position_profit; // 未实现盈亏
|
|
// $account['account_equity'] = custom_number_format($account['usable_balance'] + $account['used_balance'] + $account['freeze_balance'] + $account['unRealProfit'],4); // 永续账户权益 = 账户可用余额 + 持仓保证金 + 委托冻结保证金 + 未实现盈亏
|
|
// // 风险率 用以衡量当前合约账户风险程度的指标。风险率越低,账户风险越高,当风险率=10.0%时,将会被强制平仓。风险率=账户权益/(持仓保证金+委托冻结)*100%
|
|
// $riskRate = ContractTool::riskRate($account);
|
|
// $account['riskRate'] = $riskRate * 100 . '%';
|
|
// // 预估强平价 合约账户风险率=10.0%时的预估价格。此价格仅供参考,实际强平价以发生强平事件时成交的价格为准
|
|
// $account['flatPrice'] = ContractTool::flatPrice($account,$buy_position,$sell_position,$pair);
|
|
// $account['lever_rate'] = $buy_position['lever_rate'];
|
|
//
|
|
// return $account;
|
|
// }
|
|
|
|
public function contractAccount($user, $params)
|
|
{
|
|
// 合约保证金账户
|
|
$wallet = SustainableAccount::getContractAccount($user['user_id']);
|
|
if (blank($wallet)) throw new ApiException('账户类型错误');
|
|
|
|
$account = [];
|
|
$totalUnrealProfit = 0;
|
|
$positions = ContractPosition::query()->where('user_id', $user['user_id'])->where('hold_position', '>', 0)->get();
|
|
foreach ($positions as $position) {
|
|
$contract = ContractPair::query()->find($position['contract_id']);
|
|
// 获取最新一条成交记录 即实时最新价格
|
|
$realtime_price = Cache::store('redis')->get('swap:' . 'trade_detail_' . $position['symbol'])['price'] ?? null;
|
|
$unRealProfit = ContractTool::unRealProfit($position, $contract, $realtime_price);
|
|
$totalUnrealProfit += $unRealProfit;
|
|
}
|
|
|
|
$account['usable_balance'] = $wallet['usable_balance'];
|
|
$account['used_balance'] = $wallet['used_balance'];
|
|
$account['freeze_balance'] = $wallet['freeze_balance'];
|
|
$account['totalUnrealProfit'] = custom_number_format($totalUnrealProfit, 5);
|
|
$account['account_equity'] = custom_number_format($account['usable_balance'] + $account['used_balance'] + $account['freeze_balance'] + $account['totalUnrealProfit'], 4); // 永续账户权益 = 账户可用余额 + 持仓保证金 + 委托冻结保证金 + 未实现盈亏
|
|
// 风险率 用以衡量当前合约账户风险程度的指标。风险率越低,账户风险越高,当风险率=10.0%时,将会被强制平仓。风险率=账户权益/(持仓保证金+委托冻结)*100%
|
|
$riskRate = ContractTool::riskRate($account);
|
|
$account['riskRate'] = $riskRate * 100 . '%';
|
|
|
|
if (!empty($params['symbol'])) {
|
|
$pair = ContractPair::query()->where('symbol', $params['symbol'])->first();
|
|
$default_lever = $pair['default_lever'] ?? 100;
|
|
$symbolPosition = ContractPosition::query()->where('user_id', $user['user_id'])->where('symbol', $params['symbol'])->first();
|
|
$account['lever_rate'] = blank($symbolPosition) ? $default_lever : $symbolPosition['lever_rate'];
|
|
} else {
|
|
$account['lever_rate'] = 100;
|
|
}
|
|
|
|
return $account;
|
|
}
|
|
|
|
// 获取用户持仓信息
|
|
public function holdPosition($user, $params)
|
|
{
|
|
$builder = ContractPosition::query()->where('user_id', $user['user_id'])->where('hold_position', '>', 0);
|
|
if (!empty($params['symbol'])) {
|
|
$builder->where('symbol', $params['symbol']);
|
|
}
|
|
$positions = $builder->get();
|
|
|
|
// 合约保证金账户
|
|
$account = SustainableAccount::getContractAccount($user['user_id']);
|
|
foreach ($positions as $position) {
|
|
$contract = ContractPair::query()->find($position['contract_id']);
|
|
// 获取最新一条成交记录 即实时最新价格
|
|
$realtime_price = Cache::store('redis')->get('swap:' . 'trade_detail_' . $position['symbol'])['price'] ?? null;
|
|
$position['pair_name'] = $contract['symbol'] . '/' . $contract['type'];
|
|
$position['unRealProfit'] = ContractTool::unRealProfit($position, $contract, $realtime_price);
|
|
$position['profitRate'] = PriceCalculate($position['unRealProfit'], '/', $position['position_margin'], 4) * 100 . '%';
|
|
$position['flatPrice'] = ContractTool::getFlatPrice($account, $contract);
|
|
$position['realtimePrice'] = $realtime_price;
|
|
$strategy = ContractStrategy::query()
|
|
->where('user_id', $user['user_id'])
|
|
->where('status', 1)
|
|
->where('contract_id', $position['contract_id'])
|
|
->where('position_side', $position['side'])
|
|
->first();
|
|
$position['tpPrice'] = $strategy['tp_trigger_price'] ?? '';
|
|
$position['slPrice'] = $strategy['sl_trigger_price'] ?? '';
|
|
}
|
|
|
|
return $positions;
|
|
}
|
|
|
|
public function holdPosition2($user, $params)
|
|
{
|
|
$builder = ContractPosition::query()->where('user_id', $user['user_id'])->where('hold_position', '>', 0);
|
|
if (!empty($params['symbol'])) {
|
|
$builder->where('symbol', $params['symbol']);
|
|
}
|
|
$positions = $builder->get();
|
|
|
|
// 合约保证金账户
|
|
$account = SustainableAccount::getContractAccount($user['user_id']);
|
|
foreach ($positions as $position) {
|
|
$contract = ContractPair::query()->find($position['contract_id']);
|
|
// 获取最新一条成交记录 即实时最新价格
|
|
$realtime_price = Cache::store('redis')->get('swap:' . 'trade_detail_' . $position['symbol'])['price'] ?? null;
|
|
$position['pair_name'] = $contract['symbol'] . '/' . $contract['type'];
|
|
$position['unRealProfit'] = ContractTool::unRealProfit2($position, $contract, $realtime_price);
|
|
$position['profitRate'] = PriceCalculate($position['unRealProfit'], '/', $position['position_margin'], 4) * 100 . '%';
|
|
$position['flatPrice'] = ContractTool::getFlatPrice($account, $contract);
|
|
$position['realtimePrice'] = $realtime_price;
|
|
$strategy = ContractStrategy::query()
|
|
->where('user_id', $user['user_id'])
|
|
->where('status', 1)
|
|
->where('contract_id', $position['contract_id'])
|
|
->where('position_side', $position['side'])
|
|
->first();
|
|
$position['tpPrice'] = $strategy['tp_trigger_price'] ?? '';
|
|
$position['slPrice'] = $strategy['sl_trigger_price'] ?? '';
|
|
}
|
|
|
|
return $positions;
|
|
}
|
|
|
|
// public function holdPosition($user,$params)
|
|
// {
|
|
// $pair = ContractPair::query()->where('symbol',$params['symbol'])->first();
|
|
// if(blank($pair)) throw new ApiException('合约不存在');
|
|
// // 获取最新一条成交记录 即实时最新价格
|
|
// $trade_detail = Cache::store('redis')->get('swap:' . 'trade_detail_' . $pair['symbol']);
|
|
// $realtime_price = $trade_detail['price'];
|
|
// $buy_position = ContractPosition::getPosition(['user_id'=>$user['user_id'],'contract_id'=>$pair['id'],'side'=>1]);
|
|
// $sell_position = ContractPosition::getPosition(['user_id'=>$user['user_id'],'contract_id'=>$pair['id'],'side'=>2]);
|
|
// $buy_position['symbol'] = $sell_position['symbol'] = $pair['symbol'];
|
|
// $buy_position['type'] = $sell_position['type'] = $pair['type'];
|
|
// $buy_position['pair_name'] = $sell_position['pair_name'] = $pair['contract_coin_name'] . '/' . $pair['type'];
|
|
// $buy_position['unRealProfit'] = ContractTool::unRealProfit($buy_position,$pair,$realtime_price);
|
|
// $sell_position['unRealProfit'] = ContractTool::unRealProfit($sell_position,$pair,$realtime_price);
|
|
// $buy_position['profitRate'] = PriceCalculate($buy_position['unRealProfit'] ,'/', $buy_position['position_margin'],4) * 100 . '%';
|
|
// $sell_position['profitRate'] = PriceCalculate($sell_position['unRealProfit'] ,'/', $sell_position['position_margin'],4) * 100 . '%';
|
|
//
|
|
// // 合约保证金账户
|
|
// $account = SustainableAccount::getContractAccount($user['user_id']);
|
|
// $flatPrice = ContractTool::flatPrice($account,$buy_position,$sell_position,$pair);
|
|
// $buy_position['flatPrice'] = $sell_position['flatPrice'] = $flatPrice;
|
|
//
|
|
// $data[0] = $buy_position;
|
|
// $data[1] = $sell_position;
|
|
// return $data;
|
|
// }
|
|
|
|
public function openNum($user, $params)
|
|
{
|
|
$pair = ContractPair::query()->where('symbol', $params['symbol'])->first();
|
|
if (blank($pair)) throw new ApiException('合约不存在');
|
|
|
|
// 合约保证金账户
|
|
$wallet = SustainableAccount::query()->where(['user_id' => $user->user_id, 'coin_id' => $pair['margin_coin_id']])->first();
|
|
if (blank($wallet)) throw new ApiException('账户类型错误');
|
|
$balance = $wallet->usable_balance;
|
|
if ($balance == 0) return 0;
|
|
|
|
// 单张合约成交所需保证金 = 单张合约面值(USDT)+ 单张合约成交所需手续费
|
|
$unit_amount = $pair['unit_amount'];
|
|
$unit_fee = PriceCalculate($pair['unit_amount'], '*', $pair['maker_fee_rate'], 5); // 单张合约手续费
|
|
|
|
$unit_price = $unit_amount / $params['lever_rate'] + $unit_fee;
|
|
|
|
// 可开张数 = ((余额*杠杆倍数)/单张合约成交所需保证金)
|
|
$open_num = floor($balance / $unit_price);
|
|
return $open_num;
|
|
}
|
|
|
|
public function openPosition($user, $params)
|
|
{
|
|
//todo 开仓处理
|
|
$pair = ContractPair::query()->where('symbol', $params['symbol'])->first();
|
|
if (blank($pair)) throw new ApiException('合约不存在');
|
|
if (($can_store = $pair->can_store()) !== true) throw new ApiException($can_store);
|
|
|
|
// 查看当前是否已有仓位 已有仓位情况下 不可更换杠杆倍数
|
|
// 持仓信息
|
|
$position = ContractPosition::getPosition(['user_id' => $user['user_id'], 'contract_id' => $pair['id'], 'side' => $params['side']]);
|
|
if ($position['hold_position'] > 0 && $position['lever_rate'] != $params['lever_rate']) throw new ApiException('持有仓位时不可更改杠杆倍数');
|
|
|
|
// 查看当前是否已有同类型未成交的开仓委托 存在时不可更换杠杆倍数
|
|
$exist_entrust = ContractEntrust::query()
|
|
->where(['user_id' => $user['user_id'], 'contract_id' => $pair['id'], 'side' => $params['side'], 'order_type' => 1])
|
|
->whereIn('status', [ContractEntrust::status_wait, ContractEntrust::status_trading])
|
|
->first();
|
|
if (!blank($exist_entrust) && $exist_entrust['lever_rate'] != $params['lever_rate']) throw new ApiException('持有仓位时不可更改杠杆倍数');
|
|
|
|
// 合约保证金账户
|
|
$wallet = SustainableAccount::getContractAccount($user['user_id']);
|
|
if (blank($wallet)) throw new ApiException('账户类型错误');
|
|
$balance = $wallet->usable_balance;
|
|
|
|
// 单张合约成交所需保证金 = 单张合约面值(USDT)+ 单张合约成交所需手续费
|
|
$unit_amount = $pair['unit_amount'];
|
|
$unit_fee = PriceCalculate($pair['unit_amount'], '*', $pair['maker_fee_rate'], 5); // 单张合约手续费
|
|
// 计算出所需保证金
|
|
$freeze_balance = PriceCalculate(($params['amount'] * $unit_amount), '/', $params['lever_rate'], 5);
|
|
$freeze_fee = PriceCalculate($params['amount'], '*', $unit_fee, 5);
|
|
|
|
if ($balance < ($freeze_balance + $freeze_fee)) {
|
|
throw new ApiException('账户保证金不足');
|
|
}
|
|
|
|
if ($params['type'] == 1) {
|
|
$entrust_price = $params['entrust_price'];
|
|
if ($entrust_price <= 0) throw new ApiException('请输入价格');
|
|
$trigger_price = null;
|
|
$amount = $params['amount'];
|
|
$hang_status = 1;
|
|
} elseif ($params['type'] == 2) {
|
|
$entrust_price = null;
|
|
$trigger_price = null;
|
|
$amount = $params['amount'];
|
|
$hang_status = 1;
|
|
} else {
|
|
$entrust_price = $params['entrust_price'];
|
|
if ($entrust_price <= 0) throw new ApiException('请输入价格');
|
|
$trigger_price = $params['trigger_price'];
|
|
$amount = $params['amount'];
|
|
$hang_status = 0;
|
|
}
|
|
|
|
$log_type = 'open_position'; // 合约开仓冻结
|
|
$log_type2 = 'open_position_fee'; // 合约开仓手续费
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
//创建订单
|
|
$order_data = [
|
|
'user_id' => $user['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' => $pair['unit_amount'],
|
|
'order_type' => 1,
|
|
'side' => $params['side'],
|
|
'type' => $params['type'],
|
|
'entrust_price' => $entrust_price,
|
|
'amount' => $amount,
|
|
'lever_rate' => $params['lever_rate'],
|
|
'margin' => $freeze_balance,
|
|
'fee' => $freeze_fee,
|
|
'hang_status' => $hang_status,
|
|
'trigger_price' => $trigger_price,
|
|
'ts' => time(),
|
|
];
|
|
$entrust = ContractEntrust::query()->create($order_data);
|
|
|
|
//扣除用户可用资产 冻结保证金
|
|
$user->update_wallet_and_log($wallet['coin_id'], 'usable_balance', -$freeze_balance, UserWallet::sustainable_account, $log_type, '', $entrust['contract_id']);
|
|
$user->update_wallet_and_log($wallet['coin_id'], 'freeze_balance', $freeze_balance, UserWallet::sustainable_account, $log_type, '', $entrust['contract_id']);
|
|
$user->update_wallet_and_log($wallet['coin_id'], 'usable_balance', -$freeze_fee, UserWallet::sustainable_account, $log_type2, '', $entrust['contract_id']);
|
|
$user->update_wallet_and_log($wallet['coin_id'], 'freeze_balance', $freeze_fee, UserWallet::sustainable_account, $log_type2, '', $entrust['contract_id']);
|
|
|
|
// 增加止盈止损
|
|
if (isset($params['tp_trigger_price'], $params['sl_trigger_price']) && !empty($params['tp_trigger_price']) && !empty($params['sl_trigger_price'])) {
|
|
$this->setStrategy($user, [
|
|
'symbol' => $params['symbol'],
|
|
'position_side' => $params['side'],
|
|
'tp_trigger_price' => $params['tp_trigger_price'],
|
|
'sl_trigger_price' => $params['sl_trigger_price'],
|
|
'type' => $params['type'],
|
|
// 'tp_ratio' => $params['tp_ratio'],
|
|
// 'sl_ratio' => $params['sl_ratio'],
|
|
'lever_rate' => $params['lever_rate'],
|
|
]);
|
|
}
|
|
DB::commit();
|
|
|
|
//添加待处理委托Job
|
|
if ($entrust['hang_status'] == 1) HandleContractEntrust::dispatch($entrust)->onQueue('handleContractEntrust');
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
throw new ApiException($e->getMessage());
|
|
}
|
|
|
|
return $entrust;
|
|
}
|
|
|
|
public function closePosition($user, $params)
|
|
{
|
|
//todo 平仓处理
|
|
$pair = ContractPair::query()->where('symbol', $params['symbol'])->first();
|
|
if (blank($pair)) throw new ApiException('合约不存在');
|
|
if (($can_store = $pair->can_store()) !== true) throw new ApiException($can_store);
|
|
|
|
// 持仓信息
|
|
if ($params['side'] == 1) {
|
|
$position = ContractPosition::getPosition(['user_id' => $user['user_id'], 'contract_id' => $pair['id'], 'side' => 2]);
|
|
} else {
|
|
$position = ContractPosition::getPosition(['user_id' => $user['user_id'], 'contract_id' => $pair['id'], 'side' => 1]);
|
|
}
|
|
if (blank($position)) throw new ApiException();
|
|
$avail_position = $position->avail_position; // 可平数量
|
|
|
|
// 记录仓位保证金(平仓时直接抵消掉)
|
|
$margin = ($position['position_margin'] / $position['hold_position']) * $params['amount'];
|
|
$unit_fee = PriceCalculate($position['unit_amount'], '*', $pair['maker_fee_rate'], 5); // 单张合约手续费
|
|
$fee = PriceCalculate($params['amount'], '*', $unit_fee, 5);
|
|
|
|
if ($params['amount'] <= 0) {
|
|
throw new ApiException();
|
|
}
|
|
if ($params['amount'] > $avail_position) {
|
|
throw new ApiException('平仓数量大于可平数量');
|
|
}
|
|
// Log::info(111111);
|
|
if ($params['type'] == 1) {
|
|
$entrust_price = $params['entrust_price'];
|
|
if ($entrust_price <= 0) throw new ApiException('请输入价格');
|
|
$trigger_price = null;
|
|
$amount = $params['amount'];
|
|
$hang_status = 1;
|
|
} elseif ($params['type'] == 2) {
|
|
$entrust_price = null;
|
|
$trigger_price = null;
|
|
$amount = $params['amount'];
|
|
$hang_status = 1;
|
|
} else {
|
|
$entrust_price = $params['entrust_price'];
|
|
if ($entrust_price <= 0) throw new ApiException('请输入价格');
|
|
$trigger_price = $params['trigger_price'];
|
|
$amount = $params['amount'];
|
|
$hang_status = 0;
|
|
}
|
|
// Log::info(2222);
|
|
DB::beginTransaction();
|
|
try {
|
|
//创建订单
|
|
$order_data = [
|
|
'user_id' => $user['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' => $params['side'],
|
|
'type' => $params['type'],
|
|
'entrust_price' => $entrust_price,
|
|
'amount' => $amount,
|
|
'lever_rate' => $position['lever_rate'],
|
|
'margin' => $margin,
|
|
'fee' => $fee,
|
|
'hang_status' => $hang_status,
|
|
'trigger_price' => $trigger_price,
|
|
'ts' => time(),
|
|
];
|
|
// Log::info(555555);
|
|
$entrust = ContractEntrust::query()->create($order_data);
|
|
// Log::info(3333);
|
|
// 冻结持仓数量
|
|
$position->update([
|
|
'avail_position' => $position->avail_position - $amount,
|
|
'freeze_position' => $position->freeze_position + $amount,
|
|
]);
|
|
// Log::info(444444);
|
|
DB::commit();
|
|
|
|
//添加待处理委托Job
|
|
if ($entrust['hang_status'] == 1) HandleContractEntrust::dispatch($entrust)->onQueue('handleContractEntrust');
|
|
|
|
// Log::info(6666666666);
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
throw new ApiException($e->getMessage());
|
|
}
|
|
|
|
return $entrust;
|
|
}
|
|
|
|
public function closeAllPosition($user, $params)
|
|
{
|
|
$pair = ContractPair::query()->where('symbol', $params['symbol'])->first();
|
|
if (blank($pair)) throw new ApiException('合约不存在');
|
|
if (($can_store = $pair->can_store()) !== true) throw new ApiException($can_store);
|
|
Log::info("后台平仓");
|
|
// 持仓信息
|
|
$position_side = $params['side'] == 1 ? 2 : 1;
|
|
$position = ContractPosition::getPosition(['user_id' => $user['user_id'], 'contract_id' => $pair['id'], 'side' => $position_side]);
|
|
if (blank($position)) throw new ApiException();
|
|
if ($position['avail_position'] == 0) throw new ApiException('当前仓位张数为0');
|
|
|
|
// 记录仓位保证金(平仓时直接抵消掉)
|
|
$margin = ($position['position_margin'] / $position['hold_position']) * $position['avail_position'];
|
|
$unit_fee = PriceCalculate($position['unit_amount'], '*', $pair['maker_fee_rate'], 5); // 单张合约手续费
|
|
$fee = PriceCalculate($position['avail_position'], '*', $unit_fee, 5);
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
|
|
// $hold_position = $position->hold_position; // 总持仓张数
|
|
$avail_position = $position->avail_position; // 可平数量
|
|
// $freeze_position = $position->freeze_position; // 冻结数量
|
|
|
|
//创建订单
|
|
$order_data = [
|
|
'user_id' => $user['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' => $params['side'],
|
|
'type' => 2, // 市价
|
|
'entrust_price' => null,
|
|
'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,
|
|
]);
|
|
|
|
//添加待处理委托Job
|
|
HandleContractEntrust::dispatch($entrust)->onQueue('handleContractEntrust');
|
|
|
|
DB::commit();
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
throw new ApiException($e->getMessage());
|
|
}
|
|
|
|
return api_response()->success('Success');
|
|
}
|
|
|
|
public function onekeyAllFlat($user_id)
|
|
{
|
|
$user = User::query()->find($user_id);
|
|
if (blank($user)) return api_response()->error(0, 'error');
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
// 撤销未完成的委托
|
|
$entrusts = ContractEntrust::query()
|
|
->where('user_id', $user_id)
|
|
->where('order_type', 2)
|
|
->whereIn('status', [ContractEntrust::status_wait, ContractEntrust::status_trading])
|
|
->get();
|
|
if (!blank($entrusts)) {
|
|
foreach ($entrusts as $entrust) {
|
|
//更新委托
|
|
$entrust->update([
|
|
'status' => 0,
|
|
'cancel_time' => time(),
|
|
]);
|
|
|
|
// 平仓方向
|
|
$position_side = $entrust['side'] == 1 ? 2 : 1;
|
|
// 持仓信息
|
|
$position = ContractPosition::getPosition(['user_id' => $user['user_id'], 'contract_id' => $entrust['contract_id'], 'side' => $position_side]);
|
|
if (blank($position)) throw new ApiException();
|
|
// 回退持仓数量
|
|
$position->update([
|
|
'avail_position' => $position->avail_position + $entrust['amount'],
|
|
'freeze_position' => $position->freeze_position - $entrust['amount'],
|
|
]);
|
|
}
|
|
}
|
|
|
|
$positions = ContractPosition::query()->where('user_id', $user_id)->where('hold_position', '>', 0)->get();
|
|
if (!blank($positions)) {
|
|
// 平仓
|
|
HandleFlatPosition::dispatch($positions)->onQueue('HandleFlatPosition');
|
|
}
|
|
|
|
DB::commit();
|
|
|
|
return api_response()->success('Processed successfully.');
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
info($e);
|
|
return api_response()->error(0, 'error');
|
|
}
|
|
}
|
|
|
|
public function onekeyReverse($user, $params)
|
|
{
|
|
$pair = ContractPair::query()->where('symbol', $params['symbol'])->first();
|
|
if (blank($pair)) throw new ApiException('合约不存在');
|
|
if (($can_store = $pair->can_store()) !== true) throw new ApiException($can_store);
|
|
|
|
// 先平仓
|
|
try {
|
|
DB::beginTransaction();
|
|
Log::info("后台平仓2");
|
|
// 持仓信息
|
|
$position_side = $params['position_side'];
|
|
$position = ContractPosition::getPosition(['user_id' => $user['user_id'], 'contract_id' => $pair['id'], 'side' => $position_side]);
|
|
if (blank($position)) throw new ApiException();
|
|
if ($position['avail_position'] == 0) throw new ApiException('当前仓位张数为0');
|
|
|
|
// 撤销未完成的平仓委托
|
|
$entrust_side = $position['side'] == 1 ? 2 : 1;
|
|
$entrusts = ContractEntrust::query()
|
|
->where('user_id', $user['user_id'])
|
|
->where('order_type', 2)
|
|
->where('contract_id', $pair['id'])
|
|
->where('side', $entrust_side)
|
|
->whereIn('status', [ContractEntrust::status_wait, ContractEntrust::status_trading])
|
|
->get();
|
|
if (!blank($entrusts)) {
|
|
foreach ($entrusts as $entrust) {
|
|
//更新委托
|
|
$entrust->update([
|
|
'status' => 0,
|
|
'cancel_time' => time(),
|
|
]);
|
|
|
|
// 回退持仓数量
|
|
$position->update([
|
|
'avail_position' => $position->avail_position + $entrust['amount'],
|
|
'freeze_position' => $position->freeze_position - $entrust['amount'],
|
|
]);
|
|
}
|
|
// foreach ($entrusts as $entrust){
|
|
// $params2 = ['entrust_id'=>$entrust['id'],'symbol'=>$entrust['symbol']];
|
|
// (new ContractService())->cancelEntrust($user,$params2);
|
|
// }
|
|
}
|
|
|
|
// 记录仓位保证金(平仓时直接抵消掉)
|
|
$margin = ($position['position_margin'] / $position['hold_position']) * $position['avail_position'];
|
|
|
|
$unit_fee = PriceCalculate($position['unit_amount'], '*', $pair['maker_fee_rate'], 5); // 单张合约手续费
|
|
$fee = PriceCalculate($position['avail_position'], '*', $unit_fee, 5);
|
|
|
|
$avail_position = $position->avail_position; // 可平数量
|
|
|
|
//创建平仓委托
|
|
$order_data = [
|
|
'user_id' => $user['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' => 2, // 市价
|
|
'entrust_price' => null,
|
|
'amount' => $avail_position,
|
|
'lever_rate' => $position['lever_rate'],
|
|
'margin' => $margin,
|
|
'fee' => $fee,
|
|
'hang_status' => 1,
|
|
'trigger_price' => null,
|
|
'ts' => time(),
|
|
];
|
|
$flat_entrust = ContractEntrust::query()->create($order_data);
|
|
|
|
// 冻结持仓数量
|
|
$position->update([
|
|
'avail_position' => $position->avail_position - $avail_position,
|
|
'freeze_position' => $position->freeze_position + $avail_position,
|
|
]);
|
|
|
|
if ($flat_entrust['order_type'] == 2 && $flat_entrust['side'] == 1) {
|
|
// 买入平空
|
|
$this->handleFlatBuyOrder($flat_entrust);
|
|
} elseif ($flat_entrust['order_type'] == 2 && $flat_entrust['side'] == 2) {
|
|
// 卖出平多
|
|
$this->handleFlatSellOrder($flat_entrust);
|
|
}
|
|
|
|
DB::commit();
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
// throw $e;
|
|
return api_response()->error(0, 'error.');
|
|
}
|
|
|
|
// 反向开仓
|
|
try {
|
|
DB::beginTransaction();
|
|
// 再开反向仓位
|
|
// 合约保证金账户
|
|
$wallet = SustainableAccount::getContractAccount($user['user_id']);
|
|
if (blank($wallet)) throw new ApiException('账户类型错误');
|
|
$balance = $wallet->usable_balance;
|
|
|
|
// 计算出所需保证金
|
|
$freeze_balance = PriceCalculate(($avail_position * $position['unit_amount']), '/', $position['lever_rate'], 5);
|
|
$freeze_fee = PriceCalculate($avail_position, '*', $unit_fee, 5);
|
|
|
|
if ($balance < ($freeze_balance + $freeze_fee)) {
|
|
throw new ApiException('账户保证金不足');
|
|
}
|
|
|
|
//创建开仓委托
|
|
$order_data2 = [
|
|
'user_id' => $user['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' => $pair['unit_amount'],
|
|
'order_type' => 1,
|
|
'side' => $position_side == 1 ? 2 : 1,
|
|
'type' => 2,
|
|
'entrust_price' => null,
|
|
'amount' => $avail_position,
|
|
'lever_rate' => $position['lever_rate'],
|
|
'margin' => $freeze_balance,
|
|
'fee' => $freeze_fee,
|
|
'hang_status' => 1,
|
|
'trigger_price' => null,
|
|
'ts' => time(),
|
|
];
|
|
$open_entrust = ContractEntrust::query()->create($order_data2);
|
|
|
|
$log_type = 'open_position'; // 合约开仓冻结
|
|
$log_type2 = 'open_position_fee'; // 合约开仓手续费
|
|
//扣除用户可用资产 冻结保证金
|
|
$user->update_wallet_and_log($wallet['coin_id'], 'usable_balance', -$freeze_balance, UserWallet::sustainable_account, $log_type, '', $open_entrust['contract_id']);
|
|
$user->update_wallet_and_log($wallet['coin_id'], 'freeze_balance', $freeze_balance, UserWallet::sustainable_account, $log_type, '', $open_entrust['contract_id']);
|
|
$user->update_wallet_and_log($wallet['coin_id'], 'usable_balance', -$freeze_fee, UserWallet::sustainable_account, $log_type2, '', $open_entrust['contract_id']);
|
|
$user->update_wallet_and_log($wallet['coin_id'], 'freeze_balance', $freeze_fee, UserWallet::sustainable_account, $log_type2, '', $open_entrust['contract_id']);
|
|
|
|
if ($open_entrust['order_type'] == 1 && $open_entrust['side'] == 1) {
|
|
// 买入开多
|
|
$this->handleOpenBuyOrder($open_entrust);
|
|
} elseif ($open_entrust['order_type'] == 1 && $open_entrust['side'] == 2) {
|
|
// 卖出开空
|
|
$this->handleOpenSellOrder($open_entrust);
|
|
}
|
|
|
|
DB::commit();
|
|
|
|
return api_response()->success('success.');
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
// throw $e;
|
|
return api_response()->error(0, 'error.');
|
|
}
|
|
}
|
|
|
|
public function setStrategy($user, $params)
|
|
{
|
|
$pair = ContractPair::query()->where('symbol', $params['symbol'])->first();
|
|
if (blank($pair)) throw new ApiException('合约不存在');
|
|
// 获取最新一条成交记录 即实时最新价格
|
|
$realtime_price = Cache::store('redis')->get('swap:' . 'trade_detail_' . $pair['symbol'])['price'] ?? null;
|
|
|
|
if (blank($params['tp_trigger_price']) && blank($params['sl_trigger_price'])) {
|
|
throw new ApiException('请设置止盈价/止损价');
|
|
}
|
|
|
|
if ($params['position_side'] == 1) {
|
|
// 多仓
|
|
if (!blank($params['tp_trigger_price']) && $params['tp_trigger_price'] < $realtime_price) throw new ApiException('止盈触发价需大于最新成交价');
|
|
if (!blank($params['sl_trigger_price']) && $params['sl_trigger_price'] > $realtime_price) throw new ApiException('止损触发价需小于最新成交价');
|
|
} else {
|
|
// 空仓
|
|
if (!blank($params['tp_trigger_price']) && $params['tp_trigger_price'] > $realtime_price) throw new ApiException('止盈触发价需小于最新成交价');
|
|
if (!blank($params['sl_trigger_price']) && $params['sl_trigger_price'] < $realtime_price) throw new ApiException('止损触发价需大于最新成交价');
|
|
}
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
|
|
$where = [
|
|
'user_id' => $user['user_id'],
|
|
'contract_id' => $pair['id'],
|
|
'symbol' => $pair['symbol'],
|
|
'position_side' => $params['position_side'],
|
|
'status' => 1,
|
|
];
|
|
$create_data = [
|
|
// 'user_id' => $user['user_id'],
|
|
// 'contract_id' => $pair['id'],
|
|
// 'symbol' => $pair['symbol'],
|
|
// 'position_side' => $params['position_side'],
|
|
'current_price' => $realtime_price,
|
|
'sl_trigger_price' => $params['sl_trigger_price'],
|
|
'sl_trigger_type' => 2,
|
|
'tp_trigger_price' => $params['tp_trigger_price'],
|
|
'tp_trigger_type' => 2,
|
|
];
|
|
ContractStrategy::query()->updateOrCreate($where, $create_data);
|
|
|
|
DB::commit();
|
|
|
|
return api_response()->success('Success');
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
throw new ApiException($e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function expectProfit($user, $params)
|
|
{
|
|
$pair = ContractPair::query()->where('symbol', $params['symbol'])->first();
|
|
if (blank($pair)) throw new ApiException('合约不存在');
|
|
// 获取最新一条成交记录 即实时最新价格
|
|
$realtime_price = Cache::store('redis')->get('swap:' . 'trade_detail_' . $pair['symbol'])['price'] ?? null;
|
|
|
|
if ($params['position_side'] == 1) {
|
|
// 多仓
|
|
$position = ContractPosition::getPosition(['user_id' => $user['user_id'], 'contract_id' => $pair['id'], 'side' => $params['position_side']]);
|
|
} else {
|
|
// 空仓
|
|
$position = ContractPosition::getPosition(['user_id' => $user['user_id'], 'contract_id' => $pair['id'], 'side' => $params['position_side']]);
|
|
}
|
|
$expect_profit = ContractTool::unRealProfit($position, $pair, $realtime_price);
|
|
$data['expect_profit'] = $expect_profit;
|
|
return api_response()->success('success', $data);
|
|
}
|
|
|
|
public function cancelEntrust($user, $params)
|
|
{
|
|
$entrust = ContractEntrust::query()->where(['user_id' => $user['user_id'], 'symbol' => $params['symbol'], 'id' => $params['entrust_id']])->firstOrFail();
|
|
if (!$entrust->can_cancel()) throw new ApiException('当前委托不可撤销');
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
//更新委托
|
|
$res = $entrust->update([
|
|
'status' => 0,
|
|
'cancel_time' => time(),
|
|
]);
|
|
|
|
if ($entrust['order_type'] == 1) {
|
|
// 开仓方向
|
|
// 合约保证金账户
|
|
$wallet = SustainableAccount::query()->where(['user_id' => $user->user_id])->first();
|
|
if (blank($wallet)) throw new ApiException('账户类型错误');
|
|
$log_type = 'cancel_open_position'; // 撤销合约委托
|
|
$log_type2 = 'cancel_open_position_fee'; // 撤销合约委托
|
|
//退还用户可用资产 冻结保证金
|
|
$user->update_wallet_and_log($wallet['coin_id'], 'usable_balance', $entrust['margin'], UserWallet::sustainable_account, $log_type, '', $entrust['contract_id']);
|
|
$user->update_wallet_and_log($wallet['coin_id'], 'freeze_balance', -$entrust['margin'], UserWallet::sustainable_account, $log_type, '', $entrust['contract_id']);
|
|
$user->update_wallet_and_log($wallet['coin_id'], 'usable_balance', $entrust['fee'], UserWallet::sustainable_account, $log_type2, '', $entrust['contract_id']);
|
|
$user->update_wallet_and_log($wallet['coin_id'], 'freeze_balance', -$entrust['fee'], UserWallet::sustainable_account, $log_type2, '', $entrust['contract_id']);
|
|
} else {
|
|
// 平仓方向
|
|
$position_side = $entrust['side'] == 1 ? 2 : 1;
|
|
// 持仓信息
|
|
$position = ContractPosition::getPosition(['user_id' => $user['user_id'], 'contract_id' => $entrust['contract_id'], 'side' => $position_side]);
|
|
if (blank($position)) throw new ApiException();
|
|
// 回退持仓数量
|
|
$position->update([
|
|
'avail_position' => $position->avail_position + $entrust['amount'],
|
|
'freeze_position' => $position->freeze_position - $entrust['amount'],
|
|
]);
|
|
}
|
|
|
|
DB::commit();
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
throw new ApiException($e->getMessage());
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
|
|
public function batchCancelEntrust($user, $params)
|
|
{
|
|
$builder = ContractEntrust::query()
|
|
->where('user_id', $user['user_id'])
|
|
->whereIn('status', [ContractEntrust::status_wait, ContractEntrust::status_trading]);
|
|
|
|
if (isset($params['symbol'])) {
|
|
$builder->where('symbol', $params['symbol']);
|
|
}
|
|
$entrusts = $builder->get();
|
|
if (blank($entrusts)) throw new ApiException('暂无委托');
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
|
|
foreach ($entrusts as $entrust) {
|
|
$params2 = ['entrust_id' => $entrust['id'], 'symbol' => $entrust['symbol']];
|
|
$this->cancelEntrust($user, $params2);
|
|
}
|
|
|
|
DB::commit();
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
throw new ApiException($e->getMessage());
|
|
}
|
|
|
|
return api_response()->success('撤单成功');
|
|
}
|
|
|
|
public function getCurrentEntrust($user, $params)
|
|
{
|
|
$builder = ContractEntrust::query()
|
|
->where('user_id', $user['user_id'])
|
|
->whereIn('status', [ContractEntrust::status_wait, ContractEntrust::status_trading]);
|
|
|
|
if (isset($params['symbol'])) $builder->where('symbol', $params['symbol']);
|
|
if (isset($params['type'])) $builder->where('type', $params['type']);
|
|
if (isset($params['order_type'])) $builder->where('order_type', $params['order_type']);
|
|
if (isset($params['side'])) $builder->where('side', $params['side']);
|
|
|
|
return $builder->orderByDesc('id')->paginate();
|
|
}
|
|
|
|
public function getHistoryEntrust($user, $params)
|
|
{
|
|
$builder = ContractEntrust::query()
|
|
->where('user_id', $user['user_id'])
|
|
->whereIn('status', [ContractEntrust::status_cancel, ContractEntrust::status_completed]);
|
|
|
|
if (isset($params['symbol'])) $builder->where('symbol', $params['symbol']);
|
|
if (isset($params['type'])) $builder->where('type', $params['type']);
|
|
if (isset($params['order_type'])) $builder->where('order_type', $params['order_type']);
|
|
if (isset($params['side'])) $builder->where('side', $params['side']);
|
|
return $builder->orderByDesc('id')->paginate();
|
|
}
|
|
|
|
public function getEntrustDealList($user_id, $params)
|
|
{
|
|
$entrust = ContractEntrust::query()->where(['user_id' => $user_id, 'symbol' => $params['symbol'], 'id' => $params['entrust_id']])->firstOrFail();
|
|
if ($entrust['side'] == 1) {
|
|
return ContractOrder::query()->where('buy_id', $entrust['id'])->get();
|
|
} else {
|
|
return ContractOrder::query()->where('sell_id', $entrust['id'])->get();
|
|
}
|
|
}
|
|
|
|
public function getDealList($user_id, $params)
|
|
{
|
|
$builder = ContractOrder::query()->where(function ($q) use ($user_id) {
|
|
$q->where('buy_user_id', $user_id)->orWhere('sell_user_id', $user_id);
|
|
});
|
|
|
|
if (isset($params['symbol'])) $builder->where('symbol', $params['symbol']);
|
|
if (isset($params['order_type'])) $builder->where('order_type', $params['order_type']);
|
|
return $builder->orderByDesc('created_at')->paginate();
|
|
}
|
|
|
|
public function handleOpenBuyOrder($entrust)
|
|
{
|
|
$pair = ContractPair::query()->where('symbol', $entrust['symbol'])->first();
|
|
if (blank($pair)) return; //如果存在该合约
|
|
$surplus_amount = $entrust['amount'] - $entrust['traded_amount']; //获取未成交张数
|
|
$margin = $entrust['margin']; //获取委托保证金
|
|
if ($entrust['type'] == 1 || $entrust['type'] == 3) { //如果交易类型为限价/止盈止损
|
|
// 限价单 成交价格取买单委托价
|
|
$entrust_price = $entrust['entrust_price']; //获取委托价格
|
|
$cacheKey = 'swap:trade_detail_' . $entrust['symbol'];
|
|
$cacheData = Cache::store('redis')->get($cacheKey);
|
|
if (!blank($cacheData) && $entrust_price > $cacheData['price']) {
|
|
$entrust_price = $cacheData['price']; //如果委托价大于当前市价格,那么委托价格等于当前市价
|
|
}
|
|
} else { //如果是市价交易
|
|
// TODO 市价单 成交价格取当前市场实时成交价 或者卖一价
|
|
$cacheKey = 'swap:trade_detail_' . $entrust['symbol'];
|
|
$cacheData = Cache::store('redis')->get($cacheKey);
|
|
if (blank($cacheData)) return;
|
|
$entrust_price = $cacheData['price']; //委托价格 = 当前市价
|
|
}
|
|
if ($surplus_amount <= 0) return; //如果没有为成交张数 直接返回
|
|
$user = User::getOneSystemUser(); // 获取随机一个系统账户
|
|
if (blank($user)) return;
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
//创建订单
|
|
$order_data = [
|
|
'user_id' => $user['user_id'],
|
|
'order_no' => get_order_sn('PCB'),
|
|
'contract_id' => $entrust['contract_id'],
|
|
'contract_coin_id' => $entrust['contract_coin_id'],
|
|
'margin_coin_id' => $entrust['margin_coin_id'],
|
|
'symbol' => $entrust['symbol'],
|
|
'unit_amount' => $entrust['unit_amount'],
|
|
'order_type' => 1,
|
|
'side' => 2, //卖出
|
|
'type' => 1,
|
|
'entrust_price' => $entrust_price,
|
|
'amount' => $surplus_amount,
|
|
'lever_rate' => $entrust['lever_rate'],
|
|
'margin' => $margin,
|
|
'fee' => 0,
|
|
'hang_status' => 1,
|
|
'trigger_price' => null,
|
|
'ts' => time(),
|
|
];
|
|
$sell = ContractEntrust::query()->create($order_data); //创建系统账户的卖单
|
|
|
|
$this->openDeal($entrust, $sell, 'buy');
|
|
|
|
DB::commit();
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
public function handleOpenSellOrder($entrust)
|
|
{
|
|
$pair = ContractPair::query()->where('symbol', $entrust['symbol'])->first();
|
|
if (blank($pair)) return;
|
|
$surplus_amount = $entrust['amount'] - $entrust['traded_amount'];
|
|
$margin = $entrust['margin'];
|
|
|
|
if ($entrust['type'] == 1 || $entrust['type'] == 3) {
|
|
// 限价单 成交价格取买单委托价
|
|
$entrust_price = $entrust['entrust_price'];
|
|
$cacheKey = 'swap:trade_detail_' . $entrust['symbol'];
|
|
$cacheData = Cache::store('redis')->get($cacheKey);
|
|
if (!blank($cacheData) && $entrust_price < $cacheData['price']) {
|
|
$entrust_price = $cacheData['price'];
|
|
}
|
|
} else {
|
|
// TODO 市价单 成交价格取当前市场实时成交价 或者卖一价
|
|
$cacheKey = 'swap:trade_detail_' . $entrust['symbol'];
|
|
$cacheData = Cache::store('redis')->get($cacheKey);
|
|
if (blank($cacheData)) return;
|
|
$entrust_price = $cacheData['price'];
|
|
}
|
|
if ($surplus_amount <= 0) return;
|
|
$user = User::getOneSystemUser(); // 获取随机一个系统账户
|
|
if (blank($user)) return;
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
//创建订单
|
|
$order_data = [
|
|
'user_id' => $user['user_id'],
|
|
'order_no' => get_order_sn('PCB'),
|
|
'contract_id' => $entrust['contract_id'],
|
|
'contract_coin_id' => $entrust['contract_coin_id'],
|
|
'margin_coin_id' => $entrust['margin_coin_id'],
|
|
'symbol' => $entrust['symbol'],
|
|
'unit_amount' => $entrust['unit_amount'],
|
|
'order_type' => 1,
|
|
'side' => 1,
|
|
'type' => 1,
|
|
'entrust_price' => $entrust_price,
|
|
'amount' => $surplus_amount,
|
|
'lever_rate' => $entrust['lever_rate'],
|
|
'margin' => $margin,
|
|
'fee' => 0,
|
|
'hang_status' => 1,
|
|
'trigger_price' => null,
|
|
'ts' => time(),
|
|
];
|
|
$buy = ContractEntrust::query()->create($order_data);
|
|
|
|
$this->openDeal($buy, $entrust, 'sell');
|
|
|
|
DB::commit();
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
public function openDeal($buy, $sell, $side = 'buy')
|
|
{
|
|
$pair = ContractPair::query()->find($buy['contract_id']); //判断当前合约是否存在
|
|
if (blank($pair)) return;
|
|
if ($side == 'buy') {
|
|
$exchange_amount = $sell['amount']; //交易金额等于卖家委托数量
|
|
$unit_price = $sell['entrust_price']; //卖家委托价格
|
|
$unit_amount = $buy['unit_amount']; // 单张合约面值
|
|
$unit_fee = $buy['fee'] / $buy['amount']; // 单张合约手续费
|
|
|
|
$buy_fee = PriceCalculate($exchange_amount, '*', $unit_fee, 5); //买家手续费
|
|
$sell_fee = 0; //卖家手续费
|
|
} else {
|
|
$exchange_amount = $buy['amount'];
|
|
$unit_price = $buy['entrust_price'];
|
|
$unit_amount = $sell['unit_amount']; // 单张合约面值
|
|
$unit_fee = $sell['fee'] / $sell['amount']; // 单张合约手续费
|
|
|
|
$buy_fee = 0;
|
|
$sell_fee = PriceCalculate($exchange_amount, '*', $unit_fee, 5);
|
|
}
|
|
$buy_traded_amount = $buy['traded_amount'] + $exchange_amount; //追加买家已交易数量
|
|
$sell_traded_amount = $sell['traded_amount'] + $exchange_amount; //追加卖家已交易数量
|
|
$buy_margin = PriceCalculate(($exchange_amount * $unit_amount), '/', $buy['lever_rate'], 5); //买家保证金
|
|
$sell_margin = PriceCalculate(($exchange_amount * $unit_amount), '/', $sell['lever_rate'], 5); //卖家保证金
|
|
//增加委托成交匹配记录
|
|
ContractOrder::query()->create([
|
|
'contract_id' => $buy['contract_id'], //合约ID
|
|
'symbol' => $buy['symbol'], //合约名称
|
|
'unit_amount' => $buy['unit_amount'], //单张面值
|
|
'order_type' => $buy['order_type'], //订单类型 1开仓 2 平仓
|
|
'lever_rate' => $buy['lever_rate'], //倍数
|
|
'buy_id' => $buy['id'], //买方订单ID
|
|
'sell_id' => $sell['id'], //卖方订单ID
|
|
'buy_user_id' => $buy['user_id'], //买家用户ID
|
|
'sell_user_id' => $sell['user_id'], //卖家用户ID
|
|
'unit_price' => $unit_price, //成交价格
|
|
'trade_amount' => $exchange_amount, //交易数量
|
|
'trade_buy_fee' => $buy_fee, //买方交易手续费
|
|
'trade_sell_fee' => $sell_fee, //卖方交易手续费
|
|
'ts' => time(),
|
|
]);
|
|
|
|
if ($side == 'buy') {
|
|
$buy_user = User::query()->find($buy['user_id']);
|
|
if (!blank($buy_user)) {
|
|
// 买家 更新用户合约账户保证金
|
|
$buy_user->update_wallet_and_log($buy['margin_coin_id'], 'used_balance', $buy_margin, UserWallet::sustainable_account, 'contract_deal', '', $buy['contract_id']);
|
|
$buy_user->update_wallet_and_log($buy['margin_coin_id'], 'freeze_balance', -$buy_margin, UserWallet::sustainable_account, 'contract_deal', '', $buy['contract_id']);
|
|
$buy_user->update_wallet_and_log($buy['margin_coin_id'], 'freeze_balance', -$buy_fee, UserWallet::sustainable_account, 'contract_deal', '', $buy['contract_id']);
|
|
// 更新用户持仓信息
|
|
$buy_position = ContractPosition::getPosition(['user_id' => $buy['user_id'], 'contract_id' => $buy['contract_id'], 'side' => $buy['side']]);
|
|
$buy_position->update([
|
|
'hold_position' => $buy_position['hold_position'] + $exchange_amount, //持仓数量
|
|
'avail_position' => $buy_position['avail_position'] + $exchange_amount, //可平数量
|
|
'lever_rate' => $buy['lever_rate'], //倍数
|
|
'unit_amount' => $buy['unit_amount'], //面值
|
|
'position_margin' => $buy_position['position_margin'] + $buy_margin, //保证金
|
|
'avg_price' => ($buy_position['avg_price'] * $buy_position['hold_position'] + $unit_price * $exchange_amount) / ($buy_position['hold_position'] + $exchange_amount), //开仓平均价
|
|
]);
|
|
}
|
|
} else {
|
|
$sell_user = User::query()->find($sell['user_id']);
|
|
if (!blank($sell_user)) {
|
|
//卖家 更新用户合约账户保证金
|
|
$sell_user->update_wallet_and_log($sell['margin_coin_id'], 'used_balance', $sell_margin, UserWallet::sustainable_account, 'contract_deal', '', $sell['contract_id']);
|
|
$sell_user->update_wallet_and_log($sell['margin_coin_id'], 'freeze_balance', -$sell_margin, UserWallet::sustainable_account, 'contract_deal', '', $sell['contract_id']);
|
|
$sell_user->update_wallet_and_log($sell['margin_coin_id'], 'freeze_balance', -$sell_fee, UserWallet::sustainable_account, 'contract_deal', '', $sell['contract_id']);
|
|
// 更新用户持仓信息
|
|
$sell_position = ContractPosition::getPosition(['user_id' => $sell['user_id'], 'contract_id' => $sell['contract_id'], 'side' => $sell['side']]);
|
|
$sell_position->update([
|
|
'hold_position' => $sell_position['hold_position'] + $exchange_amount,
|
|
'avail_position' => $sell_position['avail_position'] + $exchange_amount,
|
|
'lever_rate' => $sell['lever_rate'],
|
|
'unit_amount' => $sell['unit_amount'],
|
|
'position_margin' => $sell_position['position_margin'] + $sell_margin,
|
|
'avg_price' => ($sell_position['avg_price'] * $sell_position['hold_position'] + $unit_price * $exchange_amount) / ($sell_position['hold_position'] + $exchange_amount),
|
|
]);
|
|
}
|
|
}
|
|
|
|
//更新买卖委托
|
|
$buy_avg_price = blank($buy['avg_price']) ? $unit_price : PriceCalculate(($buy['traded_amount'] * $buy['avg_price'] + $exchange_amount * $unit_price), '/', $buy_traded_amount);
|
|
if ($buy_traded_amount == $buy['amount']) {
|
|
$buy->update(['traded_amount' => $buy_traded_amount, 'avg_price' => $buy_avg_price, 'status' => ContractEntrust::status_completed]);
|
|
} else {
|
|
$buy->update(['traded_amount' => $buy_traded_amount, 'avg_price' => $buy_avg_price, 'status' => ContractEntrust::status_trading]);
|
|
}
|
|
$sell_avg_price = blank($sell['avg_price']) ? $unit_price : PriceCalculate(($sell['traded_amount'] * $sell['avg_price'] + $exchange_amount * $unit_price), '/', $sell_traded_amount);
|
|
if ($sell_traded_amount == $sell['amount']) {
|
|
$sell->update(['traded_amount' => $sell_traded_amount, 'avg_price' => $sell_avg_price, 'status' => ContractEntrust::status_completed]);
|
|
} else {
|
|
$sell->update(['traded_amount' => $sell_traded_amount, 'avg_price' => $sell_avg_price, 'status' => ContractEntrust::status_trading]);
|
|
}
|
|
|
|
// 计算订单返佣,创建佣金记录
|
|
try {
|
|
DB::beginTransaction();
|
|
// 计算上级奖励
|
|
$user = ($side == "buy") ? $buy : $sell;
|
|
$fee = ($side == "buy") ? $buy_fee : $sell_fee;
|
|
$rebates = Rebate::rebateLevelDiff($user['user_id'], $fee);
|
|
foreach ($rebates as $k => $v) {
|
|
\App\Models\Contract\ContractRebate::create([
|
|
'aid' => $v['aid'], //拿去分佣的代理商
|
|
'order_no' => $user['order_no'],
|
|
'user_id' => $user['user_id'],
|
|
'user_referrer' => $v['user_referrer'], //用户上级代理商UID
|
|
'deep' => $k + 1,
|
|
'rebate_type' => ($k == 0) ? 'contract_direct_open_reward' : 'contract_indirect_open_reward',
|
|
'contract_pair' => $user['symbol'] . 'USDT',
|
|
'side' => $user['side'],
|
|
'margin' => $user['margin'], //委托保证金
|
|
'fee' => $fee,
|
|
'rebate_rate' => $v['rebate_rate'],
|
|
'rebate' => $v['rebate'],
|
|
'status' => 0,
|
|
'order_time' => $user['ts']
|
|
]);
|
|
}
|
|
DB::commit();
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
dd($e);
|
|
info($e);
|
|
}
|
|
}
|
|
|
|
public function handleFlatBuyOrder($entrust, $system = 0)
|
|
{
|
|
Log::info("handleFlatBuyOrder start");
|
|
$surplus_amount = $entrust['amount'] - $entrust['traded_amount'];
|
|
if ($entrust['type'] == 1 || $entrust['type'] == 3) {
|
|
// 限价单 成交价格取买单委托价
|
|
$entrust_price = $entrust['entrust_price'];
|
|
$cacheKey = 'swap:trade_detail_' . $entrust['symbol'];
|
|
$cacheData = Cache::store('redis')->get($cacheKey);
|
|
if (!blank($cacheData) && $entrust_price > $cacheData['price']) {
|
|
$entrust_price = $cacheData['price'];
|
|
}
|
|
} else {
|
|
// TODO 市价单 成交价格取当前市场实时成交价 或者卖一价
|
|
$cacheKey = 'swap:trade_detail_' . $entrust['symbol'];
|
|
$cacheData = Cache::store('redis')->get($cacheKey);
|
|
if (blank($cacheData)) return;
|
|
$entrust_price = $cacheData['price'];
|
|
}
|
|
if ($surplus_amount <= 0) return;
|
|
$user = User::getOneSystemUser(); // 获取随机一个系统账户
|
|
if (blank($user)) return;
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
//创建订单
|
|
$order_data = [
|
|
'user_id' => $user['user_id'],
|
|
'order_no' => get_order_sn('PCB'),
|
|
'contract_id' => $entrust['contract_id'],
|
|
'contract_coin_id' => $entrust['contract_coin_id'],
|
|
'margin_coin_id' => $entrust['margin_coin_id'],
|
|
'symbol' => $entrust['symbol'],
|
|
'unit_amount' => $entrust['unit_amount'],
|
|
'order_type' => 2,
|
|
'side' => 2,
|
|
'type' => 1,
|
|
'entrust_price' => $entrust_price,
|
|
'amount' => $surplus_amount,
|
|
'lever_rate' => $entrust['lever_rate'],
|
|
'ts' => time(),
|
|
'system' => $system,
|
|
];
|
|
$sell = ContractEntrust::query()->create($order_data);
|
|
|
|
$this->flatDeal($entrust, $sell, 'buy', $system);
|
|
|
|
DB::commit();
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
throw new ApiException($e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function handleFlatSellOrder($entrust, $system = 0)
|
|
{
|
|
Log::info("handleFlatSellOrder_start");
|
|
$surplus_amount = $entrust['amount'] - $entrust['traded_amount'];
|
|
if ($entrust['type'] == 1 || $entrust['type'] == 3) {
|
|
// 限价单 成交价格取买单委托价
|
|
$entrust_price = $entrust['entrust_price'];
|
|
$cacheKey = 'swap:trade_detail_' . $entrust['symbol'];
|
|
$cacheData = Cache::store('redis')->get($cacheKey);
|
|
if (!blank($cacheData) && $entrust_price < $cacheData['price']) {
|
|
$entrust_price = $cacheData['price'];
|
|
}
|
|
} else {
|
|
// TODO 市价单 成交价格取当前市场实时成交价 或者卖一价
|
|
$cacheKey = 'swap:trade_detail_' . $entrust['symbol'];
|
|
$cacheData = Cache::store('redis')->get($cacheKey);
|
|
if (blank($cacheData)) return;
|
|
$entrust_price = $cacheData['price'];
|
|
}
|
|
if ($surplus_amount <= 0) return;
|
|
$user = User::getOneSystemUser(); // 获取随机一个系统账户
|
|
if (blank($user)) return;
|
|
DB::beginTransaction();
|
|
try {
|
|
//创建对手委托
|
|
$order_data = [
|
|
'user_id' => $user['user_id'],
|
|
'order_no' => get_order_sn('PCB'),
|
|
'contract_id' => $entrust['contract_id'],
|
|
'contract_coin_id' => $entrust['contract_coin_id'],
|
|
'margin_coin_id' => $entrust['margin_coin_id'],
|
|
'symbol' => $entrust['symbol'],
|
|
'unit_amount' => $entrust['unit_amount'],
|
|
'order_type' => 2,
|
|
'side' => 1,
|
|
'type' => 1,
|
|
'entrust_price' => $entrust_price,
|
|
'amount' => $surplus_amount,
|
|
'lever_rate' => $entrust['lever_rate'],
|
|
'ts' => time(),
|
|
'system' => $system,
|
|
];
|
|
$buy = ContractEntrust::query()->create($order_data);
|
|
|
|
$this->flatDeal($buy, $entrust, 'sell', $system);
|
|
|
|
DB::commit();
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
throw new ApiException($e->getMessage());
|
|
}
|
|
//Log::info("handleFlatSellOrder_end");
|
|
|
|
}
|
|
|
|
public function flatDeal($buy, $sell, $side = 'buy', $system = 0)
|
|
{
|
|
Log::info("flatDeal");
|
|
|
|
$pair = ContractPair::query()->find($buy['contract_id']);
|
|
|
|
if (blank($pair)) return;
|
|
if ($side == 'buy') {
|
|
$exchange_amount = $sell['amount'];
|
|
$unit_price = $sell['entrust_price'];
|
|
$unit_amount = $sell['unit_amount']; // 单张合约面值
|
|
$unit_fee = PriceCalculate($unit_amount, '*', $pair['maker_fee_rate'], 5); // 单张合约手续费
|
|
|
|
$buy_fee = PriceCalculate($exchange_amount, '*', $unit_fee, 5);
|
|
$sell_fee = 0;
|
|
} else {
|
|
$exchange_amount = $buy['amount'];
|
|
$unit_price = $buy['entrust_price'];
|
|
$unit_amount = $buy['unit_amount']; // 单张合约面值
|
|
$unit_fee = PriceCalculate($unit_amount, '*', $pair['maker_fee_rate'], 5); // 单张合约手续费
|
|
|
|
$buy_fee = 0;
|
|
$sell_fee = PriceCalculate($exchange_amount, '*', $unit_fee, 5);
|
|
}
|
|
|
|
$buy_traded_amount = $buy['traded_amount'] + $exchange_amount;
|
|
$sell_traded_amount = $sell['traded_amount'] + $exchange_amount;
|
|
$buy_margin = PriceCalculate(($exchange_amount * $unit_amount), '/', $buy['lever_rate'], 5);
|
|
$sell_margin = PriceCalculate(($exchange_amount * $unit_amount), '/', $sell['lever_rate'], 5);
|
|
//增加委托成交匹配记录
|
|
ContractOrder::query()->create([
|
|
'contract_id' => $buy['contract_id'],
|
|
'symbol' => $buy['symbol'],
|
|
'unit_amount' => $unit_amount,
|
|
'order_type' => $buy['order_type'],
|
|
'lever_rate' => $buy['lever_rate'],
|
|
'buy_id' => $buy['id'],
|
|
'sell_id' => $sell['id'],
|
|
'buy_user_id' => $buy['user_id'],
|
|
'sell_user_id' => $sell['user_id'],
|
|
'unit_price' => $unit_price,
|
|
'trade_amount' => $exchange_amount,
|
|
'trade_buy_fee' => $buy_fee,
|
|
'trade_sell_fee' => $sell_fee,
|
|
'ts' => time(),
|
|
]);
|
|
//Log::info("解冻合约账户保证金");
|
|
//Log::info($side);
|
|
//Log::info("解冻合约账户保证金_end");
|
|
|
|
// 解冻合约账户保证金 & 扣除平仓手续费
|
|
$log_type = $system == 1 ? 'system_close_position' : 'close_position';
|
|
$log_type2 = $system == 1 ? 'system_close_position_fee' : 'close_position_fee';
|
|
if ($side == 'buy') {
|
|
// 买入平空
|
|
$buy_user = User::query()->find($buy['user_id']);
|
|
|
|
// 空仓
|
|
$empty_position = ContractPosition::getPosition(['user_id' => $buy['user_id'], 'contract_id' => $buy['contract_id'], 'side' => 2], true);
|
|
// if($empty_position['position_margin']<$buy_margin){
|
|
// $buy_margin = $empty_position['position_margin'];
|
|
// }
|
|
Log::info("解冻合约账户保证金");
|
|
if($empty_position['position_margin']<$buy_margin && $buy_margin!=0 && $empty_position['position_margin']!=0){
|
|
Log::info("启用");
|
|
$buy_margin1 = $empty_position['position_margin'];
|
|
}
|
|
if(!isset($buy_margin1)){
|
|
Log::info("没启用");
|
|
$buy_margin1 =$buy_margin;
|
|
}
|
|
$empty_position->update([
|
|
'hold_position' => $empty_position['hold_position'] - $exchange_amount,
|
|
'freeze_position' => $empty_position['freeze_position'] - $exchange_amount,
|
|
'position_margin' => $empty_position['position_margin'] - $buy_margin1,
|
|
]);
|
|
Log::info("减钱开始");
|
|
$cont_acc = SustainableAccount::getContractAccount($sell['user_id']);
|
|
// // Log::info($cont_acc);
|
|
//todo 修复平仓
|
|
if($cont_acc['used_balance']<$buy_margin && $buy_margin!=0 && $cont_acc['used_balance']!=0){
|
|
Log::info("ac启用");
|
|
$buy_margin2 = $cont_acc['used_balance'];
|
|
}
|
|
if(!isset($buy_margin2)){
|
|
Log::info("ac不启用");
|
|
Log::info($cont_acc['used_balance']);
|
|
Log::info($buy_margin);
|
|
$buy_margin2 = $buy_margin;
|
|
}
|
|
$buy_user->update_wallet_and_log($buy['margin_coin_id'], 'usable_balance', $buy_margin2, UserWallet::sustainable_account, $log_type, '', $buy['contract_id']);
|
|
$buy_user->update_wallet_and_log($buy['margin_coin_id'], 'used_balance', -$buy_margin2, UserWallet::sustainable_account, $log_type, '', $buy['contract_id']);
|
|
$buy_user->update_wallet_and_log($buy['margin_coin_id'], 'usable_balance', -$buy_fee, UserWallet::sustainable_account, $log_type2, '', $buy['contract_id']);
|
|
Log::info("减钱结束");
|
|
// TODO 合约账户盈亏结算
|
|
/*
|
|
* 未实现盈亏计算
|
|
* 未实现盈亏,是用户当前持有的仓位的盈亏,未实现盈亏会随着最新成交价格变动而变化。
|
|
* 多仓盈亏 =(平仓均价-开仓均价)* 多仓合约张数 * 合约面值/开仓均价
|
|
* 空仓盈亏 =(开仓均价-平仓均价)* 空仓合约张数 * 合约面值/开仓均价
|
|
* 例:如用户持有1000张BTC永续合约多仓仓位(合约面值为1USD),持仓均价为5000USD/BTC. 若当前最新价格为8000USD/BTC,则现有的未实现盈亏= ( 8000-5000 ) * 1000*1 /5000 = 600USDT。
|
|
* */
|
|
$log_type4 = $system == 1 ? 'system_close_short_position' : 'close_short_position';
|
|
$empty_position['position_margin'] = $buy_margin;
|
|
|
|
// Log::info("huadian买入平空");
|
|
$spread = $pair['settle_spread'] ?? 0;
|
|
// $many_position['avg_price'] = PriceCalculate($many_position['avg_price'], '*', (1 - $spread), 8);
|
|
$unit_price = PriceCalculate($unit_price, '*', (1 + $spread), 8);
|
|
|
|
|
|
|
|
$empty_position_profit = ContractTool::unRealProfit($empty_position, $pair, $unit_price, $exchange_amount);
|
|
// dd($empty_position_profit,$buy_fee,$exchange_amount,$buy_margin);
|
|
$buy_user->update_wallet_and_log($pair['margin_coin_id'], 'usable_balance', $empty_position_profit, UserWallet::sustainable_account, $log_type4, '', $pair['id']);
|
|
|
|
// 平仓 更新委托盈亏记录
|
|
$many_profit = null;
|
|
$empty_profit = blank($buy['profit']) ? $empty_position_profit : $buy['profit'] + $empty_position_profit;
|
|
} else {
|
|
// 卖出平多
|
|
// Log::info("555555");
|
|
$sell_user = User::query()->find($sell['user_id']);
|
|
// 多仓
|
|
$many_position = ContractPosition::getPosition(['user_id' => $sell['user_id'], 'contract_id' => $sell['contract_id'], 'side' => 1], true);
|
|
// Log::info($many_position);
|
|
if($many_position['position_margin']<$sell_margin && $sell_margin!=0 && $many_position['position_margin']!=0){
|
|
// if($many_position['position_margin']<$sell_margin){
|
|
$sell_margin1 = $many_position['position_margin'];
|
|
}
|
|
if(!isset($sell_margin1)){
|
|
// Log::info("777777");
|
|
$sell_margin1 = $sell_margin;
|
|
}
|
|
$many_position->update([
|
|
'hold_position' => $many_position['hold_position'] - $exchange_amount,
|
|
'freeze_position' => $many_position['freeze_position'] - $exchange_amount,
|
|
'position_margin' => $many_position['position_margin'] - $sell_margin1,
|
|
]);
|
|
// Log::info("jianquan market");
|
|
// $cont_acc = ConractA::query()->where('user_id', $user['user_id'])->where('symbol', $params['symbol'])->first();
|
|
$cont_acc = SustainableAccount::getContractAccount($sell['user_id']);
|
|
// Log::info($cont_acc);
|
|
|
|
//todo 修复平仓问题
|
|
if($cont_acc['used_balance']<$sell_margin && $sell_margin!=0 && $cont_acc['used_balance']!=0){
|
|
// if($cont_acc['used_balance']<$sell_margin){
|
|
$sell_margin2 = $cont_acc['used_balance'];
|
|
}
|
|
if(!isset($sell_margin2)){
|
|
$sell_margin2 = $sell_margin;
|
|
}
|
|
$sell_user->update_wallet_and_log($sell['margin_coin_id'], 'usable_balance', $sell_margin2, UserWallet::sustainable_account, $log_type, '', $sell['contract_id']);
|
|
// Log::info("jianquan 1");
|
|
$sell_user->update_wallet_and_log($sell['margin_coin_id'], 'used_balance', -$sell_margin2, UserWallet::sustainable_account, $log_type, '', $sell['contract_id']);
|
|
// Log::info("jianquan 2");
|
|
$sell_user->update_wallet_and_log($sell['margin_coin_id'], 'usable_balance', -$sell_fee, UserWallet::sustainable_account, $log_type2, '', $sell['contract_id']);
|
|
Log::info("jianquan end");
|
|
// TODO 合约账户盈亏结算
|
|
/*
|
|
* 未实现盈亏计算
|
|
* 未实现盈亏,是用户当前持有的仓位的盈亏,未实现盈亏会随着最新成交价格变动而变化。
|
|
* 多仓盈亏 =(平仓均价-开仓均价)* 多仓合约张数 * 合约面值/开仓均价
|
|
* 空仓盈亏 =(开仓均价-平仓均价)* 空仓合约张数 * 合约面值/开仓均价
|
|
* 例:如用户持有1000张BTC永续合约多仓仓位(合约面值为1USD),持仓均价为5000USD/BTC. 若当前最新价格为8000USD/BTC,则现有的未实现盈亏= ( 8000-5000 ) * 1000*1 /5000 = 600USDT。
|
|
* */
|
|
$log_type3 = $system == 1 ? 'system_close_long_position' : 'close_long_position';
|
|
$many_position['position_margin'] = $sell_margin;
|
|
|
|
// Log::info("huadian卖出平多");
|
|
// Log::info($many_position);
|
|
// Log::info($pair);
|
|
// Log::info($unit_price);
|
|
// Log::info($exchange_amount);
|
|
$spread = $pair['settle_spread'] ?? 0;
|
|
// $many_position['avg_price'] = PriceCalculate($many_position['avg_price'], '*', (1 - $spread), 8);
|
|
$unit_price = PriceCalculate($unit_price, '*', (1 - $spread), 8);
|
|
// Log::info("huadian卖出平多2");
|
|
// Log::info($many_position);
|
|
// Log::info($pair);
|
|
// Log::info($unit_price);
|
|
// Log::info($exchange_amount);
|
|
|
|
|
|
$many_position_profit = ContractTool::unRealProfit($many_position, $pair, $unit_price, $exchange_amount);
|
|
// Log::info("计算盈利开始");
|
|
// Log::info($many_position_profit);
|
|
// Log::info($many_position);
|
|
// Log::info($pair);
|
|
// Log::info($unit_price);
|
|
// Log::info($exchange_amount);
|
|
// Log::info("计算盈利结束");
|
|
// //dd($many_position_profit,$sell_fee,$exchange_amount,$sell_margin,$many_position);
|
|
$sell_user->update_wallet_and_log($pair['margin_coin_id'], 'usable_balance', $many_position_profit, UserWallet::sustainable_account, $log_type3, '', $pair['id']);
|
|
|
|
// 平仓 更新委托盈亏记录
|
|
$many_profit = blank($sell['profit']) ? $many_position_profit : $sell['profit'] + $many_position_profit;
|
|
$empty_profit = null;
|
|
}
|
|
|
|
//更新买卖委托
|
|
//Log::info("更新买卖委托");
|
|
$buy_avg_price = blank($buy['avg_price']) ? $unit_price : PriceCalculate(($buy['traded_amount'] * $buy['avg_price'] + $exchange_amount * $unit_price), '/', $buy_traded_amount);
|
|
//Log::info("update_profit_start");
|
|
//Log::info($empty_profit);
|
|
//Log::info("update_profit_end");
|
|
if ($buy_traded_amount == $buy['amount']) {
|
|
$buy->update(['traded_amount' => $buy_traded_amount, 'avg_price' => $buy_avg_price, 'profit' => $empty_profit, 'status' => ContractEntrust::status_completed]);
|
|
} else {
|
|
$buy->update(['traded_amount' => $buy_traded_amount, 'avg_price' => $buy_avg_price, 'profit' => $empty_profit, 'status' => ContractEntrust::status_trading]);
|
|
}
|
|
$sell_avg_price = blank($sell['avg_price']) ? $unit_price : PriceCalculate(($sell['traded_amount'] * $sell['avg_price'] + $exchange_amount * $unit_price), '/', $sell_traded_amount);
|
|
if ($sell_traded_amount == $sell['amount']) {
|
|
$sell->update(['traded_amount' => $sell_traded_amount, 'avg_price' => $sell_avg_price, 'profit' => $many_profit, 'status' => ContractEntrust::status_completed]);
|
|
} else {
|
|
$sell->update(['traded_amount' => $sell_traded_amount, 'avg_price' => $sell_avg_price, 'profit' => $many_profit, 'status' => ContractEntrust::status_trading]);
|
|
}
|
|
|
|
// 计算订单返佣,创建佣金记录
|
|
try {
|
|
DB::beginTransaction();
|
|
// 计算上级奖励
|
|
$user = ($side == "buy") ? $buy : $sell;
|
|
$fee = ($side == "buy") ? $buy_fee : $sell_fee;
|
|
$rebates = Rebate::rebateLevelDiff($user['user_id'], $fee);
|
|
foreach ($rebates as $k => $v) {
|
|
\App\Models\Contract\ContractRebate::create([
|
|
'aid' => $v['aid'], //拿去分佣的代理商
|
|
'order_no' => $user['order_no'],
|
|
'user_id' => $user['user_id'],
|
|
'user_referrer' => $v['user_referrer'], //用户上级代理商UID
|
|
'deep' => $k + 1,
|
|
'rebate_type' => ($k == 0) ? 'contract_direct_flat_reward' : 'contract_indirect_flat_reward',
|
|
'contract_pair' => $user['symbol'] . 'USDT',
|
|
'side' => $user['side'],
|
|
'margin' => $user['margin'], //委托保证金
|
|
'fee' => $fee,
|
|
'rebate_rate' => $v['rebate_rate'],
|
|
'rebate' => $v['rebate'],
|
|
'status' => 0,
|
|
'order_time' => $user['ts']
|
|
]);
|
|
}
|
|
DB::commit();
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
dd($e);
|
|
info($e);
|
|
}
|
|
}
|
|
}
|
|
|