|
|
|
<?php
|
|
|
|
|
|
|
|
namespace trader;
|
|
|
|
|
|
|
|
require_once __DIR__ . '/autoload.php';
|
|
|
|
require_once __DIR__ . '/../vendor/autoload.php';
|
|
|
|
|
|
|
|
use trader\struct\ApiInfo;
|
|
|
|
use trader\okx\ExBroker as OkxBroker;
|
|
|
|
use trader\binance\ExBroker as BinanceBroker;
|
|
|
|
use trader\struct\Kline;
|
|
|
|
use trader\struct\Order;
|
|
|
|
use trader\struct\WsData;
|
|
|
|
use trader\struct\WsDataTrade;
|
|
|
|
use trader\struct\WsDataPos;
|
|
|
|
use trader\struct\SymbolInfo;
|
|
|
|
use trader\struct\WsDataOrder;
|
|
|
|
use trader\struct\Pos;
|
|
|
|
use \Exception;
|
|
|
|
use function Jiaoyin\timeFormat;
|
|
|
|
use trader\okx\Api as OkApi;
|
|
|
|
|
|
|
|
class CmBroker
|
|
|
|
{
|
|
|
|
private $plat;
|
|
|
|
private ?OkxBroker $exBroker;
|
|
|
|
/** @var SymbolInfo[] $symbolInfos */
|
|
|
|
public $symbolInfos = [];
|
|
|
|
/** @var Pos[] $positions */
|
|
|
|
private $positions = [];
|
|
|
|
private $name = '';
|
|
|
|
|
|
|
|
|
|
|
|
public function __construct($plat, ApiInfo $apiInfo)
|
|
|
|
{
|
|
|
|
$this->plat = $plat;
|
|
|
|
$exBroker = null;
|
|
|
|
if ($plat == 'okx') {
|
|
|
|
$exBroker = new OkxBroker($apiInfo);
|
|
|
|
}
|
|
|
|
if ($plat == 'binance') {
|
|
|
|
$exBroker = new BinanceBroker($apiInfo);
|
|
|
|
}
|
|
|
|
$this->exBroker = $exBroker;
|
|
|
|
}
|
|
|
|
public function setName($name)
|
|
|
|
{
|
|
|
|
$this->name = $name;
|
|
|
|
}
|
|
|
|
public function init()
|
|
|
|
{
|
|
|
|
$this->initSymbolInfos();
|
|
|
|
}
|
|
|
|
public function accListen(callable $onData)
|
|
|
|
{
|
|
|
|
$this->exBroker->accListen(function ($data) use ($onData) {
|
|
|
|
// output("ws 有效数据", $data);
|
|
|
|
if ($this->plat == 'binance') {
|
|
|
|
$this->msg("binance 无处理ws数据实现");
|
|
|
|
}
|
|
|
|
if ($this->plat == 'okx') {
|
|
|
|
if (isset($data['arg']) && $data['arg']['channel'] == 'orders') {
|
|
|
|
foreach ($data['data'] as $key => $value) {
|
|
|
|
$wsDataTrade = WsDataTrade::TransferOkxOrder($value, $this->symbolInfos, function ($symbol) {
|
|
|
|
return $this->getSymbolSt($symbol);
|
|
|
|
});
|
|
|
|
if ($wsDataTrade != null) {
|
|
|
|
$wsData = new WsData($this->plat, 'trade', $trade = $wsDataTrade);
|
|
|
|
$onData($wsData);
|
|
|
|
}
|
|
|
|
$wsDataOrd = WsDataOrder::TransferOkxOrder($value, $this->symbolInfos, function ($symbol) {
|
|
|
|
return $this->getSymbolSt($symbol);
|
|
|
|
});
|
|
|
|
if ($wsDataOrd != null) {
|
|
|
|
$wsData = new WsData($this->plat, 'order', $trade = null, $pos = null, $order = $wsDataOrd);
|
|
|
|
$onData($wsData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (isset($data['arg']) && $data['arg']['channel'] == 'positions') {
|
|
|
|
$positions = [];
|
|
|
|
foreach ($data['data'] as $key => $value) {
|
|
|
|
$wsDataPos = WsDataPos::TransferOkxPos($value, $this->symbolInfos, function ($symbol) {
|
|
|
|
return $this->getSymbolSt($symbol);
|
|
|
|
});
|
|
|
|
if ($wsDataPos) {
|
|
|
|
$pos = Pos::transferWsDataPos($wsDataPos);
|
|
|
|
$positions[$wsDataPos->symbol . "_" . $wsDataPos->posSide] = $pos;
|
|
|
|
$wsData = new WsData($this->plat, 'pos', $trade = null, $pos = $wsDataPos);
|
|
|
|
$onData($wsData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$this->positions = $positions;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
$this->msg("okx 无处理ws数据实现", $data);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
public function klineListen($symbol, $peroid, $onData)
|
|
|
|
{
|
|
|
|
$symbol = $this->getSymbolOri($symbol, $this->plat);
|
|
|
|
$this->exBroker->klineListen($symbol, $peroid, function ($data) use ($onData) {
|
|
|
|
$kline = Kline::transferOkx($data);
|
|
|
|
$onData($kline);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
//转换为标准交易对
|
|
|
|
public function getSymbolSt($symbol)
|
|
|
|
{
|
|
|
|
$symbol = str_replace('-USDT-SWAP', 'USDT', $symbol);
|
|
|
|
if (preg_match('/^[A-Z0-9]+USDT$/', $symbol)) {
|
|
|
|
return $symbol;
|
|
|
|
} else {
|
|
|
|
throw new Exception('转换标准交易对错误' + $symbol + ' to ', $symbol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//转换为原始交易对
|
|
|
|
public function getSymbolOri($symbol, $platTarget)
|
|
|
|
{
|
|
|
|
$symbolSt = $this->getSymbolSt($symbol);
|
|
|
|
if ($platTarget == 'binance') {
|
|
|
|
return $symbolSt;
|
|
|
|
}
|
|
|
|
if ($platTarget == 'okx') {
|
|
|
|
return str_replace('USDT', '-USDT-SWAP', $symbolSt);
|
|
|
|
}
|
|
|
|
throw new Exception('平台错误' + $platTarget);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function placeOrder(Order $order)
|
|
|
|
{
|
|
|
|
if ($this->plat == 'okx') {
|
|
|
|
$orderOri = $order->toOkxOrder($this->symbolInfos, function ($symbol) {
|
|
|
|
return $this->getSymbolOri($symbol, $this->plat);
|
|
|
|
});
|
|
|
|
$this->msg("下单", $orderOri);
|
|
|
|
if ($orderOri['sz'] == 0) {
|
|
|
|
$this->msg("下单数量为0,不下单", $orderOri);
|
|
|
|
return ["code" => 1, "msg" => "下单数量为0,不下单"];
|
|
|
|
}
|
|
|
|
$res = $this->exBroker->placeOrder($orderOri);
|
|
|
|
$this->msg("下单结果", $res);
|
|
|
|
return $res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function msg()
|
|
|
|
{
|
|
|
|
$args = func_get_args();
|
|
|
|
$outStr = '[' . timeFormat('ms') . ']:' . $this->name . ": ";
|
|
|
|
foreach ($args as $key => $value) {
|
|
|
|
$value = is_array($value) ? json_encode($value) : $value;
|
|
|
|
if (is_bool($value)) {
|
|
|
|
$value = $value ? 'bool:true' : 'bool:false';
|
|
|
|
}
|
|
|
|
$outStr .= count($args) - $key > 1 ? $value . ' ' : $value;
|
|
|
|
}
|
|
|
|
echo $outStr . PHP_EOL;
|
|
|
|
}
|
|
|
|
public function getPosQty($symbol, $posSide)
|
|
|
|
{
|
|
|
|
$key = $symbol . "_" . $posSide;
|
|
|
|
if (!isset($this->positions[$key])) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/** @var Pos $pos */
|
|
|
|
$pos = $this->positions[$key];
|
|
|
|
return abs($pos->qty);
|
|
|
|
}
|
|
|
|
private function initSymbolInfos()
|
|
|
|
{
|
|
|
|
if ($this->plat == 'okx') {
|
|
|
|
//获取所有USDT SWAP 交易对
|
|
|
|
$res = $this->exBroker->getSymbolInfos();
|
|
|
|
$infos = [];
|
|
|
|
foreach ($res as $key => $value) {
|
|
|
|
if ($value["settleCcy"] == "USDT") {
|
|
|
|
$info = SymbolInfo::transferOkx($value, function ($symbol) {
|
|
|
|
return $this->getSymbolSt($symbol);
|
|
|
|
});
|
|
|
|
$infos[$info->symbol] = $info;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$this->symbolInfos = $infos;
|
|
|
|
}
|
|
|
|
//定时10m刷新
|
|
|
|
swoole_timer_after(1000 * 60 * 10, function () {
|
|
|
|
$this->initSymbolInfos();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
public function stopListen()
|
|
|
|
{
|
|
|
|
$this->exBroker->stopListen();
|
|
|
|
}
|
|
|
|
} |
...
|
...
|
|