4
Подписаться
1271
Подписчики

Используйте агрегированный рыночный интерфейс цифровых валютных бирж для создания многопродуктовых стратегий

Создано: 2021-03-17 18:38:47, Обновлено: 2024-12-05 22:00:42
comments   13
hits   2466

Используйте агрегированный рыночный интерфейс цифровых валютных бирж для создания многопродуктовых стратегий

Используйте агрегированный рыночный интерфейс цифровых валютных бирж для создания многопродуктовых стратегий

Количественная торговая платформа FMZРаздел «Стратегия наблюдения»Часто можно увидеть многопродуктовые стратегии, которые одновременно отслеживают рыночные условия десятков или даже всего рынка биржи. Как это делается? И как это должно быть спроектировано? В этой статье мы рассмотрим, как использовать интерфейс агрегированного рынка биржи для создания многопродуктовой стратегии.

Возьмите Binance и Huobi в качестве примеров и проверьте их документы API. Мы обнаружили, что у них обоих есть интерфейсы агрегированной рыночной информации:

Интерфейс рынка

  [
      {
          "symbol": "BTCUSDT", // 交易对
          "bidPrice": "4.00000000", //最优买单价
          "bidQty": "431.00000000", //挂单量
          "askPrice": "4.00000200", //最优卖单价
          "askQty": "9.00000000", //挂单量
          "time": 1589437530011   // 撮合引擎时间
      }
      ...
  ]
  [  
      {  
          "open":0.044297,      // 开盘价
          "close":0.042178,     // 收盘价
          "low":0.040110,       // 最低价
          "high":0.045255,      // 最高价
          "amount":12880.8510,  
          "count":12838,
          "vol":563.0388715740,
          "symbol":"ethbtc",
          "bid":0.007545,
          "bidSize":0.008,
          "ask":0.008088,
          "askSize":0.009
      }, 
      ...
  ]

Однако это не так. Структура, фактически возвращаемая интерфейсом Huobi, выглядит так:

  {
      "status": "ok",
      "ts": 1616032188422,
      "data": [{
          "symbol": "hbcbtc",
          "open": 0.00024813,
          "high": 0.00024927,
          "low": 0.00022871,
          "close": 0.00023495,
          "amount": 2124.32,
          "vol": 0.517656218,
          "count": 1715,
          "bid": 0.00023427,
          "bidSize": 2.3,
          "ask": 0.00023665,
          "askSize": 2.93
      }, ...]
  }

Будьте осторожны при обработке данных, возвращаемых интерфейсом.

Создание рамок политической программы

Как инкапсулировать эти два интерфейса в стратегию и как обрабатывать данные? Давайте посмотрим на это вместе.

Давайте сначала напишем конструктор для создания объекта управления.

// 参数e用于传入exchange交易所对象,参数subscribeList是需要处理的交易对列表,例如["BTCUSDT", "ETHUSDT", "EOSUSDT", "LTCUSDT", "ETCUSDT", "XRPUSDT"]
function createManager(e, subscribeList) {           
    var self = {}
    self.supportList = ["Futures_Binance", "Huobi"]  // 支持的交易所的

    // 对象属性
    self.e = e
    self.name = e.GetName()
    self.type = self.name.includes("Futures_") ? "Futures" : "Spot"
    self.label = e.GetLabel()
    self.quoteCurrency = ""  
    self.subscribeList = subscribeList   // subscribeList : [strSymbol1, strSymbol2, ...]
    self.tickers = []                    // 接口获取的所有行情数据,定义数据格式:{bid1: 123, ask1: 123, symbol: "xxx"}}
    self.subscribeTickers = []           // 需要的行情数据,定义数据格式:{bid1: 123, ask1: 123, symbol: "xxx"}}
    self.accData = null                  // 用于记录账户资产数据

    // 初始化函数
    self.init = function() { 
    	// 判断是否支持该交易所
        if (!_.contains(self.supportList, self.name)) {        	
        	throw "not support"
        }
    }

    // 判断数据精度
    self.judgePrecision = function (p) {
        var arr = p.toString().split(".")
        if (arr.length != 2) {
            if (arr.length == 1) {
                return 0
            }
            throw "judgePrecision error, p:" + String(p)
        }
        
        return arr[1].length
    }

    // 更新资产
    self.updateAcc = function(callBackFuncGetAcc) {
        var ret = callBackFuncGetAcc(self)
        if (!ret) {
        	return false 
        }
        self.accData = ret 
        return true 
    }

    // 更新行情数据
    self.updateTicker = function(url, callBackFuncGetArr, callBackFuncGetTicker) {
    	var tickers = []
    	var subscribeTickers = []
    	var ret = self.httpQuery(url)
    	if (!ret) {
    		return false 
    	}
    	try {
            _.each(callBackFuncGetArr(ret), function(ele) {
            	var ticker = callBackFuncGetTicker(ele)
            	tickers.push(ticker)
            	for (var i = 0 ; i < self.subscribeList.length ; i++) {
            		if (self.subscribeList[i] == ele.symbol) {
            			subscribeTickers.push(ticker)
            		}
            	}
            })
        } catch(err) {
        	Log("错误:", err)
        	return false 
        }

        self.tickers = tickers
        self.subscribeTickers = subscribeTickers
        return true 
    }

    self.httpQuery = function(url) {
    	var ret = null
        try {
            var retHttpQuery = HttpQuery(url)
            ret = JSON.parse(retHttpQuery)
        } catch (err) {
            // Log("错误:", err)
            ret = null
        }
        return ret 
    }

    self.returnTickersTbl = function() {
        var tickersTbl = {
        	type : "table", 
        	title : "tickers",
        	cols : ["symbol", "ask1", "bid1"], 
        	rows : []
        }
        _.each(self.subscribeTickers, function(ticker) {        
        	tickersTbl.rows.push([ticker.symbol, ticker.ask1, ticker.bid1])
        })
        return tickersTbl
    }

    // 初始化
    self.init()
	return self 
}

