
No artigo anterior, trabalhamos juntos para criar uma estratégia de grade simples. Neste artigo, atualizaremos e expandiremos essa estratégia para uma estratégia de grade de pontos multi-variedade e colocaremos essa estratégia à prova em combate real. O objetivo não é encontrar um “Santo Graal”, mas explorar vários problemas e soluções ao projetar estratégias. Este artigo explicará algumas das minhas experiências no design desta estratégia. O conteúdo deste artigo é um pouco complicado e requer uma certa base em programação.
Este artigo, assim como o anterior, ainda discute o design baseado na Quantização do Inventor (FMZ.COM).
BTC_USDT, também pode fazerLTC_USDT/EOS_USDT/DOGE_USDT/ETC_USDT/ETH_USDT. De qualquer forma, para pares de negociação à vista, todos os produtos que você deseja negociar podem ser negociados na grade ao mesmo tempo.Hum~~É bom capturar o mercado volátil de diversas variedades. Os requisitos parecem simples, mas surgem problemas durante o design.
ETHUSDT:100:0.002|LTCUSDT:20:0.1
O “|” separa os dados de cada variedade, o que significaETHUSDT:100:0.002Ele controla o par de negociação ETH_USDT.LTCUSDT:20:0.1Ele controla o par de negociação LTC_USDT. O “|” no meio serve como separador.
ETHUSDT:100:0.002, onde ETHUSDT indica o par de negociação que você deseja negociar, 100 é o espaçamento da grade, 0,002 é o número de moedas ETH negociadas em cada grade e o sinal “:” é usado para separar esses dados (claro, essas regras de parâmetros são definido pelo designer de estratégia). Você pode projetá-lo de acordo com suas necessidades).
Essas strings contêm as informações de parâmetros de cada produto que você deseja negociar. Analise essas strings na estratégia e atribua valores específicos às variáveis da estratégia para controlar a lógica de negociação de cada produto. Então, como analisá-lo? Vamos usar o exemplo acima novamente.
function main() {
var net = [] // 记录的网格参数,具体运行到网格交易逻辑时,使用这里面的数据
var params = "ETHUSDT:100:0.002|LTCUSDT:20:0.1"
var arrPair = params.split("|")
_.each(arrPair, function(pair) {
var arr = pair.split(":")
var symbol = arr[0] // 交易对名称
var diff = parseFloat(arr[1]) // 网格间距
var amount = parseFloat(arr[2]) // 网格下单量
net.push({symbol : symbol, diff : diff, amount : amount})
})
Log("网格参数数据:", net)
}

Você pode ver que os parâmetros são analisados dessa forma. Claro, você também pode usar strings JSON diretamente, o que é mais simples.
function main() {
var params = '[{"symbol":"ETHUSDT","diff":100,"amount":0.002},{"symbol":"LTCUSDT","diff":20,"amount":0.1}]'
var net = JSON.parse(params) // 记录的网格参数,具体运行到网格交易逻辑时,使用这里面的数据
_.each(net, function(pair) {
Log("交易对:", pair.symbol, pair)
})
}

