count = 1; $worker->onWorkerStart = function ($worker) { // 每2.5秒执行一次 $time_interval = 2; Timer::add($time_interval, function () { echo "task 1min run\n"; //$day_kline = Cache::store('redis')->get('swap:' . 'BTC' . '_kline_' . '1min'); //$day_kline = Cache::store('redis')->get('swap:BTC_kline_1min'); //所有交易对 // $symbols = \App\Models\ContractPair::query()->where('status', 1)->pluck('symbol'); // // foreach ($symbols as $symbol) { // // Kline数据 // if ($symbol != "CKL" || $symbol != "NYI" || $symbol != "GFTL" || $symbol != "HNA" || $symbol != "PVR") { // $subaa = 'swap:' . $symbol . '_kline_' . '1min'; // $sendsub = 'swapKline_' . $symbol . '_1min'; // //echo $sendsub; // $min_kline = Cache::store('redis')->get($subaa); // $zhangdie = mt_rand(1000, 3000); // if ($zhangdie >= 2000) { // $min_kline['close'] += sprintf("%.3f", ($min_kline['close'] * (mt_rand(1000, 1050) / 10000000))); // } else { // $min_kline['close'] -= sprintf("%.3f", ($min_kline['close'] * (mt_rand(1000, 1050) / 10000000))); // } // \App\Jobs\TriggerStrategy::dispatch(['symbol' => $symbol, 'realtime_price' => $min_kline['close']])->onQueue('triggerStrategy'); // //var_dump($min_kline); // // Done 所有k先历史数据为GMT -4 // // $min_kline['time'] = $min_kline['time'] - 43200; // Gateway::sendToGroup($sendsub, json_encode(['code' => 0, 'msg' => 'success', 'data' => $min_kline, 'sub' => $sendsub, 'type' => 'dynamic'])); // // } // } //var_dump($day_kline); //$aa = "swapKline_BTC_1min"; //Gateway::sendToGroup($group_id2, json_encode(['code'=>0,'msg'=>'success','data'=>11111,'sub'=>$aa,'type'=>'dynamic'])); }); Gateway::$registerAddress = '127.0.0.1:1238'; // $con = new AsyncTcpConnection('ws://api.btcgateway.pro/swap-ws'); // $con = new AsyncTcpConnection('ws://api.btcgateway.pro/linear-swap-ws'); // $con = new AsyncTcpConnection('ws://fstream.binance.com/ws/btcusdt@kline_1m'); $con = new AsyncTcpConnection('ws://fstream.binance.com:443/ws'); // 设置以ssl加密方式访问,使之成为wss $con->transport = 'ssl'; $con->onConnect = function ($con) { //所有交易对 // $symbols = \App\Models\ContractPair::query()->where('status', 1)->pluck('symbol'); // todo: 修改获取当前行情配置 3m-5m-15m-30m-1h-2h-4h-6h-8h-12h-1d-3d-1w-1M $period = '1m'; $seconds = 60; //60 300 900 1800 3600 86400 604800 2592000 $symbols = \App\Models\ContractPair::query()->where('status', 1)->pluck('symbol'); foreach ($symbols as $symbol) { $symbol = strtolower($symbol); $symbol_list[] = $symbol . "usdt@kline_" . $period; } $msg1 = ["method" => "SUBSCRIBE", "params" => $symbol_list, "id" => intval(rand(100000, 999999) . time())]; $send = json_encode($msg1); // echo $send; $con->send($send); }; $con->onMessage = function ($con, $data) { // echo $data; // $data = json_decode(gzdecode($data), true); $data = json_decode($data, true); if (isset($data['ping'])) { $msg = ["pong" => $data['ping']]; $con->send(json_encode($msg)); } else { if (isset($data['s'])) { $ch = $data['s']; $symbol = str_before($ch, 'USDT'); // if ($ch) { if ($ch) { // todo: 修改获取当前行情配置 $period = '1min'; //1min 5min 15min 30min 60min 1day 1week 1mon $now = $data['k']; $kklinekey = 'swap:' . $symbol . '_kline_' . $period; $oneminopen = json_decode(Redis::get($kklinekey), true); if($oneminopen['last_now'] == strtotime(date("Y-m-d H:i:00", time()))){ $now['o'] = $oneminopen['open']; } if($ch == 'BTCUSDT'){ // var_dump($data); } $now['t']=substr($now['t'],0,10); // echo json_encode($cache_data) . "\r\n"; $cache_data = [ "id" => $now['t']*1, "open" => $now['o']*1, "close" => $now['c']*1, "low" => $now['l']*1, "high" => $now['h']*1, "amount" => $now['V']*1, 'vol' => $now['V']*1000, 'trade_turnover' => $now['Q']*1, 'count' => round($now['V']*100,0), ]; // echo json_encode($cache_data) . "\r\n"; // $cache_data['time'] = time(); $kline_book_key = 'swap:' . $symbol . '_kline_book_' . $period; $kline_book = Cache::store('redis')->get($kline_book_key); // 获取风控任务 $risk_key = 'fkJson:' . $symbol . '/USDT'; //echo $risk_key; $risk = json_decode(Redis::get($risk_key), true); $minUnit = $risk['minUnit'] ?? 0; $count = $risk['count'] ?? 0; $enabled = $risk['enabled'] ?? 0; $seconds = 60; if (!blank($risk) && $enabled == 1) { // 修改价格 $change = $minUnit * $count; $cache_data['close'] = PriceCalculate($cache_data['close'], '+', $change, 8); $cache_data['high'] = PriceCalculate($cache_data['high'], '+', $change, 8); $cache_data['low'] = PriceCalculate($cache_data['low'], '+', $change, 8); // 当前一分钟 开盘对接 if((time()-$risk['now_time'])<=61){ if($risk['count'] != $risk['back_count']){ $back_count = $risk['back_count'] ?? 0; $change_open = $minUnit * $back_count; $cache_data['open'] = PriceCalculate($cache_data['open'], '+', $change_open, 8); } }else{ // $back_count = $risk['back_count'] ?? 0; // $change_open = $minUnit * $back_count; // $cache_data['open'] = PriceCalculate($cache_data['open'], '+', $change_open, 8); // if($risk['count'] != $risk['back_count']){ $cache_data['open'] = PriceCalculate($cache_data['open'], '+', $change, 8); // } } } if (!blank($risk) && $enabled == 0 && (time()-$risk['now_time'])<=61) { $change = $minUnit * $count; $cache_data['open'] = PriceCalculate($cache_data['open'] ,'+', $change,8); } // var_dump($cache_data); // echo(date("Y-m-d H:i:s",$kline_book['id'])). "\r\n"; // echo $kline_book['id']; if ($period == '1min') { // 1分钟基线 if (!blank($kline_book)) { $prev_id = $cache_data['id'] - $seconds; $prev_item = array_last($kline_book, function ($value, $key) use ($prev_id) { return $value['id'] == $prev_id; }); // $cache_data['open'] = $prev_item['close']; } // echo json_encode($cache_data) . "\r\n"; if (blank($kline_book)) { Cache::store('redis')->put($kline_book_key, [$cache_data]); } else { $last_item1 = array_pop($kline_book); if ($last_item1['id'] == $cache_data['id']) { array_push($kline_book, $cache_data); } else { array_push($kline_book, $last_item1, $cache_data); } if (count($kline_book) > 3000) { array_shift($kline_book); } Cache::store('redis')->put($kline_book_key, $kline_book); } } else { // 其他长周期K线都以前一周期作为参考 比如5minK线以1min为基础 $periodMap = [ '5min' => ['period' => '1min', 'seconds' => 60], '15min' => ['period' => '5min', 'seconds' => 300], '30min' => ['period' => '5min', 'seconds' => 300], '60min' => ['period' => '5min', 'seconds' => 300], '1day' => ['period' => '60min', 'seconds' => 3600], '1week' => ['period' => '1day', 'seconds' => 86400], '1mon' => ['period' => '1day', 'seconds' => 86400], ]; $map = $periodMap[$period] ?? null; $kline_base_book = Cache::store('redis')->get('swap:' . $symbol . '_kline_book_' . $map['period']); if (!blank($kline_base_book)) { // 以5min周期为例 这里一次性取出1min周期前后10个 $first_item_id = $cache_data['id']; $last_item_id = $cache_data['id'] + $seconds - $map['seconds']; $items1 = array_where($kline_base_book, function ($value, $key) use ($first_item_id, $last_item_id) { return $value['id'] >= $first_item_id && $value['id'] <= $last_item_id; }); if (!blank($items1)) { $cache_data['open'] = array_first($items1)['open'] ?? $cache_data['open']; $cache_data['close'] = array_last($items1)['close'] ?? $cache_data['close']; $cache_data['high'] = max(array_pluck($items1, 'high')) ?? $cache_data['high']; $cache_data['low'] = min(array_pluck($items1, 'low')) ?? $cache_data['low']; } if (blank($kline_book)) { Cache::store('redis')->put($kline_book_key, [$cache_data]); } else { $last_item1 = array_pop($kline_book); if ($last_item1['id'] == $cache_data['id']) { array_push($kline_book, $cache_data); } else { $update_last_item1 = $last_item1; // 有新的周期K线生成 此时尝试更新$last_item1 $first_item_id2 = $cache_data['id'] - $seconds; $last_item_id2 = $cache_data['id'] - $map['seconds']; $items2 = array_where($kline_base_book, function ($value, $key) use ($first_item_id2, $last_item_id2) { return $value['id'] >= $first_item_id2 && $value['id'] <= $last_item_id2; }); if (!blank($items2)) { $update_last_item1['open'] = array_first($items2)['open'] ?? $update_last_item1['open']; $update_last_item1['close'] = array_last($items2)['close'] ?? $update_last_item1['close']; $update_last_item1['high'] = max(array_pluck($items2, 'high')) ?? $update_last_item1['high']; $update_last_item1['low'] = min(array_pluck($items2, 'low')) ?? $update_last_item1['low']; } array_push($kline_book, $update_last_item1, $cache_data); } if (count($kline_book) > 3000) { array_shift($kline_book); } Cache::store('redis')->put($kline_book_key, $kline_book); } } } Cache::store('redis')->put('swap:' . $symbol . '_kline_' . $period, $cache_data); $group_id2 = 'swapKline_' . $symbol . '_' . $period; //var_dump($group_id2); //echo Gateway::getClientIdCountByGroup($group_id2); if (Gateway::getClientIdCountByGroup($group_id2) > 0) { // $cache_data['time'] = $cache_data['time'] - 43200; Gateway::sendToGroup($group_id2, json_encode(['code' => 0, 'msg' => 'success', 'data' => $cache_data, 'sub' => $group_id2, 'type' => 'dynamic'])); } } } } }; $con->onClose = function ($con) { //这个是延迟断线重连,当服务端那边出现不确定因素,比如宕机,那么相对应的socket客户端这边也链接不上,那么可以吧1改成适当值,则会在多少秒内重新,我也是1,也就是断线1秒重新链接 $con->reConnect(1); }; $con->onError = function ($con, $code, $msg) { echo "error $code $msg\n"; }; $con->connect(); }; Worker::runAll();