作者 karlet

feat:盘口订阅

  1 +<?php
  2 +
  3 +require_once __DIR__ . '/../trader/CmBroker.php';
  4 +require_once __DIR__ . '/../trader/struct/ApiInfo.php';
  5 +require_once __DIR__ . '/../jytools/BinanceFutures.php';
  6 +
  7 +use trader\struct\ApiInfo;
  8 +use trader\CmBroker;
  9 +use function jytools\output;
  10 +
  11 +$key = "b34ae137-a085-4ec9-a7c7-d10283da9455";
  12 +$secret = "1896634401D28262A05BF538608D44E0";
  13 +$passphrase = "!@Name4tst";
  14 +$apiInfo = new ApiInfo($key, $secret, $passphrase);
  15 +
  16 +$wsHost = "ws://okws.a.indigo888.com";
  17 +$restHost = "http://okapi.a.indigo888.com";
  18 +$broker = new CmBroker(CmBroker::PLAT_OKX, $apiInfo, $wsHost, $restHost);
  19 +
  20 +$broker->subDepth('ADAUSDT', function ($data) {
  21 + // var_dump($data);
  22 + output("asks len:", count($data['asks']));
  23 + output("bids len:", count($data['bids']));
  24 + echo "-----" . PHP_EOL;
  25 +});
@@ -862,7 +862,7 @@ class CmBroker @@ -862,7 +862,7 @@ class CmBroker
862 } 862 }
863 public function subDepth($symbol, callable $onData) 863 public function subDepth($symbol, callable $onData)
864 { 864 {
865 - $this->exBroker->subDepth($symbol, $onData); 865 + $this->exBroker->subDepth($this->getSymbolOri($symbol), $onData);
866 } 866 }
867 public function getIndexTickers() 867 public function getIndexTickers()
868 { 868 {
@@ -11,6 +11,7 @@ use trader\struct\ApiInfo; @@ -11,6 +11,7 @@ use trader\struct\ApiInfo;
11 use trader\exchange\okx\Api as OkxApi; 11 use trader\exchange\okx\Api as OkxApi;
12 use jytools\Websocket; 12 use jytools\Websocket;
13 use function jytools\output; 13 use function jytools\output;
  14 +use function jytools\getMicrotime;
14 15
15 16
16 class ExBroker 17 class ExBroker
@@ -23,8 +24,15 @@ class ExBroker @@ -23,8 +24,15 @@ class ExBroker
23 private OkxApi $api; 24 private OkxApi $api;
24 private ?Websocket $wsAcc; 25 private ?Websocket $wsAcc;
25 private ?Websocket $wsKline; 26 private ?Websocket $wsKline;
  27 + private ?Websocket $wsDepth;
26 private $timerAccPing = 0; 28 private $timerAccPing = 0;
27 private $timerKlinePing = 0; 29 private $timerKlinePing = 0;
  30 + private array $depthData = [
  31 + 'lid' => 0, //lastUpdateId
  32 + 'bids' => [],
  33 + 'asks' => [],
  34 + 'uts' => 0, //updateTime
  35 + ];
28 36
29 public function __construct(?ApiInfo $apiInfo) 37 public function __construct(?ApiInfo $apiInfo)
30 { 38 {
@@ -429,4 +437,74 @@ class ExBroker @@ -429,4 +437,74 @@ class ExBroker
429 $res = $this->api->indexTickers($param); 437 $res = $this->api->indexTickers($param);
430 return $res; 438 return $res;
431 } 439 }
  440 + public function subDepth($symbol, callable $onData)
  441 + {
  442 + $this->wsDepth = new Websocket($this->host . $this->pathPublic);
  443 + $this->wsDepth->connect(
  444 + $onOpen = function () use ($symbol) {
  445 + $subData = json_encode(["op" => "subscribe", "args" => [['channel' => 'books', 'instId' => $symbol]]]);
  446 + $this->wsDepth->push($subData);
  447 + },
  448 + $onMessage = function ($data) use ($onData) {
  449 + // var_dump($data);
  450 + $data = json_decode($data, true);
  451 + if (!$data || !isset($data['data'])) {
  452 + return;
  453 + }
  454 + if ($data['action'] == 'snapshot') {
  455 + $this->udpateDepthSnapshot($data['data'][0]);
  456 + }
  457 + if ($data['action'] == 'update') {
  458 + $this->addDepthData($data['data'][0]);
  459 + }
  460 + $onData($this->depthData);
  461 + },
  462 + $onClose = null,
  463 + );
  464 + }
  465 + function udpateDepthSnapshot($data)
  466 + {
  467 + // $this->depthData = $data;
  468 + $this->depthData['lid'] = $data['seqId'];
  469 + $this->depthData['bids'] = $this->formatDepthData($data['bids'], 'bids');
  470 + $this->depthData['asks'] = $this->formatDepthData($data['asks'], 'asks');
  471 + $this->depthData['uts'] = $data['ts'];
  472 + }
  473 + private function formatDepthData($data, $type)
  474 + {
  475 + $newData = [];
  476 + foreach ($data as $item) {
  477 + $price = ($item[0]);
  478 + $qty = ($item[1]);
  479 + $newData[$price] = $qty;
  480 + }
  481 + if ($type == 'asks') {
  482 + //从小到大排序
  483 + ksort($newData);
  484 + } else {
  485 + //从大到小排序
  486 + krsort($newData);
  487 + }
  488 + return $newData;
  489 + }
  490 + private function addDepthData($data)
  491 + {
  492 + $data['a'] = $this->formatDepthData($data['asks'], 'asks');
  493 + $data['b'] = $this->formatDepthData($data['bids'], 'bids');
  494 + $this->depthData['asks'] = array_merge($this->depthData['asks'], $data['a']);
  495 + $this->depthData['bids'] = array_merge($this->depthData['bids'], $data['b']);
  496 + //保留值不为0的数据
  497 + $this->depthData['asks'] = array_filter($this->depthData['asks'], function ($v) {
  498 + return floatval($v) != 0;
  499 + });
  500 + $this->depthData['bids'] = array_filter($this->depthData['bids'], function ($v) {
  501 + return floatval($v) != 0;
  502 + });
  503 + //从小到大排序
  504 + ksort($this->depthData['asks']);
  505 + //从大到小排序
  506 + krsort($this->depthData['bids']);
  507 + $this->depthData['lid'] = $data['seqId'];
  508 + $this->depthData['uts'] = $data['ts'];
  509 + }
432 } 510 }