作者 karlet

feat:bitget初步完成

  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 +require_once __DIR__ . '/../jytools/func.php';
  7 +
  8 +use trader\struct\ApiInfo;
  9 +use trader\struct\WsData;
  10 +use trader\CmBroker;
  11 +use function jytools\output;
  12 +
  13 +$key = "bg_21bd365eaecaaa165a6167211785e2c0";
  14 +$secret = "d850a0b1e344157d91b0d2585805e3c8d92f0f61d867a11aaf2569f3a8587991";
  15 +$passphrase = "Z1345zbnm";
  16 +$apiInfo = new ApiInfo($key, $secret, $passphrase);
  17 +$wsHost = "ws://bgws.keetu.com";
  18 +$restHost = "http://bgapi.keetu.com";
  19 +$broker = new CmBroker(CmBroker::PLAT_BITGET, $apiInfo, $wsHost, $restHost);
  20 +
  21 +output("开始监听");
  22 +// $broker->accListen(function (WsData $data) {
  23 +// if ($data->dataType == "order") {
  24 +// var_dump($data);
  25 +// }
  26 +// });
  27 +$broker->setLever("BTCUSDT", 20);
  28 +// $broker->klineListen("BTCUSDT", "1m", function ($data) {
  29 +// output($data->toArray());
  30 +// });
@@ -6,6 +6,7 @@ require_once __DIR__ . '/struct/ApiInfo.php'; @@ -6,6 +6,7 @@ require_once __DIR__ . '/struct/ApiInfo.php';
6 require_once __DIR__ . '/exchange/okx/ExBroker.php'; 6 require_once __DIR__ . '/exchange/okx/ExBroker.php';
7 require_once __DIR__ . '/exchange/binance/ExBroker.php'; 7 require_once __DIR__ . '/exchange/binance/ExBroker.php';
8 require_once __DIR__ . '/exchange/bybit/ExBroker.php'; 8 require_once __DIR__ . '/exchange/bybit/ExBroker.php';
  9 +require_once __DIR__ . '/exchange/bitget/ExBroker.php';
9 require_once __DIR__ . '/struct/Kline.php'; 10 require_once __DIR__ . '/struct/Kline.php';
10 require_once __DIR__ . '/struct/Order.php'; 11 require_once __DIR__ . '/struct/Order.php';
11 require_once __DIR__ . '/struct/WsData.php'; 12 require_once __DIR__ . '/struct/WsData.php';
@@ -23,6 +24,7 @@ use trader\struct\ApiInfo; @@ -23,6 +24,7 @@ use trader\struct\ApiInfo;
23 use trader\exchange\okx\ExBroker as OkxBroker; 24 use trader\exchange\okx\ExBroker as OkxBroker;
24 use trader\exchange\binance\ExBroker as BinanceBroker; 25 use trader\exchange\binance\ExBroker as BinanceBroker;
25 use trader\exchange\bybit\ExBroker as BybitBroker; 26 use trader\exchange\bybit\ExBroker as BybitBroker;
  27 +use trader\exchange\bitget\ExBroker as BitgetBroker;
26 use trader\struct\Kline; 28 use trader\struct\Kline;
27 use trader\struct\Order; 29 use trader\struct\Order;
28 use trader\struct\WsData; 30 use trader\struct\WsData;
@@ -52,7 +54,7 @@ class CmBroker @@ -52,7 +54,7 @@ class CmBroker
52 * @see PLAT_BITGET 54 * @see PLAT_BITGET
53 */ 55 */
54 public $plat; 56 public $plat;
55 - private OkxBroker|BinanceBroker|BybitBroker $exBroker; 57 + private OkxBroker|BinanceBroker|BybitBroker|BitgetBroker $exBroker;
56 /** @var SymbolInfo[] $symbolInfos */ 58 /** @var SymbolInfo[] $symbolInfos */
57 public $symbolInfos = []; 59 public $symbolInfos = [];
58 /** @var Pos[] $positions */ 60 /** @var Pos[] $positions */
@@ -75,14 +77,16 @@ class CmBroker @@ -75,14 +77,16 @@ class CmBroker
75 if ($plat == self::PLAT_BYBIT) { 77 if ($plat == self::PLAT_BYBIT) {
76 $exBroker = new BybitBroker($apiInfo); 78 $exBroker = new BybitBroker($apiInfo);
77 } 79 }
  80 + if ($plat == self::PLAT_BITGET) {
  81 + $exBroker = new BitgetBroker($apiInfo);
  82 + }
