Na secção [
Pegue Binance e Huobi como exemplo; se você verificar sua documentação de API, você encontrará interfaces agregadas:
Contrato Binance:https://fapi.binance.com/fapi/v1/ticker/bookTickerDados devolvidos pela interface:
[
{
"symbol": "BTCUSDT", // trading pair
"bidPrice": "4.00000000", //optimum bid price
"bidQty": "431.00000000", //bid quantity
"askPrice": "4.00000200", //optimum ask price
"askQty": "9.00000000", //ask quantity
"time": 1589437530011 // matching engine time
}
...
]
Spot da Huobi:https://api.huobi.pro/market/tickersDados devolvidos pela interface:
[
{
"open":0.044297, // open price
"close":0.042178, // close price
"low":0.040110, // the lowest price
"high":0.045255, // the highest price
"amount":12880.8510,
"count":12838,
"vol":563.0388715740,
"symbol":"ethbtc",
"bid":0.007545,
"bidSize":0.008,
"ask":0.008088,
"askSize":0.009
},
...
]
No entanto, o resultado não é realmente assim, e a estrutura real devolvida pela interface 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
}, ...]
}
Deve ser prestada atenção ao processar os dados devolvidos pela interface.
Como encapsular as duas interfaces na estratégia e como processar os dados? Vamos dar uma olhada.
Primeiro, escrever um construtor, para construir objetos de controle
// parameter e is used to import the exchange object; parameter subscribeList is the trading pair list to be processed, such as ["BTCUSDT", "ETHUSDT", "EOSUSDT", "LTCUSDT", "ETCUSDT", "XRPUSDT"]
function createManager(e, subscribeList) {
var self = {}
self.supportList = ["Futures_Binance", "Huobi"] // the supported platform's
// object attribute
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 = [] // all market data obtained by the interfaces; define the data format as: {bid1: 123, ask1: 123, symbol: "xxx"}}
self.subscribeTickers = [] // the market data needed; define the data format as: {bid1: 123, ask1: 123, symbol: "xxx"}}
self.accData = null // used to record the account asset data
// initialization function
self.init = function() {
// judge whether a platform is supported
if (!_.contains(self.supportList, self.name)) {
throw "not support"
}
}
// judge the data precision
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
}
// update assets
self.updateAcc = function(callBackFuncGetAcc) {
var ret = callBackFuncGetAcc(self)
if (!ret) {
return false
}
self.accData = ret
return true
}
// update market data
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("error:", 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("error:", 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
}
// initialization
self.init()
return self
}
Utilize a função FMZ APIHttpQuery
para enviar uma solicitação de acesso à interface da plataforma.HttpQuery
, você precisa usar o processamento de exceçõestry...catch
para lidar com exceções como falhas de retorno de interface.
Alguns estudantes aqui podem perguntar: bidPrice
em Binance, masbid
em Huobi.
Usamos a função de recallback aqui e separar estas partes que precisam de processamento especializado de forma independente.
Então depois que o objeto acima é inicializado, ele se torna assim no uso específico:
(O seguinte código omite o construtorcreateManager
)
Contratos monitorizados pela Binance Futures:["BTCUSDT", "ETHUSDT", "EOSUSDT", "LTCUSDT", "ETCUSDT", "XRPUSDT"]
Pais de negociação spot monitorizados pela 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) {
// update market data
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 : "futures market data",
cols : ["futures contract", "futures buy1", "futures sell1"],
rows : []
}
_.each(manager1.subscribeTickers, function(ticker) {
tbl1.rows.push([ticker.symbol, ticker.bid1, ticker.ask1])
})
var tbl2 = {
type : "table",
title : "spot market data",
cols : ["spot contract", "spot buy1", "spot sell1"],
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)
}
}
Ensaio de funcionamento:
Adicione Binance Futures como o primeiro objeto de troca e adicione Huobi Spot como o segundo objeto de troca.
Como você pode ver, aqui a função callback é invocada para fazer processamento especializado em operações em diferentes plataformas, como como obter os dados retornados pela interface.
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}})
Depois de projetar o método de obtenção dos dados de mercado, podemos criar um método de obtenção dos dados de mercado. Para ser uma estratégia de vários símbolos, os dados de ativos da conta também são múltiplos. Felizmente, uma interface de ativos da conta da plataforma geralmente retorna dados de ativos completos.
Adicionar o método de obtenção de ativos no construtorcreateManager
:
// update assets
self.updateAcc = function(callBackFuncGetAcc) {
var ret = callBackFuncGetAcc(self)
if (!ret) {
return false
}
self.accData = ret
return true
}
Da mesma forma, para os formatos retornados por diferentes interfaces de plataforma e os nomes de campos são diferentes, aqui precisamos usar a função de callback para fazer processamento especializado.
Pegue Huobi Spot e Binance Futures como exemplos, e a função de callback pode ser escrita assim:
// the callback function of obtaining the account assets
var callBackFuncGetHuobiAcc = function(self) {
var account = self.e.GetAccount()
var ret = []
if (!account) {
return false
}
// construct the array structure of assets
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") // set to USDT-margined contract trading pair
self.e.SetContractType("swap") // all are perpetual contracts
var account = self.e.GetAccount()
var ret = []
if (!account) {
return false
}
var balance = account.Balance
var frozenBalance = account.FrozenBalance
// construct asset data structure
_.each(self.subscribeList, function(symbol) {
var acc = {symbol: symbol}
acc.Balance = balance
acc.FrozenBalance = frozenBalance
ret.push(acc)
})
return ret
}
Mercado:
Ativos:
Pode-se ver que depois de obter os dados de mercado, você pode processar os dados para calcular o spread de preço de cada símbolo, e monitorar o spread de preço spot de futuros de vários pares de negociação. E então você pode projetar uma estratégia de hedge de futuros multi-símbolo.
De acordo com esta forma de desenhar, outras plataformas também podem ser expandidas assim, e os estudantes interessados podem experimentá-lo.