作者 karlet

feat:增加增量盘口更新

... ... @@ -6,6 +6,7 @@ require_once __DIR__ . '/../jytools/BinanceFutures.php';
use trader\struct\ApiInfo;
use trader\CmBroker;
use function jytools\output;
// $key = "gfqf3key8Ywq4NkdgXl9P7eZAfH2mxNLfLAiik9xjRQ64fWitkMeOrC0HNEk5VC3";
// $secret = "W0WN7WeFINJpHi7BJam6xxeNquKkcrZCiPdrr4I6PZuYGiWXDomPbmgFmGINevSB";
... ... @@ -14,14 +15,20 @@ $secret = "rX9PVXaX2bEqKycsPsuk3e5dAbUk8Psvd6tYKzYHTbZIBimOJxWqrSjQOaS2eqLP";
$apiInfo = new ApiInfo($key, $secret, "");
// $wsHost = "ws://bnws.keetu.com";
// $restHost = "http://bnapi.keetu.com";
$wsHost = "bnws.a.indigo888.com";
$restHost = "bnfapi.a.indigo888.com";
$broker = new CmBroker(CmBroker::PLAT_BINANCE, $apiInfo, $wsHost, $restHost);
$wsHost = "ws://bnws.a.indigo888.com";
$restHost = "http://bnfapi.a.indigo888.com";
$broker = new CmBroker(CmBroker::PLAT_BINANCE, $apiInfo, "", "");
// $broker->accListen(function ($data) {
// // var_dump($data);
// });
$broker->getLevers();
// $broker->getLevers();
$broker->subDepth('ADAUSDT', function ($data) {
// var_dump($data);
output("asks len:", count($data['asks']));
output("bids len:", count($data['bids']));
echo "-----" . PHP_EOL;
});
// use jytools\BinanceFutures;
... ...
... ... @@ -838,4 +838,8 @@ class CmBroker
}
return [];
}
public function subDepth($symbol, callable $onData)
{
$this->exBroker->subDepth($symbol, $onData);
}
}
... ...
... ... @@ -44,6 +44,13 @@ class Api
$method = "GET";
return $this->request($method, $url, $params);
}
//获取深度
public function depth($params)
{
$url = "/fapi/v1/depth";
$method = "GET";
return $this->request($method, $url, $params);
}
//-------private interface ------------
//获取用户监听key
... ...
... ... @@ -10,6 +10,9 @@ require_once __DIR__ . '/../../../jytools/func.php';
use trader\struct\ApiInfo;
use trader\exchange\binance\Api as BnApi;
use jytools\Websocket;
use Swoole\Coroutine;
use function jytools\getMicrotime;
use function jytools\output;
class ExBroker
... ... @@ -20,6 +23,15 @@ class ExBroker
private BnApi $api;
private ?Websocket $wsAcc;
private ?Websocket $wsKline;
private ?Websocket $wsDepth;
private array $depthData = [
'lid' => 0, //lastUpdateId
'bids' => [],
'asks' => [],
'uts' => 0, //updateTime
];
private array $depthCache = [];
private bool $gettingDepth = false;
public function __construct(?ApiInfo $apiInfo)
{
... ... @@ -181,4 +193,92 @@ class ExBroker
$res = $this->api->klines($params);
return $res;
}
public function subDepth($symbol, callable $onData)
{
var_dump($this->host . $this->path);
$this->wsDepth = new Websocket($this->host . $this->path);
$this->wsDepth->connect(
$onOpen = function () use ($symbol) {
$symbol = strtolower($symbol);
$subData = json_encode(['method' => 'SUBSCRIBE', 'params' => [$symbol . '@depth@100ms'], 'id' => 1]);
$this->wsDepth->push($subData);
},
$onMessage = function ($data) use ($onData) {
$data = json_decode($data, true);
if (!$data || !isset($data['data'])) {
return;
}
$startTs = getMicrotime();
$this->updateDepthData($data['data']);
$endTs = getMicrotime();
$cost = $endTs - $startTs;
output($data['data']['s'] . ' depth update cost(ms):' . $cost);
$onData($this->depthData);
},
$onClose = null,
);
}
private function updateDepthData($data)
{
if ($this->depthData['lid'] == 0 && !$this->gettingDepth) {
Coroutine::create(function () use ($data) {
$this->gettingDepth = true;
$data = $this->api->depth(['symbol' => $data['s'], 'limit' => 1000]);
if ($data) {
$this->depthData['lid'] = $data['lastUpdateId'];
$this->depthData['bids'] = $this->formatDepthData($data['bids']);
$this->depthData['asks'] = $this->formatDepthData($data['asks']);
$this->depthData['uts'] = $data['T'];
}
$this->gettingDepth = false;
});
}
if ($this->depthData['lid'] == 0) {
$this->depthCache[] = $data;
while (count($this->depthCache) > 20) {
array_shift($this->depthCache);
}
} else {
if (count($this->depthCache) != 0) {
foreach ($this->depthCache as $v) {
if ($v['pu'] == $this->depthData['lid'] || $v['T'] > $this->depthData['uts']) {
$this->addDepthData($v);
}
}
$this->depthCache = [];
}
$this->addDepthData($data);
}
}
private function formatDepthData($data)
{
$newData = [];
foreach ($data as $item) {
$price = ($item[0]);
$qty = ($item[1]);
$newData[$price] = $qty;
}
return $newData;
}
private function addDepthData($data)
{
$data['a'] = $this->formatDepthData($data['a']);
$data['b'] = $this->formatDepthData($data['b']);
$this->depthData['asks'] = array_merge($this->depthData['asks'], $data['a']);
$this->depthData['bids'] = array_merge($this->depthData['bids'], $data['b']);
//保留值不为0的数据
$this->depthData['asks'] = array_filter($this->depthData['asks'], function ($v) {
return floatval($v) != 0;
});
$this->depthData['bids'] = array_filter($this->depthData['bids'], function ($v) {
return floatval($v) != 0;
});
//从大到小排序
krsort($this->depthData['asks']);
//从小到大排序
ksort($this->depthData['bids']);
$this->depthData['lid'] = $data['u'];
$this->depthData['uts'] = $data['T'];
}
}
... ...