78 $this->exBroker = $exBroker; 83 $this->exBroker = $exBroker;
79 - if ($wsHost) { 84 + if ($wsHost && $wsHost != "") {
80 $this->exBroker->setWsHost($wsHost); 85 $this->exBroker->setWsHost($wsHost);
81 } 86 }
82 - if ($restHost) { 87 + if ($restHost && $restHost != "") {
83 $this->exBroker->setRestHost($restHost); 88 $this->exBroker->setRestHost($restHost);
84 } 89 }
85 - var_dump("初始化。。。。");  
86 $this->init(); 90 $this->init();
87 } 91 }
88 public function setName($name) 92 public function setName($name)
@@ -110,6 +114,9 @@ class CmBroker @@ -110,6 +114,9 @@ class CmBroker
110 if ($this->plat == self::PLAT_BYBIT) { 114 if ($this->plat == self::PLAT_BYBIT) {
111 $this->bybitAccDataHandle($data, $onData); 115 $this->bybitAccDataHandle($data, $onData);
112 } 116 }
  117 + if ($this->plat == self::PLAT_BITGET) {
  118 + $this->bitgetAccDataHandle($data, $onData);
  119 + }
113 }); 120 });
114 } 121 }
115 //处理币安相关账户数据监听 122 //处理币安相关账户数据监听
@@ -248,6 +255,52 @@ class CmBroker @@ -248,6 +255,52 @@ class CmBroker
248 return; 255 return;
249 } 256 }
250 } 257 }
  258 + //处理bitget账户相关数据监听
  259 + private function bitgetAccDataHandle($data, $onData)
  260 + {
  261 + // 处理订单和成交数据
  262 + if (isset($data['arg']) && $data['arg']['channel'] == 'orders') {
  263 + foreach ($data['data'] as $value) {
  264 + // 处理成交数据
  265 + $wsDataTrade = WsDataTrade::TransferBitgetOrder($value, $this->symbolInfos, function ($symbol) {
  266 + return $this->getSymbolSt($symbol);
  267 + });
  268 + if ($wsDataTrade) {
  269 + $wsData = new WsData($this->plat, 'trade', $wsDataTrade);
  270 + $onData($wsData);
  271 + }
  272 +
  273 + // 处理订单数据
  274 + $wsDataOrder = WsDataOrder::TransferBitgetOrder($value, $this->symbolInfos, function ($symbol) {
  275 + return $this->getSymbolSt($symbol);
  276 + });
  277 + if ($wsDataOrder) {
  278 + $wsData = new WsData($this->plat, 'order', null, null, $wsDataOrder);
  279 + $onData($wsData);
  280 + }
  281 + }
  282 + return;
  283 + }
  284 +
  285 + // 处理账户和持仓数据
  286 + if (isset($data['arg']) && $data['arg']['channel'] == 'account') {
  287 + foreach ($data['data'] as $value) {
  288 + if (isset($value['positions'])) {
  289 + foreach ($value['positions'] as $pos) {
  290 + $wsDataPos = WsDataPos::TransferBitgetPos($pos, $this->symbolInfos, function ($symbol) {
  291 + return $this->getSymbolSt($symbol);
  292 + });
  293 + if ($wsDataPos) {
  294 + $this->positions[$wsDataPos->symbol . "_" . $wsDataPos->posSide] = $wsDataPos;
  295 + $wsData = new WsData($this->plat, 'pos', null, $wsDataPos);
  296 + $onData($wsData);
  297 + }
  298 + }
  299 + }
  300 + }
  301 + return;
  302 + }
  303 + }