Использование функций API FMZHttpQueryФункция отправляет запрос на доступ к интерфейсу обмена. использоватьHttpQueryТребуется обработка исключенийtry...catchОбрабатывайте исключения, такие как сбои возврата интерфейса. Некоторые студенты могут спросить: «Структуры данных, возвращаемые интерфейсами обмена, различны. Как нам с ними работать? Определенно невозможно использовать тот же метод обработки». Действительно, не только структура данных, возвращаемых интерфейсом обмена, отличается, но даже наименование возвращаемых полей данных отличается. Одно и то же значение может быть названо по-разному. Например, интерфейсы, перечисленные нами выше. Это же выражение означает цену покупки, которая называется:bidPrice, который называетсяbid

Здесь мы используем функции обратного вызова для разделения этих специальных частей обработки. Итак, после инициализации вышеуказанного объекта, при использовании он становится таким: (В следующем коде конструктор опущенcreateManager) Отслеживайте эти контракты с помощью Binance Futures:["BTCUSDT", "ETHUSDT", "EOSUSDT", "LTCUSDT", "ETCUSDT", "XRPUSDT"] Huobi Spot отслеживает следующие торговые пары монета-монета:["btcusdt", "ethusdt", "eosusdt", "etcusdt", "ltcusdt", "xrpusdt"]Например.

function main() {
    var manager1 = createManager(exchanges[0], ["BTCUSDT", "ETHUSDT", "EOSUSDT", "LTCUSDT", "ETCUSDT", "XRPUSDT"])
    var manager2 = createManager(exchanges[1], ["btcusdt", "ethusdt", "eosusdt", "etcusdt", "ltcusdt", "xrpusdt"])   

    while (true) {
    	// 更新行情数据
    	var ticker1GetSucc = manager1.updateTicker("https://fapi.binance.com/fapi/v1/ticker/bookTicker", 
    		function(data) {return data}, 
    		function (ele) {return {bid1: ele.bidPrice, ask1: ele.askPrice, symbol: ele.symbol}})
    	var ticker2GetSucc = manager2.updateTicker("https://api.huobi.pro/market/tickers", 
    		function(data) {return data.data}, 
    		function(ele) {return {bid1: ele.bid, ask1: ele.ask, symbol: ele.symbol}})
        if (!ticker1GetSucc || !ticker2GetSucc) {
        	Sleep(1000)
        	continue
        }
        
        var tbl1 = {
        	type : "table", 
        	title : "期货行情数据",
        	cols : ["期货合约", "期货买一", "期货卖一"], 
        	rows : []
        }
        _.each(manager1.subscribeTickers, function(ticker) {
        	tbl1.rows.push([ticker.symbol, ticker.bid1, ticker.ask1])
        })
        var tbl2 = {
        	type : "table", 
        	title : "现货行情数据",
        	cols : ["现货合约", "现货买一", "现货卖一"], 
        	rows : []
        }
        _.each(manager2.subscribeTickers, function(ticker) {
        	tbl2.rows.push([ticker.symbol, ticker.bid1, ticker.ask1])
        })
        LogStatus(_D(), "\n`" + JSON.stringify(tbl1) + "`", "\n`" + JSON.stringify(tbl2) + "`")
        Sleep(10000)
    }
}

