作者 karlet

feat:增加增量盘口更新

@@ -6,6 +6,7 @@ require_once __DIR__ . '/../jytools/BinanceFutures.php'; @@ -6,6 +6,7 @@ require_once __DIR__ . '/../jytools/BinanceFutures.php';
6 6
7 use trader\struct\ApiInfo; 7 use trader\struct\ApiInfo;
8 use trader\CmBroker; 8 use trader\CmBroker;
  9 +use function jytools\output;
9 10
10 // $key = "gfqf3key8Ywq4NkdgXl9P7eZAfH2mxNLfLAiik9xjRQ64fWitkMeOrC0HNEk5VC3"; 11 // $key = "gfqf3key8Ywq4NkdgXl9P7eZAfH2mxNLfLAiik9xjRQ64fWitkMeOrC0HNEk5VC3";
11 // $secret = "W0WN7WeFINJpHi7BJam6xxeNquKkcrZCiPdrr4I6PZuYGiWXDomPbmgFmGINevSB"; 12 // $secret = "W0WN7WeFINJpHi7BJam6xxeNquKkcrZCiPdrr4I6PZuYGiWXDomPbmgFmGINevSB";
@@ -14,14 +15,20 @@ $secret = "rX9PVXaX2bEqKycsPsuk3e5dAbUk8Psvd6tYKzYHTbZIBimOJxWqrSjQOaS2eqLP"; @@ -14,14 +15,20 @@ $secret = "rX9PVXaX2bEqKycsPsuk3e5dAbUk8Psvd6tYKzYHTbZIBimOJxWqrSjQOaS2eqLP";
14 $apiInfo = new ApiInfo($key, $secret, ""); 15 $apiInfo = new ApiInfo($key, $secret, "");
15 // $wsHost = "ws://bnws.keetu.com"; 16 // $wsHost = "ws://bnws.keetu.com";
16 // $restHost = "http://bnapi.keetu.com"; 17 // $restHost = "http://bnapi.keetu.com";
17 -$wsHost = "bnws.a.indigo888.com";  
18 -$restHost = "bnfapi.a.indigo888.com";  
19 -$broker = new CmBroker(CmBroker::PLAT_BINANCE, $apiInfo, $wsHost, $restHost); 18 +$wsHost = "ws://bnws.a.indigo888.com";
  19 +$restHost = "http://bnfapi.a.indigo888.com";
  20 +$broker = new CmBroker(CmBroker::PLAT_BINANCE, $apiInfo, "", "");
20 // $broker->accListen(function ($data) { 21 // $broker->accListen(function ($data) {
21 // // var_dump($data); 22 // // var_dump($data);
22 // }); 23 // });
23 24
24 -$broker->getLevers(); 25 +// $broker->getLevers();
  26 +$broker->subDepth('ADAUSDT', function ($data) {
  27 + // var_dump($data);
  28 + output("asks len:", count($data['asks']));
  29 + output("bids len:", count($data['bids']));
  30 + echo "-----" . PHP_EOL;
  31 +});
25 32
26 33
27 // use jytools\BinanceFutures; 34 // use jytools\BinanceFutures;
@@ -838,4 +838,8 @@ class CmBroker @@ -838,4 +838,8 @@ class CmBroker
838 } 838 }
839 return []; 839 return [];
840 } 840 }
  841 + public function subDepth($symbol, callable $onData)
  842 + {
  843 + $this->exBroker->subDepth($symbol, $onData);
  844 + }
841 } 845 }
@@ -44,6 +44,13 @@ class Api @@ -44,6 +44,13 @@ class Api
44 $method = "GET"; 44 $method = "GET";
45 return $this->request($method, $url, $params); 45 return $this->request($method, $url, $params);
46 } 46 }
  47 + //获取深度
  48 + public function depth($params)
  49 + {
  50 + $url = "/fapi/v1/depth";
  51 + $method = "GET";
  52 + return $this->request($method, $url, $params);
  53 + }
47 54
48 //-------private interface ------------ 55 //-------private interface ------------
49 //获取用户监听key 56 //获取用户监听key
@@ -10,6 +10,9 @@ require_once __DIR__ . '/../../../jytools/func.php'; @@ -10,6 +10,9 @@ require_once __DIR__ . '/../../../jytools/func.php';
10 use trader\struct\ApiInfo; 10 use trader\struct\ApiInfo;
11 use trader\exchange\binance\Api as BnApi; 11 use trader\exchange\binance\Api as BnApi;
12 use jytools\Websocket; 12 use jytools\Websocket;
  13 +use Swoole\Coroutine;
  14 +
  15 +use function jytools\getMicrotime;
