get('lang'); list ( 'user_id' => $user_id, 'type' => $type, 'match_id' => $match_id, 'currency_id' => $currency_id, 'seconds' => $seconds, 'price' => $price, 'number' => $number, 'use_insurance' => $use_insurance, ) = $param; // file_put_contents('/www/wwwroot/crypto/public/m.txt',json_encode($param).PHP_EOL,FILE_APPEND); try { DB::beginTransaction(); //检测用户是否存在 $user = Users::find($user_id); throw_unless($user, new \Exception('用户不存在')); //检测交易对是否存在 $currency_match = CurrencyMatch::find($match_id); throw_unless($currency_match, new \Exception('交易对不存在')); throw_unless($currency_match->open_microtrade, new \Exception('交易未开启')); $currency = Currency::where('is_micro', 1)->find($currency_id); throw_unless($currency, new \Exception('币种不存在或不允许被交易')); //检测秒数是否在合法范围内 $seconds = MicroSecond::where('seconds', $seconds)->first(); throw_unless($seconds, new \Exception('秒数不在时间范围')); //检测数量是否在合法范围内 /* $number_not_exist = $currency->microNumbers->where('number', $number)->isEmpty(); throw_if($number_not_exist, new \Exception('数量不在有效范围内')); */ //整数判断 if (!preg_match('/^\d+$/', $number)) { throw new \Exception('The order quantity must be an integer'); } // if (bc_comp($currency->micro_min, 0) > 0 && $number % $currency->micro_min != 0) { // throw new \Exception('下单数量必须是' . $currency->micro_min . '的整数倍'); // } if (bc_comp($currency->micro_max, $number) < 0 && bc_comp($currency->micro_max, 0) > 0) { throw new \Exception('The maximum number of orders cannot exceed:' . $currency->micro_max); } // if (bc_comp($currency->micro_min, $number) > 0 && bc_comp($currency->micro_min, 0) > 0) { // throw new \Exception('最小下单数量不能小于:' . $currency->micro_min); // } //持仓类计判断 //扣款 $wallet = UsersWallet::where('currency', $currency_id) ->where('user_id', $user_id) ->first(); throw_unless($wallet, new \Exception('用户钱包不存在')); if($use_insurance != 0){ $balance_type = 5; }else{ $balance_type = 4; } $is_insurance = $use_insurance; $result = change_wallet_balance($wallet, $balance_type, -$number, AccountLog::DEDUCT_PRINCIPAL_PLACING, '秒合约下单扣除本金'); throw_unless($result === true, new \Exception($result)); //扣手续费 $fee = bc_div(bc_mul($number, $currency->micro_trade_fee), 100); $result = change_wallet_balance($wallet, $balance_type, -$fee, AccountLog::DEDUCT_PRINCIPAL_PLACING, '秒合约下单扣除' . $currency->micro_trade_fee . '%手续费'); $level=Level::where('level',$user->level)->first(); $insurance_start = Setting::getValueByKey('insurance_start','09:00'); $insurance_end = Setting::getValueByKey('insurance_end','12:00'); $insurance_start_datetime = Carbon::parse(date("Y-m-d {$insurance_start}:00")); $insurance_end_datetime = Carbon::parse(date("Y-m-d {$insurance_end}:00")); //在受保时间段的话 if (Carbon::now()->gte($insurance_start_datetime) && Carbon::now()->lte($insurance_end_datetime)) { $at_protected = true; }else{ $at_protected = false; } if (!empty($level) && !$at_protected){ Users::rebate($user_id,$user_id,$currency_id,$fee,1,$level->max_algebra); } throw_unless($result === true, new \Exception($result)); $now = Carbon::now(); //生成交易数据 $order_data = [ 'user_id' => $user_id, 'match_id' => $currency_match->id, 'currency_id' => $currency->id, 'type' => $type, 'seconds' => $seconds->seconds, 'number' => $number, 'open_price' => $price, 'end_price' => $price, 'profit_ratio' => $seconds->profit_ratio, 'loss_ratio' => $seconds->loss_ratio, 'fee' => $fee, 'status' => MicroOrder::STATUS_OPENED, 'pre_profit_result' => 0, //预设赢利 'handled_at' => $now->addSeconds($seconds->seconds), //'handled_at' => date('Y-m-d H:i:s',time()+$seconds->seconds), //'complete_at' => date('Y-m-d H:i:s',time()+$seconds->seconds), 'is_insurance' => $is_insurance, 'agent_path' =>$user->agent_path, ]; //添加一个交易 $result = MicroOrder::unguarded(function () use ($order_data) { $micro_order = MicroOrder::create($order_data); return $micro_order; }); DB::commit(); return $result; } catch (\Throwable $th) { DB::rollBack(); throw $th; } } /** * 批量更新交易对的价格 * * @param integer $match_id * @return void */ public static function newPrice($match_id, $price) { MicroOrder::where('status', MicroOrder::STATUS_OPENED) ->where('match_id', $match_id) ->where('pre_profit_result', 0) ->update([ 'end_price' => $price, ]); self::risk($match_id); } public static function mergeCountPrice($shoud_price_list) { $merge_price = [ 'max_price' => 0, 'min_price' => 0, ]; foreach ($shoud_price_list as $key => $value) { if (isset($value['max_price']) && bc_comp($value['max_price'], $merge_price['max_price']) > 0) { $merge_price['max_price'] = $value['max_price']; } if ( isset($value['min_price']) && (bc_comp($value['min_price'], $merge_price['min_price']) < 0 || bc_comp($merge_price['min_price'], 0) == 0) ) { $merge_price['min_price'] = $value['min_price']; } } return $merge_price; } /** * 交易订单统计 * * @param $orders * @return array */ public static function orderCount($orders) { //按盈亏进行分组 $profit_group_order = $orders->groupBy('pre_profit_result'); $shoud_price_list = []; $profit_group_order->each(function (\Illuminate\Database\Eloquent\Collection $item, $key) use (&$shoud_price_list) { $result_type = $key; //按交易类型(买涨,买跌)来分组统计 $type_group_orders = $item->groupBy('type'); $type_group_orders->each(function (\Illuminate\Database\Eloquent\Collection $item, $key) use ($result_type, &$shoud_price_list) { $submit_type = $key; list( 'name' => $price_name, 'price' => $right_price, ) = self::countPrice($result_type, $submit_type, $item); $shoud_price_list[$result_type][$price_name . '_price'] = $right_price; }); }); return $shoud_price_list; } /** * 统计订单类型和盈亏推断价格 * * @param integer $result_type 盈亏(-1亏,1盈) * @param integer $type 下单类型(买涨、买跌) * @param \Illuminate\Database\Eloquent\Collection $orders * @return array */ public static function countPrice($result_type, $type, $orders) { if ($result_type == MicroOrder::RESULT_LOSS) { //亏损处理 if ($type == MicroOrder::TYPE_RISE) { //统计出买涨的最低价让行情价格低于最低价 $name = 'min'; $right_price = $orders->min('open_price'); } elseif ($type == MicroOrder::TYPE_FALL) { //统计出买跌的最高价让行情价格高于最高价 $name = 'max'; $right_price = $orders->max('open_price'); } } elseif ($result_type == MicroOrder::RESULT_PROFIT) { //盈利处理 if ($type == MicroOrder::TYPE_RISE) { //统计出买涨的最高价让行情价格高于最高价 $name = 'max'; $right_price = $orders->max('open_price'); } elseif ($type == MicroOrder::TYPE_FALL) { //统计出买跌的最低价让行情价格低于最低价 $name = 'min'; $right_price = $orders->min('open_price'); } } else { //平局处理 } return [ 'name' => $name, 'price' => $right_price, ]; } /** * 根据指定订单推断出价格并更新 * * @param \App\CurrencyMatch $currency_match * @param \Illuminate\Database\Eloquent\Collection $micro_order * @return void */ public static function deduceOrderPrice($currency_match, $micro_order) { // echo date('Y-m-d H:i:s ') . '订单推算中...' . PHP_EOL; $micro_order = $micro_order->where('match_id', $currency_match->id); //过滤一下交易对 $shoud_price_list = self::orderCount($micro_order); $price_range = self::mergeCountPrice($shoud_price_list); /* 1.当最高价小于最低价时,为最理想情况,一个价格(区间:maxfluctuate_min, '.') !== false) { $fluctuate_min = rtrim($currency_match->fluctuate_min, '0'); //移除掉小数点后面右侧多余的0 $fluctuate_min = rtrim($fluctuate_min, '.'); //如果是整数再移除掉小数点 $decimal_index = stripos($fluctuate_min, '.'); //查找小数点的位置 if ($decimal_index !== false) { $decimal = strlen($fluctuate_min) - $decimal_index - 1; } } trim($currency_match->fluctuate_min, '0'); $float_diff = $faker->randomFloat($decimal, $currency_match->fluctuate_min, $currency_match->fluctuate_max); //产生一个随机浮动价格 $start = microtime(true); foreach ($price_range as $key => $value) { if ($key == 'max_price') { if (bc_comp($value, 0) > 0) { $price_range[$key] = $value = bc_add($value, $float_diff); MarketHour::batchEsearchMarket($currency_match->currency_name, $currency_match->legal_name, $value, time()); } } elseif ($key == 'min_price') { if (bc_comp($value, 0) > 0) { $price_range[$key] = $value = bc_sub($value, $float_diff); MarketHour::batchEsearchMarket($currency_match->currency_name, $currency_match->legal_name, $value, time()); } } } $end = microtime(true); // echo '插入K线耗时:' . ($end - $start) . '秒' . PHP_EOL; $handle_orders = $micro_order->where('status', '<>', MicroOrder::STATUS_CLOSED)->where('pre_profit_result', '<>', 0); $handle_orders = $handle_orders->groupBy('pre_profit_result'); $handle_orders->each(function (\Illuminate\Database\Eloquent\Collection $item, $key) use ($price_range) { $pre_profit_result = $key; $item->each(function ($item, $key) use ($price_range, $pre_profit_result) { // dump($price_range); if ($pre_profit_result == 1) { // 盈利 // echo date('Y-m-d H:i:s ') . '订单:' . $item->id . ',买' . $item->type_name . ',盈利处理:' . PHP_EOL; $item->refresh(); if ($item->type == MicroOrder::TYPE_RISE) { $item->end_price = $price_range['max_price']; } elseif ($item->type == MicroOrder::TYPE_FALL) { $item->end_price = $price_range['min_price']; } $item->save(); } elseif ($pre_profit_result == -1) { // 亏损 // echo date('Y-m-d H:i:s ') . '订单:' . $item->id . ',买' . $item->type_name . ',亏损处理:' . PHP_EOL; $item->refresh(); if ($item->type == MicroOrder::TYPE_RISE) { $item->end_price = $price_range['min_price']; } elseif ($item->type == MicroOrder::TYPE_FALL) { $item->end_price = $price_range['max_price']; } $item->save(); } }); }); // echo date('Y-m-d H:i:s ') . '订单推算完成' . PHP_EOL; } /** * 取风控开始影响秒数 * * @return void */ public static function getRiskAdvanceSeconds() { $risk_end_ago_min = Setting::getValueByKey('risk_end_ago_min', 0); $risk_end_ago_max = Setting::getValueByKey('risk_end_ago_max', 0); $risk_advance_seconds = $risk_end_ago_max; return $risk_advance_seconds; } /** * 按用户进行风控 * * @param \App\CurrencyMatch $currency_match * @param integer $risk_advance_seconds 风控影响秒数 * @param Illuminate\Support\Carbon $now 当前时间 * @return void */ public static function riskByUser($currency_match, $risk_advance_seconds, $now) { //先找出来设定了按用户风控的列表 $user_list = Users::where('risk', '<>', 0) ->pluck('id') ->all(); if (count($user_list) <= 0) { //throw new \Exception('当前没有要风控的用户'); return false; } $user_orders = MicroOrder::where('match_id', $currency_match->id) ->whereIn('user_id', $user_list) ->where('status', '<>', MicroOrder::STATUS_CLOSED) ->where('handled_at', '<=', $now->addSeconds($risk_advance_seconds)) ->get(); if (count($user_orders) <= 0) { //throw new \Exception('当前被控用户没有要处理的订单或不在风控时间内'); return false; } //按用户进行分类 $user_groupby_order = $user_orders->groupBy('user_id'); $user_count = $user_groupby_order->count(); //当前受风控影响的用户数 $user_groupby_order->each(function (\Illuminate\Database\Eloquent\Collection $item, $key) { $user = Users::find($key); $ids = $item->pluck('id')->all(); if (!empty($user->risk)) { //更新订单的预设盈亏结果 MicroOrder::whereIn('id', $ids) ->where('pre_profit_result', '<>', $user->risk) ->update([ 'pre_profit_result' => $user->risk, ]); } }); $user_id_list = $user_orders->pluck('id')->all(); $micro_order = MicroOrder::where('match_id', $currency_match->id) ->whereIn('id', $user_id_list) ->where('status', '<>', MicroOrder::STATUS_CLOSED) ->get(); self::deduceOrderPrice($currency_match, $micro_order); } /** * 按订单进行风控 * * @param \App\CurrencyMatch $currency_match * @param integer $risk_advance_seconds 风控影响秒数 * @param Illuminate\Support\Carbon $now 当前时间 * @return void */ public static function riskByOrders($currency_match, $risk_advance_seconds, $now) { $pre_profit_orders = MicroOrder::where('match_id', $currency_match->id) ->where('pre_profit_result', '<>', 0) ->where('status', '<>', MicroOrder::STATUS_CLOSED) ->where('handled_at', '<=', $now->addSeconds($risk_advance_seconds)) ->get(); self::deduceOrderPrice($currency_match, $pre_profit_orders); } /** * 按用户群进行风控 * * @param \App\CurrencyMatch $currency_match * @param integer $risk_advance_seconds 风控影响秒数 * @param Illuminate\Support\Carbon $now 当前时间 * @return void */ public static function riskByGroup($currency_match, $risk_advance_seconds, $now, $group_type = 0) { if ($group_type == 1 && $currency_match->risk_group_result == 0) { return false; } $need_risk_orders = MicroOrder::where('status', '<>', MicroOrder::STATUS_CLOSED) ->when($currency_match->id > 0, function ($query) use ($currency_match) { $query->where('match_id', $currency_match->id); }) ->where('handled_at', '<=', $now->addSeconds($risk_advance_seconds)) ->get(); if (count($need_risk_orders) <= 0) { return false; } $ids = $need_risk_orders->pluck('id')->all(); $grouped_type_orders = $need_risk_orders->groupBy('type'); $group_sum = []; //计算一下当前时间内未预设盈亏结果的是买涨的多还是买跌的多(按价值,不是按数量哦) $grouped_type_orders->each(function (\Illuminate\Database\Eloquent\Collection $item, $key) use (&$group_sum) { $sum_cost = 0; $sum_cost_with_profit = 0; $item->each(function ($item, $key) use (&$sum_cost, &$sum_cost_with_profit) { $sum_cost = bc_add($sum_cost, $item->cost); $sum_cost_with_profit = bc_add($sum_cost_with_profit, $item->cost_with_profit); }); $group_sum[$key] = [ 'cost' => $sum_cost, 'cost_with_profit' => $sum_cost_with_profit, ]; }); //dump($group_sum); if (count($group_sum) == 1) { $type_keys = array_keys($group_sum); $buy_type_many = reset($type_keys); } else { list( '1' => $rise, '2' => $fall ) = $group_sum; $compare_result = bc_comp($rise['cost_with_profit'], $fall['cost_with_profit']); if ($compare_result == 0) { //两者一样多 $buy_type_many = mt_rand(1, 2); //随机 } elseif ($compare_result == 1) { //买涨多 $buy_type_many = MicroOrder::TYPE_RISE; } elseif ($compare_result == -1) { //买跌多 $buy_type_many = MicroOrder::TYPE_FALL; } } if ($group_type == 0) { $risk_group_result = Setting::getValueByKey('risk_group_result'); } else { $risk_group_result = $currency_match->risk_group_result; } //下单方向多的按群控结果处理 MicroOrder::whereIn('id', $ids) ->where('status', '<>', MicroOrder::STATUS_CLOSED) ->where('type', $buy_type_many) //->where('pre_profit_result', 0) ->update([ 'pre_profit_result' => $risk_group_result ]); //下单方向少的按相反结果处理 MicroOrder::whereIn('id', $ids) ->where('status', '<>', MicroOrder::STATUS_CLOSED) ->where('type', '<>', $buy_type_many) //->where('pre_profit_result', 0) ->update([ 'pre_profit_result' => -$risk_group_result ]); //重新查询处理过预设盈亏的交易 $need_risk_orders = MicroOrder::whereIn('id', $ids) ->where('status', '<>', MicroOrder::STATUS_CLOSED) ->get(); self::deduceOrderPrice($currency_match, $need_risk_orders); } /** * 按金额进行风控 * * @param \App\CurrencyMatch $currency_match * @param integer $risk_advance_seconds 风控影响秒数 * @param Illuminate\Support\Carbon $now 当前时间 * @return void */ public static function riskByMoney($currency_match, $risk_advance_seconds, $now) { $risk_money_profit_probability = Setting::getValueByKey('risk_money_profit_probability', ''); //转换配置 $rules = explode('|', $risk_money_profit_probability); $rules = array_map(function ($item) { list($range, $probability) = explode(':', $item); list($min, $max) = explode('-', $range); $profit_probability = $probability; $loss_probability = 100 - ($probability > 100 ? 100 : $probability); return compact('min', 'max', 'profit_probability', 'loss_probability'); }, $rules); //查询交易 $need_risk_orders = MicroOrder::where('status', '<>', MicroOrder::STATUS_CLOSED) ->when($currency_match->id > 0, function ($query) use ($currency_match) { $query->where('match_id', $currency_match->id); }) ->where('handled_at', '<=', $now->addSeconds($risk_advance_seconds)) ->get(); $need_risk_orders->transform(function ($item, $key) use ($rules) { $item->refresh(); if ($item->pre_profit_result <> 0) { return $item; } //检索当前金额在哪个风控区间内 $current_rule = []; foreach ($rules as $value) { if ( $item->cost >= $value['min'] && ($item->cost < $value['max'] && $value['max'] > 0 || $value['max'] == 0) ) { $current_rule = $value; continue; } } if (empty($current_rule)) { return $item; } $probability_data = [ [ 'pre_profit_result' => 1, 'chance' => $current_rule['profit_probability'], ], [ 'pre_profit_result' => -1, 'chance' => $current_rule['loss_probability'], ] ]; $profit_result = Probability::lotteryRaffle($probability_data); //根据概率决定单子的否盈亏 $item->pre_profit_result = $profit_result['pre_profit_result']; $item->save(); return $item; }); self::deduceOrderPrice($currency_match, $need_risk_orders); } /** * 按概率进行风控 * * @param \App\CurrencyMatch $currency_match * @param integer $risk_advance_seconds 风控影响秒数 * @param Illuminate\Support\Carbon $now 当前时间 * @return void */ public static function riskByProbability($currency_match, $risk_advance_seconds, $now) { //当前盈利概率 $risk_profit_probability = Setting::getValueByKey('risk_profit_probability', 0); $risk_loss_probability = 100 - ($risk_profit_probability > 100 ? 100 : $risk_profit_probability); //查询订单 $need_risk_orders = MicroOrder::where('status', '<>', MicroOrder::STATUS_CLOSED) ->when($currency_match->id > 0, function ($query) use ($currency_match) { $query->where('match_id', $currency_match->id); }) ->where('handled_at', '<=', $now->addSeconds($risk_advance_seconds)) ->get(); if (count($need_risk_orders) <= 0) { return false; } $probability_data = [ [ 'pre_profit_result' => 1, 'chance' => $risk_profit_probability, ], [ 'pre_profit_result' => -1, 'chance' => $risk_loss_probability, ] ]; $need_risk_orders->transform(function ($item, $key) use ($probability_data) { $profit_result = Probability::lotteryRaffle($probability_data); $item->refresh(); //不处理已经风控过的订单 if ($item->pre_profit_result == 0) { $item->pre_profit_result = $profit_result['pre_profit_result']; $item->save(); } return $item; }); self::deduceOrderPrice($currency_match, $need_risk_orders); } /** * 内控检测和处理 * * @param integer $match_id * @return void */ public static function risk($match_id) { try { // echo date('Y-m-d H:i:s ') . '开始风控' . PHP_EOL; $currency_match = CurrencyMatch::find($match_id); if (!$currency_match) { return false; } $currency = Currency::find($currency_match->currency_id); $now = Carbon::now(); $risk_advance_seconds = self::getRiskAdvanceSeconds(); $risk_mode = Setting::getValueByKey('risk_mode', 0); // 0.无,1.点控,2.群控,3.金额,4.单控,5.概率 // echo '当前风控模式:' . $risk_mode . PHP_EOL; switch ($risk_mode) { case 1: self::riskByUser($currency_match, $risk_advance_seconds, $now); break; case 2: self::riskByGroup($currency_match, $risk_advance_seconds, $now); break; case 3: self::riskByMoney($currency_match, $risk_advance_seconds, $now); break; case 4: self::riskByOrders($currency_match, $risk_advance_seconds, $now); break; case 5: self::riskByGroup($currency_match, $risk_advance_seconds, $now, 1); break; /* case 6: self::riskByProbability($currency_match, $risk_advance_seconds, $now); break; */ default: break; } self::riskByProbability($currency_match, $risk_advance_seconds, $now); // echo date('Y-m-d H:i:s ') . '风控完成' . PHP_EOL; } catch (\Throwable $th) { echo '发生异常:' . PHP_EOL; dump($th->getFile() . ','. $th->getLine() . ',' . $th->getMessage()); } } /** * 平仓 * * @param integer $match_id * @return void */ public static function close($match_id) { try { $micro_key = "micro_close".$match_id; //redis key /* if(Redis::get($micro_key)){ Log::info("秒合约 match_id: ".$match_id."正在执行"); return false; } */ Redis::set($micro_key, true); //写入缓存状态 $currency_match = CurrencyMatch::find($match_id); if (!$currency_match) { Redis::set($micro_key, false); Log::info("秒合约平仓,此币不存在,match_id".$match_id); return false; } $opened_orders = self::getNeedCloseOrder($match_id); if (count($opened_orders) <= 0) { Redis::set($micro_key, false); Log::info("秒合约平仓, match_id: ".$match_id." 没有查询到可执行的订单"); return false; } // $currency = Currency::find($currency_match->currency_id); // $quotation = CurrencyQuotation::where('match_id', $match_id)->first(); // if (!$quotation) { // return false; // } self::risk($match_id); $ret = MicroOrder::whereIn('id', $opened_orders->pluck('id')->all()) ->where('status', 1) ->update([ 'status' => 2, ]); $ids = $opened_orders->pluck('id')->all(); //profit_type 1盈利,0平,-1亏损 $closing_oreders = MicroOrder::where('status', MicroOrder::STATUS_CLOSING) ->whereIn('id', $ids) ->get(); // file_put_contents('/www/wwwroot/crypto/public/t1.txt',$match_id."---".json_encode($closing_oreders).PHP_EOL,FILE_APPEND); if(count($closing_oreders)<=0){ Redis::set($micro_key, false); Log::info("秒合约平仓, match_id: ".$match_id."没有查询到正在平仓中的订单"); return false; } $closing_oreders->transform(function (\App\MicroOrder $item, $key) { return $item->append('profit_type'); }); // echo date('Y-m-d H:i:s ') . '+++开始平仓+++' . PHP_EOL; foreach ($closing_oreders as $key => $value) { // 根据盈亏生成相关参数 if ($value->profit_type == 1) { //结算本金和利息 $profit_ratio = bc_div($value->profit_ratio, 100); //旧的赢注释 $capital = $value->number;//旧的赢注释 $fact_profit = bc_mul($capital, $profit_ratio); //旧的赢注释 //$fact_profit = $value->number; 赢 全部赢 $change = bc_add($capital, $fact_profit); $memo = '秒合约订单平仓,盈利结算'; } elseif ($value->profit_type == 0) { //结算本金,利息为0 $capital = $value->number; $fact_profit = 0; $change = $capital; $memo = '秒合约订单平仓结算,平局结算'; } elseif ($value->profit_type == -1) { //本金填补亏损 /* $capital = $value->number;; // $fact_profit = -$value->number; //原本的 $fact_profit = $value->number * ($value->profit_ratio / 100); //新的 $fact_profit = -$fact_profit; //新的 $change = $capital + $fact_profit; */ $capital = 0; $money_new = $value->number; $loss_ratio = bc_div($value->loss_ratio, 100); $fact_profit = -bc_mul($money_new, $loss_ratio); $change = bc_sub($value->number,bc_mul($money_new, $loss_ratio)); // file_put_contents('/www/wwwroot/crypto/public/t1.txt',$value->profit_type."---".$loss_ratio."---".$money_new."--".$fact_profit); $memo = '秒合约订单,亏损结算'; } $value->profit_result = $value->profit_type; $value->status = MicroOrder::STATUS_CLOSED; $value->fact_profits = $fact_profit; $value->complete_at = Carbon::now(); // echo date('Y-m-d H:i:s ') . '===发送平仓通知消息===' . PHP_EOL; SendClosedMicroOrder::dispatch($value)->onQueue('micro_order:closed'); //先推送数据过去 $value->save(); // 查找钱包并结算 $wallet = UsersWallet::where('currency', $value->currency_id) ->where('user_id', $value->user_id) ->first(); // 判断是否保险订单 if($value->is_insurance){ $currency_id = $value->currency_id; $user_id = $value->user_id; $user_insurance = UsersInsurance::where('user_id', $user_id) ->whereHas('insurance_type', function ($query) use ($currency_id) { $query->where('currency_id', $currency_id); }) ->where('status', 1) ->where('claim_status', 0) ->first(); //如果是保险订单,并且该用户当前没有生效保险 if(!$user_insurance){ $change = 0; $memo = '秒合约订单平仓结算,无生效保险,资金不变'; } $balance_type = 5; }else{ $balance_type = 4; } Log::info(" match_id:".$match_id."秒合约结算,此次操作条数:".count($closing_oreders)); Log::info("【user_id】:".$value->user_id." 订单号:".$value->id); change_wallet_balance($wallet, $balance_type, $change, AccountLog::MICRO_TRADE_CLOSE_SETTLE, $memo, false, 0, 0, '订单号'.$value->id, true); //如果是保险仓交易 if ($value->is_insurance) { $insurance_if_end = self::checkInsuranceIfEnd($value->user_id, $value->currency_id); if($insurance_if_end === true){ //解约 $rescission_res = self::insuranceRescission($value->user_id, $value->currency_id); if($rescission_res !== true){ throw new \Exception($rescission_res); } } } } Redis::set($micro_key, false); //写入缓存状态 } catch (\Throwable $th) { Redis::set($micro_key, false); //写入缓存状态 Log::info($th->getFile() . ', Line:'. $th->getLine() . ':' . $th->getMessage()); } } /** * 取需要平仓的交易 * * @param integer $match_id * @return \Illuminate\Database\Eloquent\Collection */ public static function getNeedCloseOrder($match_id = 0) { $now = Carbon::now(); //待平仓的任务,按交易对进行分组 $lists = MicroOrder::where('status', 1) ->when($match_id > 0, function ($query) use ($match_id) { $query->where('match_id', $match_id); })->where('handled_at', '<=', $now) ->get(); return $lists; } /** * 检查保险是否爆仓 */ public static function checkInsuranceIfEnd($user_id, $currency_id){ $user_insurance = UsersInsurance::where('user_id', $user_id) ->whereHas('insurance_type', function ($query) use ($currency_id) { $query->where('currency_id', $currency_id); }) ->where('status', 1) ->where('claim_status', 0) ->first(); if(!$user_insurance){ return false; } //保险类型 $insurance_type = $user_insurance->insurance_type; //用户钱包 $user_wallet = UsersWallet::where('user_id', $user_id) ->where('currency', $insurance_type->currency_id) ->first(); //爆仓盈利条件 $rescission_profit = bc_mul($user_insurance->amount, 1 + bc_div($insurance_type->profit_termination_condition, 100), 2); //达到条件,为真 if($user_wallet->insurance_balance >= $rescission_profit){ return true; }else{ return false; } } /** * 保险解约 */ public static function insuranceRescission($user_id, $currency_id, $auto = 0) { $user_insurance = UsersInsurance::where('user_id', $user_id) ->whereHas('insurance_type', function ($query) use ($currency_id) { $query->where('currency_id', $currency_id); }) ->where('status', 1) ->where('claim_status', 0) ->first(); if(!$user_insurance){ return "找不到该保险"; } //保险类型 $insurance_type = $user_insurance->insurance_type; //用户钱包 $user_wallet = UsersWallet::where('user_id', $user_id) ->where('currency', $insurance_type->currency_id) ->first(); //爆仓盈利条件 $rescission_profit = bc_mul($user_insurance->amount, 1 + bc_div($insurance_type->profit_termination_condition, 100), 2); try { DB::beginTransaction(); //将用户的保险状态改变 $user_insurance->status = 0; $user_insurance->rescinded_at = \Carbon\Carbon::now()->toDateTimeString(); $user_insurance->rescinded_type = $auto;//解约类型 $user_insurance->save(); //将平仓额度给予用户 change_wallet_balance($user_wallet, 4, $rescission_profit, AccountLog::INSURANCE_RESCISSION_ADD, '保险解约,赔付金额'); //扣除用户钱包保险金额 change_wallet_balance($user_wallet, 5, -$user_wallet->insurance_balance, AccountLog::INSURANCE_RESCISSION1, '保险解约,扣除受保金额', false); change_wallet_balance($user_wallet, 5, -$user_wallet->lock_insurance_balance, AccountLog::INSURANCE_RESCISSION2, '保险解约,扣除保险金额', true); DB::commit(); return true; } catch (\Exception $e) { DB::rollBack(); return "解约失败:".$e->getMessage(); } } }