251 public function klineListen($symbol, $peroid, $onData) 304 public function klineListen($symbol, $peroid, $onData)
252 { 305 {
253 if ($this->plat == self::PLAT_BINANCE && $peroid == '1s') { 306 if ($this->plat == self::PLAT_BINANCE && $peroid == '1s') {
@@ -266,6 +319,9 @@ class CmBroker @@ -266,6 +319,9 @@ class CmBroker
266 if ($this->plat == self::PLAT_BYBIT) { 319 if ($this->plat == self::PLAT_BYBIT) {
267 $kline = Kline::transferBybit($data); 320 $kline = Kline::transferBybit($data);
268 } 321 }
  322 + if ($this->plat == self::PLAT_BITGET) {
  323 + $kline = Kline::transferBitget($data);
  324 + }
269 $onData($kline); 325 $onData($kline);
270 }); 326 });
271 } 327 }
@@ -455,6 +511,19 @@ class CmBroker @@ -455,6 +511,19 @@ class CmBroker
455 } 511 }
456 $this->symbolInfos = $infos; 512 $this->symbolInfos = $infos;
457 } 513 }
  514 + if ($this->plat == self::PLAT_BITGET) {
  515 + $res = $this->exBroker->getSymbolInfos();
  516 + $infos = [];
  517 + foreach ($res as $value) {
  518 + if ($value['quoteCoin'] == 'USDT' && $value['symbolStatus'] == 'normal') {
  519 + $info = SymbolInfo::transferBitget($value, function ($symbol) {
  520 + return $this->getSymbolSt($symbol);
  521 + });
  522 + $infos[$info->symbol] = $info;
  523 + }
  524 + }
  525 + $this->symbolInfos = $infos;
  526 + }
