avatar of 发明者量化-小小梦 发明者量化-小小梦
focar em Mensagem privada
4
focar em
1271
Seguidores

Use a interface de mercado agregada de trocas de moeda digital para construir estratégias de vários produtos

Criado em: 2021-03-17 18:38:47, atualizado em: 2024-12-05 22:00:42
comments   13
hits   2466

Use a interface de mercado agregada de trocas de moeda digital para construir estratégias de vários produtos

Use a interface de mercado agregada de trocas de moeda digital para construir estratégias de vários produtos

Plataforma de negociação quantitativa FMZSeção de observação de estratégiaÉ comum ver algumas estratégias multiprodutos que monitoram simultaneamente as condições de mercado de dezenas ou até mesmo de todo o mercado de uma bolsa. Como isso é feito? E como ele deve ser projetado? Este artigo explorará como usar a interface de mercado agregado de câmbio para criar uma estratégia multiproduto.

Tome Binance e Huobi como exemplos e verifique seus documentos de API. Descobrimos que ambos têm interfaces de informações de mercado agregadas:

Interface de mercado

  [
      {
          "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
      }, 
      ...
  ]

No entanto, esse não é o caso. A estrutura realmente retornada 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
      }, ...]
  }

Tenha cuidado ao processar dados retornados pela interface.

Construindo uma estrutura de programa de políticas

Como encapsular essas duas interfaces na estratégia e como processar os dados? Vamos dar uma olhada nisso juntos.

Vamos primeiro escrever um construtor para construir o objeto 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 
}

Usando funções da API FMZHttpQueryA função envia uma solicitação para acessar a interface de troca. usarHttpQueryO tratamento de exceções é necessáriotry...catchLide com exceções, como falhas de retorno de interface. Alguns alunos podem perguntar: “As estruturas de dados retornadas pelas interfaces de troca são diferentes. Como devemos lidar com elas? Definitivamente não é possível usar o mesmo método de processamento.” De fato, não apenas a estrutura de dados retornada pela interface de troca é diferente, mas até mesmo a nomenclatura dos campos de dados retornados é diferente. O mesmo significado pode ter nomes diferentes. Por exemplo, as interfaces que listamos acima. A mesma expressão significa o preço de compra, que é chamado:bidPrice, que é chamadobid

Usamos funções de retorno de chamada aqui para separar essas partes especiais de processamento. Então, depois que o objeto acima é inicializado, ele fica assim quando usado: (O código a seguir omite o construtorcreateManager) Monitore esses contratos com a Binance Futures:["BTCUSDT", "ETHUSDT", "EOSUSDT", "LTCUSDT", "ETCUSDT", "XRPUSDT"] O Huobi Spot monitora estes pares de negociação moeda a moeda:["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)
    }
}

Execute os testes: O primeiro objeto de troca adiciona futuros da Binance e o segundo objeto de troca adiciona o Huobi spot Use a interface de mercado agregada de trocas de moeda digital para construir estratégias de vários produtos

Use a interface de mercado agregada de trocas de moeda digital para construir estratégias de vários produtos

Pode-se observar que aqui, as operações como obter os dados retornados pela interface são processadas especificamente para diferentes trocas usando funções de retorno de chamada.

    	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}})

Após formular a aquisição de informações de mercado, podemos formular a aquisição de ativos de conta. Devido à estratégia de multiprodutos, os dados de ativos de conta também devem ser múltiplos. Felizmente, a interface de ativos da conta de câmbio geralmente retorna todos os dados de ativos.

No construtorcreateManagerAdicione um método para obter ativos

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

Além disso, devido aos diferentes formatos e nomes de campos retornados pela interface de troca, funções de retorno de chamada também são necessárias para processamento especial.

Tomando como exemplos o Huobi spot e o Binance futures, a função de retorno de chamada 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 
    }

Executar uma estrutura de estratégia com a função de obter informações de mercado e ativos

Citações: Use a interface de mercado agregada de trocas de moeda digital para construir estratégias de vários produtos

ativos: Use a interface de mercado agregada de trocas de moeda digital para construir estratégias de vários produtos

Pode-se observar que, após obter os dados de mercado, os dados podem ser processados ​​para calcular a diferença de preço de cada variedade e monitorar a diferença de preço spot-futuros de vários pares de negociação. Então, uma estratégia de hedge multivariada de futuros e spot pode ser projetada.

De acordo com esse método de design, outras trocas também podem ser expandidas. Estudantes interessados ​​podem experimentar.