Plataforma de troca quantitativa FMZA estratégia do panoramaÉ frequente encontrar estratégias de múltiplas variedades, ao mesmo tempo em que se detectam dezenas de mercados ou até mesmo um mercado inteiro. Como fazer isso?
Para listar as duas trocas de Bitcoin e Token, veja o documento da API da bolsa e veja que todas elas possuem uma interface de mercado agregado:
O acordo de Binance:https://fapi.binance.com/fapi/v1/ticker/bookTickerInterface de retorno de dados
[
{
"symbol": "BTCUSDT", // 交易对
"bidPrice": "4.00000000", //最优买单价
"bidQty": "431.00000000", //挂单量
"askPrice": "4.00000200", //最优卖单价
"askQty": "9.00000000", //挂单量
"time": 1589437530011 // 撮合引擎时间
}
...
]
O Bitcoin é uma moeda em dinheiro:https://api.huobi.pro/market/tickersInterface de retorno de dados
[
{
"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
},
...
]
Mas, na realidade, não é assim, a estrutura que a interface do token retorna é:
{
"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
}, ...]
}
É necessário ter cuidado ao processar os dados retornados pela interface.
Como envolver essas duas interfaces na estratégia e como processar os dados? A gente pode ver tudo juntos, devagar.
Primeiro, escreva uma função de construção para construir objetos de controle.
// 参数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
}
Funções de API com FMZHttpQuery
Funções para enviar solicitações e acessar interfaces de exchanges.HttpQuery
Quando é necessário o tratamento de exceçõestry...catch
Tratar de exceções, como falhas de retorno de interface.
Alguns dos alunos que vêem aqui podem perguntar: "Como lidar com as diferentes estruturas de dados que as interfaces das bolsas de alumínio retornam?
Na verdade, não só a estrutura de dados de interfaces de trocas é diferente, mas até mesmo os nomes dos campos de dados retornados são diferentes. Um mesmo significado pode ser um nome diferente. Por exemplo, a interface que listamos acima.bidPrice
A moeda é chamadabid
。
Nós usamos soluções de chamadas para separar essas partes de tratamentos especiais.
O objeto acima é initializado e, quando usado especificamente, fica assim:
(O código abaixo omite a função de construção)createManager
Não.
Os futuros em Bitcoin são monitorados por:["BTCUSDT", "ETHUSDT", "EOSUSDT", "LTCUSDT", "ETCUSDT", "XRPUSDT"]
O Bitcoin Cash monitora as transações de moedas para:["btcusdt", "ethusdt", "eosusdt", "etcusdt", "ltcusdt", "xrpusdt"]
Por exemplo:
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)
}
}
A partir de agora, a empresa está em desenvolvimento. O primeiro objeto de troca adiciona futuros de moeda digital e o segundo objecto de troca adiciona dinheiro de tokens.
Como se pode ver, aqui, operações como a extração de dados de retorno da interface são usadas para processar a especialização de diferentes exchanges usando funções de retorno.
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}})
A aquisição de mercado é definida e a aquisição de ativos de conta pode ser definida em seguida, pois a estratégia multi-variedade é que os dados de ativos de conta também devem ser múltiplos.
Em funções de construçãocreateManager
Adicionar métodos para obter os ativos
// 更新资产
self.updateAcc = function(callBackFuncGetAcc) {
var ret = callBackFuncGetAcc(self)
if (!ret) {
return false
}
self.accData = ret
return true
}
Também, devido ao formato de retorno da interface do exchange, os nomes dos campos variam, o que também requer o tratamento especializado de funções de retorno.
Em um exemplo de moeda corrente, moeda de futuro, a função de retorno pode ser escrita assim:
// 获取账户资产的回调函数
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
}
O que aconteceu:
Ativos:
A partir daí, o cliente pode visualizar a diferença entre as diferentes variedades, monitorando a diferença entre os diferentes pares de transações. A partir daí, pode-se criar uma estratégia de hedge de futuros de várias variedades.
De acordo com este design, outras casas de câmbio podem ser expandidas e os alunos interessados podem experimentá-las.
Eu amo o Jimmy.O que a callBackFuncGetAcc tem a ver com o callBackFuncGetAcc? Eu sinto que é um conjunto de funções dentro de funções, onde aprender esse conhecimento?
Eu amo o Jimmy.Como extrair simultaneamente o preço do Bid1 e do Ask1 de um par de negociações em um prazo de diferença?
ZltimMuito bem.
Inventor quantificado - sonho pequenoA função de chamada de volta do Baudoin.
Inventor quantificado - sonho pequenoAfinal, o que eu quero dizer é que os dois ciclos se cruzam e atravessam.
Inventor quantificado - sonho pequenoO que eu estou dizendo é a diferença entre o preço de venda e o preço de venda de futuros, não é tudo descrito no artigo, é a diferença de venda. A questão é: o que você está fazendo para diminuir ou não?
Eu amo o Jimmy.Se você quiser obter a diferença entre o preço de compra e o preço de venda do BTCUSDT no mercado de futuros: primeiro percorra o gerenciador de mercado de futuros 1.subscribeTickers, descubra o gerenciador de preço de venda do BTCUSDT 1.subscribeTickers[i].ask1, a questão é como extrair o preço de oferta do BTCUSDT no mercado de futuros quando o gerenciamento de mercado de futuros é feito, será que o gerenciador de mercado de futuros 1.subscribeTickers?
Eu amo o Jimmy.Eu quero dizer a diferença entre o preço de compra e o preço de venda de futuros, e não o preço de compra e venda de futuros ou de futuros; o problema é que não é possível obter o preço de compra e o preço de venda do mesmo negócio. função GetBAspot ((syboml, tickerspot, BA) { para (var i = 0; i < tickerspot.length; i++) { If (tickerspot [i].syboml!==syboml) { Continuar }else If (tickerspot [i].syboml ===syboml) { var bidspot=tickerspot[i].bid1 var askspot=tickerspot[i].ask1 Não. Não. If ((BA==="bid") return bidspot (em inglês) if ((BA==="ask") return askspot Não. função main() { _.each ((manager1.subscribe Tickers, function ((ticker)) { var symb=ticker.symbol var symb1=manager1.symFuturesToSpot (symb) tbl1.rows.push (([ticker.symbol, ticker.bid1, ticker.ask1, manager1.Getfundingrate ((symb), manager1.Getrealrate ((symb, 50), GetBAspot ((symb1, SpotTickers, "ask"))))) Não. Não.
Inventor quantificado - sonho pequenoA diferença de preços não é uma redução da diferença de preços.
Eu amo o Jimmy.Como é que o código de origem do artigo não foi divulgado?
Inventor quantificado - sonho pequenoNão entendo o que você quer dizer.
Eu amo o Jimmy.Eu vi, mas não há uma unificação para especificar o mesmo par de transações.
Inventor quantificado - sonho pequenoVocê vê que o código tem dados de compra e venda.