458 if (count($this->symbolInfos) == 0) { 527 if (count($this->symbolInfos) == 0) {
459 $this->initSymbolInfos($count + 1); 528 $this->initSymbolInfos($count + 1);
460 return; 529 return;
@@ -4,6 +4,7 @@ namespace trader\exchange\bitget; @@ -4,6 +4,7 @@ namespace trader\exchange\bitget;
4 4
5 require_once __DIR__ . '/../../struct/ApiInfo.php'; 5 require_once __DIR__ . '/../../struct/ApiInfo.php';
6 require_once __DIR__ . '/../../../jytools/func.php'; 6 require_once __DIR__ . '/../../../jytools/func.php';
  7 +require_once __DIR__ . '/../../../jytools/Curl.php';
7 8
8 use trader\struct\ApiInfo; 9 use trader\struct\ApiInfo;
9 use jytools\Curl; 10 use jytools\Curl;
@@ -11,14 +12,105 @@ use function jytools\getMicrotime; @@ -11,14 +12,105 @@ use function jytools\getMicrotime;
11 12
12 class Api 13 class Api
13 { 14 {
14 - private $host = ''; 15 + private $host = 'https://api.bitget.com';
15 private ApiInfo $apiInfo; 16 private ApiInfo $apiInfo;
  17 +
16 public function __construct(ApiInfo $apiInfo) 18 public function __construct(ApiInfo $apiInfo)
17 { 19 {
18 $this->apiInfo = $apiInfo; 20 $this->apiInfo = $apiInfo;
19 } 21 }
  22 +
20 public function setHost($host) 23 public function setHost($host)
21 { 24 {
22 $this->host = $host; 25 $this->host = $host;
23 } 26 }
  27 +
  28 + //----------- public interface ------------
  29 + // 获取交易对信息
  30 + public function instruments($param)
  31 + {
  32 + $path = '/api/v2/mix/market/contracts';
  33 + $method = 'GET';
  34 + return $this->request($path, $method, $param);
  35 + }
  36 +
  37 + // 获取K线数据
  38 + public function klines($param)
  39 + {
  40 + $path = '/api/v2/spot/market/candles';
  41 + $method = 'GET';
  42 + return $this->request($path, $method, $param);
  43 + }
  44 +
  45 + //----------- private interface ------------
  46 + // 下单
  47 + public function placeOrder($param)
  48 + {
  49 + $path = '/api/v2/spot/trade/place-order';
  50 + $method = 'POST';
  51 + return $this->request($path, $method, $param, true);
  52 + }
  53 +
  54 + // 查询持仓
  55 + public function getPositions($param)
  56 + {
  57 + $path = '/api/v2/mix/position/positions';
  58 + $method = 'GET';
  59 + return $this->request($path, $method, $param, true);
  60 + }
  61 +
  62 + // 设置杠杆
  63 + public function setLeverage($param)
  64 + {
  65 + $path = '/api/v2/mix/account/set-leverage';
  66 + $method = 'POST';
  67 + return $this->request($path, $method, $param, true);
  68 + }
  69 +
  70 + // 查询账户余额
  71 + public function accountBalance($param)
  72 + {
  73 + $path = '/api/v2/spot/account/assets';
  74 + $method = 'GET';
  75 + return $this->request($path, $method, $param, true);
  76 + }
  77 +
  78 + //-------------------------------------
  79 + private function createSign($timestamp, $method, $requestPath, $body = '')
  80 + {
  81 + $message = $timestamp . $method . $requestPath . $body;
  82 + return base64_encode(hash_hmac('sha256', $message, $this->apiInfo->secret, true));
  83 + }
  84 +
  85 + private function request($path, $method, $param, $auth = false)
  86 + {
  87 + $header = [];
  88 + $body = '';
  89 + $fullPath = $path;
  90 +
  91 + if ($method == 'GET' && !empty($param)) {
  92 + $fullPath = $path . '?' . http_build_query($param);
  93 + } else {
  94 + $header[] = 'Content-Type: application/json';
  95 + $body = json_encode($param);
  96 + }
  97 +
  98 + if ($auth) {
  99 + $timestamp = (string)getMicrotime();
  100 + $header[] = 'ACCESS-KEY: ' . $this->apiInfo->key;
  101 + $header[] = 'ACCESS-TIMESTAMP: ' . $timestamp;
  102 + $header[] = 'ACCESS-PASSPHRASE: ' . $this->apiInfo->passphrase;
  103 + $header[] = 'ACCESS-SIGN: ' . $this->createSign($timestamp, $method, $fullPath, $body);
  104 + }
  105 +
  106 + $url = $this->host . $path;
  107 + $result = "";
  108 + if ($method == 'POST') {
  109 + $result = Curl::httpPost($url, $param, $header);
  110 + } else {
  111 + $result = Curl::httpGet($url, $param, $header);
  112 + }
  113 +
  114 + return json_decode($result, true);
  115 + }
24 } 116 }
  1 +<?php
  2 +
  3 +namespace trader\exchange\bitget;
  4 +
  5 +require_once __DIR__ . '/../../struct/ApiInfo.php';
  6 +require_once __DIR__ . '/Api.php';
  7 +require_once __DIR__ . '/../../../jytools/Websocket.php';
  8 +require_once __DIR__ . '/../../../jytools/func.php';
  9 +
  10 +use trader\struct\ApiInfo;
  11 +use trader\exchange\bitget\Api as BgApi;
  12 +use jytools\Websocket;
  13 +use function jytools\output;
  14 +use function jytools\getMicrotime;
  15 +
  16 +class ExBroker
  17 +{
  18 + private $host = 'wss://ws.bitget.com';
  19 + private $pathPri = '/v2/ws/private'; //账户信息path
  20 + private $pathPub = '/v2/ws/public'; //行情信息path
  21 + private ApiInfo $apiInfo;
  22 + private BgApi $api;
  23 + private ?Websocket $wsAcc;
  24 + private ?Websocket $wsKline;
  25 + private $timerAccPing = 0;
  26 + private $timerKlinePing = 0;
  27 +
  28 + public function __construct(ApiInfo $apiInfo)
  29 + {
  30 + $this->apiInfo = $apiInfo;
  31 + $this->api = new BgApi($apiInfo);
  32 + }
  33 +
  34 + public function setWsHost($host)
  35 + {
  36 + $this->host = $host;
  37 + }
  38 +
  39 + public function setRestHost($host)
  40 + {
  41 + $this->api->setHost($host);
  42 + }
  43 +
  44 + public function accListen(callable $onData)
  45 + {
  46 + if (isset($this->wsAcc)) {
  47 + $this->wsAcc->close();
  48 + }
  49 + $this->wsAcc = new Websocket($this->host . $this->pathPri);
  50 + $this->wsAcc->connect(
  51 + function () {
  52 + $this->wsLogin();
  53 + $this->wsAccPing();
  54 + },
  55 + function ($data) use ($onData) {
  56 + $this->onWsDataPre($data, $onData);
  57 + },
  58 + function () {
  59 + swoole_timer_clear($this->timerAccPing);
  60 + }
  61 + );
  62 + }
  63 +
  64 + public function klineListen($symbol, $interval, callable $onData)
  65 + {
  66 + if (isset($this->wsKline)) {
  67 + $this->wsKline->close();
  68 + }
  69 + $this->wsKline = new Websocket($this->host . $this->pathPub);
  70 + $this->wsKline->connect(
  71 + function () use ($symbol, $interval) {
  72 + $this->wsKline->push(json_encode([
  73 + 'op' => 'subscribe',
  74 + 'args' => [
  75 + [
  76 + 'instType' => 'SPOT',
  77 + 'channel' => 'candle' . $interval,
  78 + 'instId' => $symbol
  79 + ]
  80 + ]
  81 + ]));
  82 + $this->wsKlinePing();
  83 + },
  84 + function ($data) use ($onData) {
  85 + $data = json_decode($data, true);
  86 + if (isset($data['data'])) {
  87 + $onData($data);
  88 + }
  89 + },
  90 + function () {
  91 + swoole_timer_clear($this->timerKlinePing);
  92 + }
  93 + );
  94 + }
  95 +
  96 + private function wsKlinePing()
  97 + {
  98 + $this->timerKlinePing = swoole_timer_tick(1000 * 20, function () {
  99 + $this->wsKline->push('ping');
  100 + });
  101 + }
  102 +
  103 + private function wsAccPing()
  104 + {
  105 + $this->timerAccPing = swoole_timer_tick(1000 * 20, function () {
  106 + $this->wsAcc->push('ping');
  107 + });
  108 + }
  109 +
  110 + private function createWsSign($timestamp)
  111 + {
  112 + $message = $timestamp . 'GET' . '/user/verify';
  113 + return base64_encode(hash_hmac('sha256', $message, $this->apiInfo->secret, true));
  114 + }
  115 +
  116 + private function wsLogin()
  117 + {
  118 + $timestamp = (string)(getMicrotime() / 1000);
  119 + $this->wsAcc->push(json_encode([
  120 + 'op' => 'login',
  121 + 'args' => [
  122 + [
  123 + 'apiKey' => $this->apiInfo->key,
  124 + 'passphrase' => $this->apiInfo->passphrase,
  125 + 'timestamp' => $timestamp,
  126 + 'sign' => $this->createWsSign($timestamp)
  127 + ]
  128 + ]
  129 + ]));
  130 + }
  131 +
  132 + private function onWsDataPre($data, callable $onWsData)
  133 + {
  134 + if ($data == 'pong') {
  135 + return;
  136 + }
  137 + $data = json_decode($data, true);
  138 + if (isset($data['event'])) {
  139 + if ($data['event'] == 'login' && $data['code'] == '0') {
  140 + output('ws登录成功');
  141 + $this->wsSubscribe();
  142 + return;
  143 + }
  144 + if ($data['event'] == 'subscribe') {
  145 + return;
  146 + }
  147 + output('bitget ws 未处理数据', $data);
  148 + }
  149 + call_user_func($onWsData, $data);
  150 + }
  151 +
  152 + private function wsSubscribe()
  153 + {
  154 + $this->wsAcc->push(json_encode([
  155 + 'op' => 'subscribe',
  156 + 'args' => [
  157 + [
  158 + 'instType' => 'SPOT',
  159 + 'channel' => 'account',
  160 + 'instId' => 'default'
  161 + ],
  162 + [
  163 + 'instType' => 'SPOT',
  164 + 'channel' => 'orders',
  165 + 'instId' => 'default'
  166 + ]
  167 + ]
  168 + ]));
  169 + }
  170 +
  171 + public function placeOrder(array $params)
  172 + {
  173 + return $this->api->placeOrder($params);
  174 + }
  175 +
  176 + public function setLever($symbol, $lever)
  177 + {
  178 + $res = $this->api->setLeverage([
  179 + 'symbol' => $symbol,
  180 + 'leverage' => $lever,
  181 + 'productType' => 'USDT-FUTURES',
  182 + 'marginCoin' => 'USDT'
  183 + ]);
  184 + if (!isset($res['code']) || $res['code'] != '00000') {
  185 + output('bitget设置杠杆失败', $res);
  186 + } else {
  187 + output('bitget设置杠杆成功', $res);
  188 + }
  189 + return $res;
  190 + }
  191 +
  192 + public function getAllPos()
  193 + {
  194 + return $this->api->getPositions(['productType' => 'SPOT']);
  195 + }
  196 + public function getSymbolInfos()
  197 + {
  198 + $res = $this->api->instruments([
  199 + 'productType' => 'USDT-FUTURES'
  200 + ]);
  201 + if (!isset($res['data'])) {
  202 + output('bitget获取所有交易对信息失败');
  203 + return [];
  204 + }
  205 + return $res['data'];
  206 + }
  207 +}
@@ -85,4 +85,18 @@ class Kline @@ -85,4 +85,18 @@ class Kline
85 $isFinal = $kline['confirm']; 85 $isFinal = $kline['confirm'];
86 return new Kline($time, $open, $high, $low, $close, $vol, $volQuote, $uts, $isFinal); 86 return new Kline($time, $open, $high, $low, $close, $vol, $volQuote, $uts, $isFinal);
87 } 87 }
  88 + public static function transferBitget($data)
  89 + {
  90 + $kline = $data['data'][0];
  91 + $time = (int)($kline['ts']);
  92 + $open = (float)$kline['open'];
  93 + $high = (float)$kline['high'];
  94 + $low = (float)$kline['low'];
  95 + $close = (float)$kline['close'];
  96 + $vol = (float)$kline['vol'];
  97 + $volQuote = (float)$kline['volCcy'];
  98 + $uts = $time;
  99 + $isFinal = $kline['confirm'] ?? true;
  100 + return new Kline($time, $open, $high, $low, $close, $vol, $volQuote, $uts, $isFinal);
  101 + }