_G()Função, ou usar função de operação de banco de dadosDBExec()Para mais detalhes, consulte a documentação da API do FMZ.Por exemplo, projetamos uma função de varredura, usando_G()Função, salvar os dados da grade.
var net = null
function main() { // 策略主函数
// 首先读取储存的net
net = _G("net")
// ...
}
function onExit() {
_G("net", net)
Log("执行扫尾处理,保存数据", "#FF0000")
}
function onexit() { // 平台系统定义的退出扫尾函数,在点击实盘停止时触发执行
onExit()
}
function onerror() { // 平台系统定义的异常退出函数,在程序发生异常时触发执行
onExit()
}
O sistema de backtest não impõe restrições tão rígidas sobre a quantidade e a precisão dos pedidos, mas na negociação real, cada bolsa pode ter padrões rígidos para o preço e a quantidade dos pedidos, e esses padrões para cada par de negociação também são muito rígidos. As restrições não são o mesmo. Portanto, novatos frequentemente testam o sistema de backtest e veem todos os tipos de problemas ao disparar transações no mercado real. Eles então nem leem a mensagem de erro e experimentam todos os tipos de problemas malucos [dog head].
Para variedades múltiplas, esse requisito é mais complicado. Para uma estratégia de produto único, você pode projetar um parâmetro para especificar informações como precisão. No entanto, ao projetar uma estratégia de vários produtos, é óbvio que escrever essas informações no parâmetro fará com que o parâmetro pareça muito inchado.
Neste momento, você precisa verificar a documentação da API da exchange para ver se há uma interface com informações relacionadas ao par de negociação na documentação da exchange. Se essas interfaces estiverem disponíveis, você pode projetar uma interface de acesso automático na estratégia para obter informações como precisão e configurá-la para as informações do par de negociação envolvido na transação (em termos simples, a precisão é solicitada automaticamente à bolsa e então adaptado aos parâmetros da estratégia). variáveis).
Com base na análise acima, uma biblioteca de modelos é projetada para reduzir o acoplamento entre estratégias e mecanismos de troca e interfaces.
Podemos projetar esta biblioteca de classes de modelo assim (alguns códigos são omitidos):
function createBaseEx(e, funcConfigure) {
var self = {}
self.e = e
self.funcConfigure = funcConfigure
self.name = e.GetName()
self.type = self.name.includes("Futures_") ? "Futures" : "Spot"
self.label = e.GetLabel()
// 需要实现的接口
self.interfaceGetTickers = null // 创建异步获取聚合行情数据线程的函数
self.interfaceGetAcc = null // 创建异步获取账户数据线程的函数
self.interfaceGetPos = null // 获取持仓
self.interfaceTrade = null // 创建并发下单
self.waitTickers = null // 等待并发行情数据
self.waitAcc = null // 等待账户并发数据
self.waitTrade = null // 等待下单并发数据
self.calcAmount = null // 根据交易对精度等数据计算下单量
self.init = null // 初始化工作,获取精度等数据
// 执行配置函数,给对象配置
funcConfigure(self)
// 检测configList约定的接口是否都实现
_.each(configList, function(funcName) {
if (!self[funcName]) {
throw "接口" + funcName + "未实现"
}
})
return self
}
$.createBaseEx = createBaseEx
$.getConfigureFunc = function(exName) {
dicRegister = {
"Futures_OKCoin" : funcConfigure_Futures_OKCoin, // OK期货的实现
"Huobi" : funcConfigure_Huobi,
"Futures_Binance" : funcConfigure_Futures_Binance,
"Binance" : funcConfigure_Binance,
"WexApp" : funcConfigure_WexApp, // wexApp的实现
}
return dicRegister
}
No modelo, escreva-o para a implementação de troca específica, por exemplo, tome como exemplo o disco de simulação WexApp da FMZ:
function funcConfigure_WexApp(self) {
var formatSymbol = function(originalSymbol) {
// BTC_USDT
var arr = originalSymbol.split("_")
var baseCurrency = arr[0]
var quoteCurrency = arr[1]
return [originalSymbol, baseCurrency, quoteCurrency]
}
self.interfaceGetTickers = function interfaceGetTickers() {
self.routineGetTicker = HttpQuery_Go("https://api.wex.app/api/v1/public/tickers")
}
self.waitTickers = function waitTickers() {
var ret = []
var arr = JSON.parse(self.routineGetTicker.wait()).data
_.each(arr, function(ele) {
ret.push({
bid1: parseFloat(ele.buy),
bid1Vol: parseFloat(-1),
ask1: parseFloat(ele.sell),
ask1Vol: parseFloat(-1),
symbol: formatSymbol(ele.market)[0],
type: "Spot",
originalSymbol: ele.market
})
})
return ret
}
self.interfaceGetAcc = function interfaceGetAcc(symbol, updateTS) {
if (self.updateAccsTS != updateTS) {
self.routineGetAcc = self.e.Go("GetAccount")
}
}
self.waitAcc = function waitAcc(symbol, updateTS) {
var arr = formatSymbol(symbol)
var ret = null
if (self.updateAccsTS != updateTS) {
ret = self.routineGetAcc.wait().Info
self.bufferGetAccRet = ret
} else {
ret = self.bufferGetAccRet
}
if (!ret) {
return null
}
var acc = {symbol: symbol, Stocks: 0, FrozenStocks: 0, Balance: 0, FrozenBalance: 0, originalInfo: ret}
_.each(ret.exchange, function(ele) {
if (ele.currency == arr[1]) {
// baseCurrency
acc.Stocks = parseFloat(ele.free)
acc.FrozenStocks = parseFloat(ele.frozen)
} else if (ele.currency == arr[2]) {
// quoteCurrency
acc.Balance = parseFloat(ele.free)
acc.FrozenBalance = parseFloat(ele.frozen)
}
})
return acc
}
self.interfaceGetPos = function interfaceGetPos(symbol, price, initSpAcc, nowSpAcc) {
var symbolInfo = self.getSymbolInfo(symbol)
var sumInitStocks = initSpAcc.Stocks + initSpAcc.FrozenStocks
var sumNowStocks = nowSpAcc.Stocks + nowSpAcc.FrozenStocks
var diffStocks = _N(sumNowStocks - sumInitStocks, symbolInfo.amountPrecision)
if (Math.abs(diffStocks) < symbolInfo.min / price) {
return []
}
return [{symbol: symbol, amount: diffStocks, price: null, originalInfo: {}}]
}
self.interfaceTrade = function interfaceTrade(symbol, type, price, amount) {
var tradeType = ""
if (type == self.OPEN_LONG || type == self.COVER_SHORT) {
tradeType = "bid"
} else {
tradeType = "ask"
}
var params = {
"market": symbol,
"side": tradeType,
"amount": String(amount),
"price" : String(-1),
"type" : "market"
}
self.routineTrade = self.e.Go("IO", "api", "POST", "/api/v1/private/order", self.encodeParams(params))
}
self.waitTrade = function waitTrade() {
return self.routineTrade.wait()
}
self.calcAmount = function calcAmount(symbol, type, price, amount) {
// 获取交易对信息
var symbolInfo = self.getSymbolInfo(symbol)
if (!symbol) {
throw symbol + ",交易对信息查询不到"
}
var tradeAmount = null
var equalAmount = null // 记录币数
if (type == self.OPEN_LONG || type == self.COVER_SHORT) {
tradeAmount = _N(amount * price, parseFloat(symbolInfo.pricePrecision))
// 检查最小交易量
if (tradeAmount < symbolInfo.min) {
Log(self.name, " tradeAmount:", tradeAmount, "小于", symbolInfo.min)
return false
}
equalAmount = tradeAmount / price
} else {
tradeAmount = _N(amount, parseFloat(symbolInfo.amountPrecision))
// 检查最小交易量
if (tradeAmount < symbolInfo.min / price) {
Log(self.name, " tradeAmount:", tradeAmount, "小于", symbolInfo.min / price)
return false
}
equalAmount = tradeAmount
}
return [tradeAmount, equalAmount]
}
self.init = function init() { // 自动处理精度等条件的函数
var ret = JSON.parse(HttpQuery("https://api.wex.app/api/v1/public/markets"))
_.each(ret.data, function(symbolInfo) {
self.symbolsInfo.push({
symbol: symbolInfo.pair,
amountPrecision: parseFloat(symbolInfo.basePrecision),
pricePrecision: parseFloat(symbolInfo.quotePrecision),
multiplier: 1,
min: parseFloat(symbolInfo.minQty),
originalInfo: symbolInfo
})
})
}
}
Então usar este modelo na estratégia é simples:
function main() {
var fuExName = exchange.GetName()
var fuConfigureFunc = $.getConfigureFunc()[fuExName]
var ex = $.createBaseEx(exchange, fuConfigureFunc)
var arrTestSymbol = ["LTC_USDT", "ETH_USDT", "EOS_USDT"]
var ts = new Date().getTime()
// 测试获取行情
ex.goGetTickers()
var tickers = ex.getTickers()
Log("tickers:", tickers)
// 测试获取账户信息
ex.goGetAcc(symbol, ts)
_.each(arrTestSymbol, function(symbol) {
_.each(tickers, function(ticker) {
if (symbol == ticker.originalSymbol) {
// 打印行情数据
Log(symbol, ticker)
}
})
// 打印资产数据
var acc = ex.getAcc(symbol, ts)
Log("acc:", acc.symbol, acc)
})
}
É muito simples projetar e escrever uma estratégia com base no modelo acima. A estratégia inteira tem cerca de 300+ linhas, que implementam uma estratégia de grade multi-variedade spot de moeda digital.


Perdendo dinheiro atualmenteT_T, o código-fonte não será divulgado por enquanto.
Aqui estão alguns códigos de registro. Se você estiver interessado, pode tentar no wexApp:
购买地址: https://www.fmz.com/m/s/284507
注册码:
adc7a2e0a2cfde542e3ace405d216731
f5db29d05f57266165ce92dc18fd0a30
1735dca92794943ddaf277828ee04c27
0281ea107935015491cda2b372a0997d
1d0d8ef1ea0ea1415eeee40404ed09cc
Havia pouco mais de 200 Us e, quando começou a funcionar, encontrou um grande mercado unilateral e se recuperou lentamente. A maior vantagem da grade de pontos é: “Você pode dormir bem!” A estabilidade está ok. Não toquei nela desde 27 de maio. Não ouso tentar a grade de futuros por enquanto.