Запустите тесты: Первый объект биржи добавляет фьючерсы Binance, а второй объект биржи добавляет спот Huobi. Используйте агрегированный рыночный интерфейс цифровых валютных бирж для создания многопродуктовых стратегий

Используйте агрегированный рыночный интерфейс цифровых валютных бирж для создания многопродуктовых стратегий

Видно, что здесь такие операции, как получение данных, возвращаемых интерфейсом, обрабатываются специально для различных обменов с использованием функций обратного вызова.

    	var ticker1GetSucc = manager1.updateTicker("https://fapi.binance.com/fapi/v1/ticker/bookTicker", 
    		function(data) {return data}, 
    		function (ele) {return {bid1: ele.bidPrice, ask1: ele.askPrice, symbol: ele.symbol}})
    	var ticker2GetSucc = manager2.updateTicker("https://api.huobi.pro/market/tickers", 
    		function(data) {return data.data}, 
    		function(ele) {return {bid1: ele.bid, ask1: ele.ask, symbol: ele.symbol}})

После формулирования приобретения рыночной информации мы можем далее сформулировать приобретение активов счета. Из-за многопродуктовой стратегии данные об активах счета также должны быть множественными. К счастью, интерфейс активов биржевого счета обычно возвращает все данные об активах.

В конструктореcreateManagerДобавить метод получения активов

    // 更新资产
    self.updateAcc = function(callBackFuncGetAcc) {
        var ret = callBackFuncGetAcc(self)
        if (!ret) {
        	return false 
        }
        self.accData = ret 
        return true 
    }

Кроме того, из-за различных форматов и имен полей, возвращаемых интерфейсом обмена, для специальной обработки также требуются функции обратного вызова.

Если взять в качестве примера спотовые сделки Huobi и фьючерсы Binance, то функцию обратного вызова можно записать следующим образом:

    // 获取账户资产的回调函数
    var callBackFuncGetHuobiAcc = function(self) {
        var account = self.e.GetAccount()
        var ret = []
        if (!account) {
        	return false 
        }
        // 构造资产的数组结构
        var list = account.Info.data.list
        _.each(self.subscribeList, function(symbol) {
            var coinName = symbol.split("usdt")[0]
            var acc = {symbol: symbol}
            for (var i = 0 ; i < list.length ; i++) {
            	if (coinName == list[i].currency) {
                    if (list[i].type == "trade") {
                        acc.Stocks = parseFloat(list[i].balance)
                    } else if (list[i].type == "frozen") {
                    	acc.FrozenStocks = parseFloat(list[i].balance)
                    }
                } else if (list[i].currency == "usdt") {
                	if (list[i].type == "trade") {
                		acc.Balance = parseFloat(list[i].balance)
                	} else if (list[i].type == "frozen") {
                		acc.FrozenBalance = parseFloat(list[i].balance)
                	}
                }
            }
            ret.push(acc)
        })
        return ret 
    }

    var callBackFuncGetFutures_BinanceAcc = function(self) {
    	self.e.SetCurrency("BTC_USDT")   // 设置为U本位合约的交易对
        self.e.SetContractType("swap")   // 合约都是永续合约
        var account = self.e.GetAccount() 
        var ret = []
        if (!account) {
        	return false 
        }
        var balance = account.Balance
        var frozenBalance = account.FrozenBalance
        // 构造资产数据结构
        _.each(self.subscribeList, function(symbol) {
            var acc = {symbol: symbol}
            acc.Balance = balance
            acc.FrozenBalance = frozenBalance
            ret.push(acc)
        })
        return ret 
    }

Запустить стратегическую структуру с функцией получения рыночной информации и активов

Кавычки: Используйте агрегированный рыночный интерфейс цифровых валютных бирж для создания многопродуктовых стратегий

ресурсы: Используйте агрегированный рыночный интерфейс цифровых валютных бирж для создания многопродуктовых стратегий

Видно, что после получения рыночных данных их можно обрабатывать для расчета разницы цен каждого сорта и отслеживания разницы цен спот-фьючерсы для нескольких торговых пар. Затем можно разработать многовариантную стратегию хеджирования фьючерсов и спотовых сделок.

Согласно этому методу проектирования, другие обмены также могут быть расширены. Студенты, которым интересно, могут попробовать это.