88 } 102 }
@@ -94,6 +94,30 @@ class SymbolInfo @@ -94,6 +94,30 @@ class SymbolInfo
94 $info = new SymbolInfo($symbolOri, $symbolSt, $ctVal, $pricePrec, $qtyPrec, $lotPrec, $minLot, $minQty, $mul); 94 $info = new SymbolInfo($symbolOri, $symbolSt, $ctVal, $pricePrec, $qtyPrec, $lotPrec, $minLot, $minQty, $mul);
95 return $info; 95 return $info;
96 } 96 }
  97 + public static function transferBitget($data, callable $getSymbolSt): SymbolInfo
  98 + {
  99 + $symbolOri = $data['symbol'];
  100 + $symbolSt = $getSymbolSt($symbolOri); //转换为标准交易对
  101 + $ctVal = 1; // Bitget合约面值为1
  102 + $pricePrec = (int)$data['pricePlace'];
  103 + $qtyPrec = (int)$data['volumePlace'];
  104 + $lotPrec = $qtyPrec;
  105 + $minQty = $data['minTradeNum'];
  106 + $minLot = $minQty * $ctVal;
  107 + $mul = self::extractNumber($symbolOri);
  108 +
  109 + return new SymbolInfo(
  110 + $symbolOri,
  111 + $symbolSt,
  112 + $ctVal,
  113 + $pricePrec,
  114 + $qtyPrec,
  115 + $lotPrec,
  116 + $minLot,
  117 + $minQty,
  118 + $mul
  119 + );
  120 + }