13 use function jytools\output; 16 use function jytools\output;
14 17
15 class ExBroker 18 class ExBroker
@@ -20,6 +23,15 @@ class ExBroker @@ -20,6 +23,15 @@ class ExBroker
20 private BnApi $api; 23 private BnApi $api;
21 private ?Websocket $wsAcc; 24 private ?Websocket $wsAcc;
22 private ?Websocket $wsKline; 25 private ?Websocket $wsKline;
  26 + private ?Websocket $wsDepth;
  27 + private array $depthData = [
  28 + 'lid' => 0, //lastUpdateId
  29 + 'bids' => [],
  30 + 'asks' => [],
  31 + 'uts' => 0, //updateTime
  32 + ];
  33 + private array $depthCache = [];
  34 + private bool $gettingDepth = false;
23 35
24 public function __construct(?ApiInfo $apiInfo) 36 public function __construct(?ApiInfo $apiInfo)
25 { 37 {
@@ -181,4 +193,92 @@ class ExBroker @@ -181,4 +193,92 @@ class ExBroker
181 $res = $this->api->klines($params); 193 $res = $this->api->klines($params);
182 return $res; 194 return $res;
183 } 195 }
  196 + public function subDepth($symbol, callable $onData)
  197 + {
  198 + var_dump($this->host . $this->path);
  199 + $this->wsDepth = new Websocket($this->host . $this->path);
  200 + $this->wsDepth->connect(
  201 + $onOpen = function () use ($symbol) {
  202 + $symbol = strtolower($symbol);
  203 + $subData = json_encode(['method' => 'SUBSCRIBE', 'params' => [$symbol . '@depth@100ms'], 'id' => 1]);
  204 + $this->wsDepth->push($subData);
  205 + },
  206 + $onMessage = function ($data) use ($onData) {
  207 + $data = json_decode($data, true);
  208 + if (!$data || !isset($data['data'])) {
  209 + return;
  210 + }
  211 + $startTs = getMicrotime();
  212 + $this->updateDepthData($data['data']);
  213 + $endTs = getMicrotime();
  214 + $cost = $endTs - $startTs;
  215 + output($data['data']['s'] . ' depth update cost(ms):' . $cost);
  216 + $onData($this->depthData);
  217 + },
  218 + $onClose = null,
  219 + );
  220 + }
  221 + private function updateDepthData($data)
  222 + {
  223 + if ($this->depthData['lid'] == 0 && !$this->gettingDepth) {
  224 + Coroutine::create(function () use ($data) {
  225 + $this->gettingDepth = true;
  226 + $data = $this->api->depth(['symbol' => $data['s'], 'limit' => 1000]);
  227 + if ($data) {
  228 + $this->depthData['lid'] = $data['lastUpdateId'];
  229 + $this->depthData['bids'] = $this->formatDepthData($data['bids']);
  230 + $this->depthData['asks'] = $this->formatDepthData($data['asks']);
  231 + $this->depthData['uts'] = $data['T'];
  232 + }
  233 + $this->gettingDepth = false;
  234 + });
  235 + }
  236 +
  237 + if ($this->depthData['lid'] == 0) {
  238 + $this->depthCache[] = $data;
  239 + while (count($this->depthCache) > 20) {
  240 + array_shift($this->depthCache);
  241 + }
  242 + } else {
  243 + if (count($this->depthCache) != 0) {
  244 + foreach ($this->depthCache as $v) {
  245 + if ($v['pu'] == $this->depthData['lid'] || $v['T'] > $this->depthData['uts']) {
  246 + $this->addDepthData($v);
  247 + }
  248 + }
  249 + $this->depthCache = [];
  250 + }
  251 + $this->addDepthData($data);
  252 + }
  253 + }
  254 + private function formatDepthData($data)
  255 + {
  256 + $newData = [];
  257 + foreach ($data as $item) {
  258 + $price = ($item[0]);
  259 + $qty = ($item[1]);
  260 + $newData[$price] = $qty;
  261 + }
  262 + return $newData;
  263 + }
  264 + private function addDepthData($data)
  265 + {
  266 + $data['a'] = $this->formatDepthData($data['a']);
  267 + $data['b'] = $this->formatDepthData($data['b']);
  268 + $this->depthData['asks'] = array_merge($this->depthData['asks'], $data['a']);
  269 + $this->depthData['bids'] = array_merge($this->depthData['bids'], $data['b']);
  270 + //保留值不为0的数据
  271 + $this->depthData['asks'] = array_filter($this->depthData['asks'], function ($v) {
  272 + return floatval($v) != 0;
  273 + });
  274 + $this->depthData['bids'] = array_filter($this->depthData['bids'], function ($v) {
  275 + return floatval($v) != 0;
  276 + });
  277 + //从大到小排序
  278 + krsort($this->depthData['asks']);
  279 + //从小到大排序
  280 + ksort($this->depthData['bids']);
  281 + $this->depthData['lid'] = $data['u'];
  282 + $this->depthData['uts'] = $data['T'];
  283 + }
184 } 284 }