97 public static function extractNumber($str) 121 public static function extractNumber($str)
98 { 122 {
99 // 示例 123 // 示例
@@ -85,13 +85,13 @@ class WsDataOrder @@ -85,13 +85,13 @@ class WsDataOrder
85 $ordType = strtoupper($data['ordType']); 85 $ordType = strtoupper($data['ordType']);
86 $cliOrdId = $data['clOrdId']; 86 $cliOrdId = $data['clOrdId'];
87 $ordId = $data['ordId']; 87 $ordId = $data['ordId'];
88 - $status = self::getOkStatus($data['state']); 88 + $status = self::getOkxStatus($data['state']);
89 if ($data['cancelSource'] != '') { 89 if ($data['cancelSource'] != '') {
90 $status = 'CANCELED'; 90 $status = 'CANCELED';
91 } 91 }
92 return new WsDataOrder($platform, $posSide, $symbol, $side, $price, $avgPx, $qty, $lot, $pnl, $ts, $uts, $ordType, $cliOrdId, $ordId, $status); 92 return new WsDataOrder($platform, $posSide, $symbol, $side, $price, $avgPx, $qty, $lot, $pnl, $ts, $uts, $ordType, $cliOrdId, $ordId, $status);
93 } 93 }
94 - private static function getOkStatus(string $state) 94 + private static function getOkxStatus(string $state)
95 { 95 {
96 if ($state == 'live') { 96 if ($state == 'live') {
97 return 'LIVE'; 97 return 'LIVE';
@@ -129,9 +129,28 @@ class WsDataOrder @@ -129,9 +129,28 @@ class WsDataOrder
129 $ordType = strtoupper($order['o']); 129 $ordType = strtoupper($order['o']);
130 $cliOrdId = $order['c']; 130 $cliOrdId = $order['c'];
131 $ordId = $order['i']; 131 $ordId = $order['i'];
132 - $status = self::getBnStatus($order['X']); 132 + $status = self::getBinanceStatus($order['X']);
133 return new WsDataOrder($platform, $posSide, $symbol, $side, $price, $avgPx, $qty, $lot, $pnl, $ts, $uts, $ordType, $cliOrdId, $ordId, $status); 133 return new WsDataOrder($platform, $posSide, $symbol, $side, $price, $avgPx, $qty, $lot, $pnl, $ts, $uts, $ordType, $cliOrdId, $ordId, $status);
134 } 134 }
  135 + private static function getBinanceStatus(string $state)
  136 + {
  137 + if ($state == 'NEW') {
  138 + return 'LIVE';
  139 + }
  140 + if ($state == 'PARTIALLY_FILLED') {
  141 + return 'PARTIALLY_FILLED';
  142 + }
  143 + if ($state == 'FILLED') {
  144 + return 'FILLED';
  145 + }
  146 + if ($state == 'CANCELED') {
  147 + return 'CANCELED';
  148 + }
  149 + if ($state == 'EXPIRED' || $state == "EXPIRED_IN_MATCH") {
  150 + return 'CANCELED';
  151 + }
  152 + return 'UNKNOWN';
  153 + }
135 public static function TransferBybitOrder($data, $symbolInfos, callable $toSymbolSt): WsDataOrder|null 154 public static function TransferBybitOrder($data, $symbolInfos, callable $toSymbolSt): WsDataOrder|null
136 { 155 {
137 $symbol = call_user_func($toSymbolSt, $data['symbol']); 156 $symbol = call_user_func($toSymbolSt, $data['symbol']);
@@ -166,25 +185,6 @@ class WsDataOrder @@ -166,25 +185,6 @@ class WsDataOrder
166 $status = self::getBybitStatus($data['orderStatus']); 185 $status = self::getBybitStatus($data['orderStatus']);
167 return new WsDataOrder($platform, $posSide, $symbol, $side, $price, $avgPx, $qty, $lot, $pnl, $ts, $uts, $ordType, $cliOrdId, $ordId, $status); 186 return new WsDataOrder($platform, $posSide, $symbol, $side, $price, $avgPx, $qty, $lot, $pnl, $ts, $uts, $ordType, $cliOrdId, $ordId, $status);
168 } 187 }
169 - private static function getBnStatus(string $state)  
170 - {  
171 - if ($state == 'NEW') {  
172 - return 'LIVE';  
173 - }  
174 - if ($state == 'PARTIALLY_FILLED') {  
175 - return 'PARTIALLY_FILLED';  
176 - }  
177 - if ($state == 'FILLED') {  
178 - return 'FILLED';  
179 - }  
180 - if ($state == 'CANCELED') {  
181 - return 'CANCELED';  
182 - }  
183 - if ($state == 'EXPIRED' || $state == "EXPIRED_IN_MATCH") {  
184 - return 'CANCELED';  
185 - }  
186 - return 'UNKNOWN';  
187 - }  
188 private static function getBybitStatus(string $state) 188 private static function getBybitStatus(string $state)
189 { 189 {
190 if ($state == 'New') { 190 if ($state == 'New') {
@@ -201,4 +201,47 @@ class WsDataOrder @@ -201,4 +201,47 @@ class WsDataOrder
201 } 201 }
202 return 'UNKNOWN'; 202 return 'UNKNOWN';
203 } 203 }
  204 + public static function TransferBitgetOrder(array $data, array $symbolInfos, callable $toSymbolSt): WsDataOrder|null
  205 + {
  206 + $symbol = call_user_func($toSymbolSt, $data['symbol']);
  207 + /** @var SymbolInfo $symbolInfo */
  208 + $symbolInfo = $symbolInfos[$symbol] ?? null;
  209 + if ($symbolInfo === null) {
  210 + return null;
  211 + }
  212 +
  213 + return new WsDataOrder(
  214 + 'bitget',
  215 + 'BOTH',
  216 + $symbol,
  217 + strtoupper($data['side']),
  218 + (float)$data['price'],
  219 + (float)$data['fillPrice'],
  220 + (float)$data['size'],
  221 + (float)$data['size'],
  222 + 0,
  223 + (int)($data['cTime']),
  224 + (int)($data['uTime']),
  225 + strtoupper($data['orderType']),
  226 + $data['clientOid'],
  227 + $data['orderId'],
  228 + self::getBitgetStatus($data['status'])
  229 + );
  230 + }
  231 +
  232 + private static function getBitgetStatus($status)
  233 + {
  234 + switch ($status) {
  235 + case 'new':
  236 + return 'LIVE';
  237 + case 'partial-filled':
  238 + return 'PARTIALLY_FILLED';
  239 + case 'filled':
  240 + return 'FILLED';
  241 + case 'cancelled':
  242 + return 'CANCELED';
  243 + default:
  244 + return 'UNKNOWN';
  245 + }
  246 + }
204 } 247 }
@@ -92,4 +92,23 @@ class WsDataPos @@ -92,4 +92,23 @@ class WsDataPos
92 $pnl = (float)$data['unrealisedPnl']; 92 $pnl = (float)$data['unrealisedPnl'];
93 return new WsDataPos($symbol, $posSide, $qty, $lot, $avgPrice, false, $pnl); 93 return new WsDataPos($symbol, $posSide, $qty, $lot, $avgPrice, false, $pnl);
94 } 94 }
  95 + public static function TransferBitgetPos(array $data, array $symbolInfos, callable $toSymbolSt): WsDataPos|null
  96 + {
  97 + $symbol = call_user_func($toSymbolSt, $data['symbol']);
  98 + /** @var SymbolInfo $symbolInfo */
  99 + $symbolInfo = $symbolInfos[$symbol] ?? null;
  100 + if ($symbolInfo === null) {
  101 + return null;
  102 + }
  103 +
  104 + return new WsDataPos(
  105 + $symbol,
  106 + 'BOTH',
  107 + (float)$data['total'],
  108 + (float)$data['total'],
  109 + (float)$data['averageOpenPrice'],
  110 + false,
  111 + (float)$data['unrealizedPL']
  112 + );
  113 + }
95 } 114 }
@@ -139,4 +139,35 @@ class WsDataTrade @@ -139,4 +139,35 @@ class WsDataTrade
139 $lever = 0; 139 $lever = 0;
140 return new WsDataTrade($platform, $posSide, $symbol, $side, $price, $qty, $lot, $pnl, $fee, $quoteVol, $ts, $tradeId, $ordId, $cliOrdId, $lever); 140 return new WsDataTrade($platform, $posSide, $symbol, $side, $price, $qty, $lot, $pnl, $fee, $quoteVol, $ts, $tradeId, $ordId, $cliOrdId, $lever);
141 } 141 }
  142 + public static function TransferBitgetOrder(array $data, array $symbolInfos, callable $toSymbolSt): WsDataTrade|null
  143 + {
  144 + if ($data['status'] != 'filled' && $data['status'] != 'partial-filled') {
  145 + return null;
  146 + }
  147 +
  148 + $symbol = call_user_func($toSymbolSt, $data['symbol']);
  149 + /** @var SymbolInfo $symbolInfo */
  150 + $symbolInfo = $symbolInfos[$symbol] ?? null;
  151 + if ($symbolInfo === null) {
  152 + return null;
  153 + }
  154 +
  155 + return new WsDataTrade(
  156 + 'bitget',
  157 + 'BOTH',
  158 + $symbol,
  159 + strtoupper($data['side']),
  160 + (float)$data['fillPrice'],
  161 + (float)$data['fillQuantity'],
  162 + (float)$data['fillQuantity'],
  163 + 0,
  164 + (float)$data['fee'],
  165 + (float)$data['fillPrice'] * (float)$data['fillQuantity'],
  166 + (int)($data['cTime']),
  167 + $data['tradeId'],
  168 + $data['orderId'],
  169 + $data['clientOid'],
  170 + 1
  171 + );
  172 + }
142 } 173 }