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

Novatos em negociação quantitativa nos círculos de criptomoedas, dêem uma olhada nisso - Levando você mais perto da negociação quantitativa nos círculos de criptomoedas (V)

Criado em: 2021-05-28 09:50:12, atualizado em: 2023-09-21 21:06:08
comments   14
hits   2531

Novatos em negociação quantitativa nos círculos de criptomoedas, dêem uma olhada nisso - Levando você mais perto da negociação quantitativa nos círculos de criptomoedas (V)

Novatos em negociação quantitativa nos círculos de criptomoedas, dêem uma olhada nisso - Levando você mais perto da negociação quantitativa nos círculos de criptomoedas (V)

No artigo anterior, explicamos a análise da lógica de negociação de uma estratégia de grade simples. Neste artigo, continuaremos a concluir o design desta estratégia de ensino.

  • Análise lógica de transação No artigo anterior, mencionamos que, desde que percorramos cada linha da grade e determinemos se o preço atual cruza acima ou abaixo da linha da grade, a ação da transação pode ser acionada. Mas, na verdade, ainda há muitos detalhes lógicos. Novatos que não entendem a escrita de estratégia geralmente formam uma percepção errada de que “a lógica é muito simples e o código deve ter apenas algumas linhas, mas na escrita real, ainda há muitos detalhes.”

O primeiro detalhe que precisamos considerar é o design da grade infinita. Lembre-se de que no último artigo projetamos uma função para gerar a estrutura de dados da grade inicialcreateNetO que? Esta função gera uma estrutura de dados de grade com um número finito de linhas de grade. E daí se o preço exceder os limites dessa estrutura de dados da grade (além da linha superior da grade com o preço mais alto e da linha inferior da grade com o preço mais baixo) quando a estratégia estiver em execução? Então, primeiro precisamos adicionar um mecanismo de extensão à estrutura de dados da grade.

Comece a escrever a função principal da estratégia, que é o código que inicia a execução da estratégia.

  var diff = 50                                 // 全局变量,网格间距,可以设计成参数,方便讲解,我们把这个参数写死在代码里。
  function main() {
      // 实盘开始运行后,从这里开始执行策略代码
      var ticker = _C(exchange.GetTicker)       // 获取市场最新的行情数据ticker,ticker这个数据的结构参看FMZ API文档:https://www.fmz.com/api#ticker
      var net = createNet(ticker.Last, diff)    // 我们上篇设计的初始构造网格数据结构的函数,这里构造一个网格数据结构net

      while (true) {                            // 然后程序逻辑就进入了这个while死循环,策略执行到此将不停的循环执行这里{}符号之内的代码
          ticker = _C(exchange.GetTicker)       // 死循环代码部分的第一行,获取最新的行情数据,更新给ticker变量
          // 检查网格范围
          while (ticker.Last >= net[net.length - 1].price) {
              net.push({
                  buy : false,
                  sell : false,
                  price : net[net.length - 1].price + diff,
              })
          }
          while (ticker.Last <= net[0].price) {
              var price = net[0].price - diff
              if (price <= 0) {
                  break
              }
              net.unshift({
                  buy : false,
                  sell : false,
                  price : price,
              })
          }

          // 还有其它代码...
      }
  }

O código que torna a estrutura de dados da grade extensível é este (extraído do código acima):

        // 检查网格范围
        while (ticker.Last >= net[net.length - 1].price) {   // 如果价格超过网格最高价格的网格线
            net.push({                                       // 就在网格最高价格的网格线之后加入一个新的网格线
                buy : false,                                 // 初始化卖出标记
                sell : false,                                // 初始化买入标记
                price : net[net.length - 1].price + diff,    // 在之前最高价格的基础上再加一个网格间距
            })
        }
        while (ticker.Last <= net[0].price) {                // 如果价格低于网格最低价格的网格线
            var price = net[0].price - diff                  // 区别于向上添加,要注意向下添加新网格线的价格不能小于等于0,所以这里要判断
            if (price <= 0) {                                // 小于等于0就不添加了,跳出这层循环
                break
            }
            net.unshift({                                    // 就在网格最低价格的网格线之前添加一个新的网格线
                buy : false,
                sell : false,
                price : price,
            })
        }

O próximo passo é considerar como implementar o acionamento de transações em detalhes.

  var diff = 50
  var amount = 0.002       // 增加一个全局变量,也可以设计成参数,当然为了简便讲解,我们也写死在策略代码,
                           // 这个参数控制每次网格线上触发交易时的交易量
  function main() {
      var ticker = _C(exchange.GetTicker)
      var net = createNet(ticker.Last, diff)
      var preTicker = ticker       // 在主循环(死循环)开始前,设置一个变量,记录上一次的行情数据
      while (true) {
          ticker = _C(exchange.GetTicker)
          // 检查网格范围
          while (ticker.Last >= net[net.length - 1].price) {
              net.push({
                  buy : false,
                  sell : false,
                  price : net[net.length - 1].price + diff,
              })
          }
          while (ticker.Last <= net[0].price) {
              var price = net[0].price - diff
              if (price <= 0) {
                  break
              }
              net.unshift({
                  buy : false,
                  sell : false,
                  price : price,
              })
          }  

          // 检索网格
          for (var i = 0 ; i < net.length ; i++) {     // 遍历网格数据结构中的所有网格线
              var p = net[i]
              if (preTicker.Last < p.price && ticker.Last > p.price) {         // 上穿,卖出,当前节点已经交易过不论SELL BUY ,都不再交易
                  if (i != 0) {
                      var downP = net[i - 1]
                      if (downP.buy) {
                          exchange.Sell(-1, amount, ticker)
                          downP.buy = false 
                          p.sell = false 
                          continue
                      }
                  }
                  if (!p.sell && !p.buy) {
                      exchange.Sell(-1, amount, ticker)
                      p.sell = true
                  }
              } else if (preTicker.Last > p.price && ticker.Last < p.price) {  // 下穿,买入
                  if (i != net.length - 1) {
                      var upP = net[i + 1]
                      if (upP.sell) {
                          exchange.Buy(-1, amount * ticker.Last, ticker)
                          upP.sell = false 
                          p.buy = false 
                          continue
                      }
                  }
                  if (!p.buy && !p.sell) {
                      exchange.Buy(-1, amount * ticker.Last, ticker)
                      p.buy = true 
                  } 
              }
          }
          preTicker = ticker    // 把当前的行情数据记录在preTicker中,在下一次循环中,作为“上一次”行情数据和最新的对比,判断上穿下穿
          Sleep(500)
      }
  }  

Você pode ver:

  • Condição de cruzamento da linha de grade:preTicker.Last < p.price && ticker.Last > p.price
  • Condição de cruzamento da linha de grade:preTicker.Last > p.price && ticker.Last < p.price

Foi sobre isso que falamos no artigo anterior:

Novatos em negociação quantitativa nos círculos de criptomoedas, dêem uma olhada nisso - Levando você mais perto da negociação quantitativa nos círculos de criptomoedas (V)

Cruzar para cima ou para baixo é apenas o primeiro passo para determinar se uma negociação pode ser feita, o que também requer a determinação das marcas nos dados da linha da grade.

Se for um cruzamento ascendente, o preço é julgado como sendo menor do que a linha de grade atual e a marca de compra na linha de grade mais próxima. Se o valor da marca de compra for verdadeiro, significa que a linha de grade anterior foi comprada, e a linha de grade anterior é redefinida. A marca de compra da raiz é falsa, e a marca de venda da linha de grade atual é redefinida como falsa.

Após julgar a condição anterior, se ela não for acionada, continue a julgar. Se as marcas de compra/venda na linha de grade atual forem ambas falsas, significa que a linha de grade atual pode ser negociada. Como é um cruzamento ascendente, nós execute a operação sell aqui. Após a execução, marque o sinalizador sell da linha de grade atual como true.

A lógica para lidar com passagens subterrâneas é a mesma (isso fica para os novatos pensarem).

Backtesting de estratégia completa

Para ver alguns dados de backtesting, uma função é escritashowTblExibir os dados.

function showTbl(arr) {
    var tbl = {
        type : "table", 
        title : "网格",
        cols : ["网格信息"],
        rows : []
    }
    var arrReverse = arr.slice(0).reverse()
    _.each(arrReverse, function(ele) {
        var color = ""
        if (ele.buy) {
            color = "#FF0000"
        } else if (ele.sell) {
            color = "#00FF00"
        }
        tbl.rows.push([JSON.stringify(ele) + color])
    })
    LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`", "\n 账户信息:", exchange.GetAccount())
}

Código de estratégia completo:

/*backtest
start: 2021-04-01 22:00:00
end: 2021-05-22 00:00:00
period: 1d
basePeriod: 1m
exchanges: [{"eid":"OKEX","currency":"ETH_USDT","balance":100000}]
*/

var diff = 50
var amount = 0.002
function createNet(begin, diff) {
    var oneSideNums = 10
    var up = []
    var down = []
    for (var i = 0 ; i < oneSideNums ; i++) {
        var upObj = {
            buy : false,
            sell : false, 
            price : begin + diff / 2 + i * diff,
        }
        up.push(upObj)

        var j = (oneSideNums - 1) - i
        var downObj = {
            buy : false,
            sell : false,
            price : begin - diff / 2 - j * diff,
        }
        if (downObj.price <= 0) {  // 价格不能小于等于0 
            continue
        }
        down.push(downObj)
    }

    return down.concat(up)
}

function showTbl(arr) {
    var tbl = {
        type : "table", 
        title : "网格",
        cols : ["网格信息"],
        rows : []
    }
    var arrReverse = arr.slice(0).reverse()
    _.each(arrReverse, function(ele) {
        var color = ""
        if (ele.buy) {
            color = "#FF0000"
        } else if (ele.sell) {
            color = "#00FF00"
        }
        tbl.rows.push([JSON.stringify(ele) + color])
    })
    LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`", "\n 账户信息:", exchange.GetAccount())
}

function main() {
    var ticker = _C(exchange.GetTicker)
    var net = createNet(ticker.Last, diff)
    var preTicker = ticker 
    while (true) {
        ticker = _C(exchange.GetTicker)
        // 检查网格范围
        while (ticker.Last >= net[net.length - 1].price) {
            net.push({
                buy : false,
                sell : false,
                price : net[net.length - 1].price + diff,
            })
        }
        while (ticker.Last <= net[0].price) {
            var price = net[0].price - diff
            if (price <= 0) {
                break
            }
            net.unshift({
                buy : false,
                sell : false,
                price : price,
            })
        }

        // 检索网格
        for (var i = 0 ; i < net.length ; i++) {
            var p = net[i]
            if (preTicker.Last < p.price && ticker.Last > p.price) {         // 上穿,卖出,当前节点已经交易过不论SELL BUY ,都不再交易
                if (i != 0) {
                    var downP = net[i - 1]
                    if (downP.buy) {
                        exchange.Sell(-1, amount, ticker)
                        downP.buy = false 
                        p.sell = false 
                        continue
                    }
                }
                if (!p.sell && !p.buy) {
                    exchange.Sell(-1, amount, ticker)
                    p.sell = true
                }
            } else if (preTicker.Last > p.price && ticker.Last < p.price) {  // 下穿,买入
                if (i != net.length - 1) {
                    var upP = net[i + 1]
                    if (upP.sell) {
                        exchange.Buy(-1, amount * ticker.Last, ticker)
                        upP.sell = false 
                        p.buy = false 
                        continue
                    }
                }
                if (!p.buy && !p.sell) {
                    exchange.Buy(-1, amount * ticker.Last, ticker)
                    p.buy = true 
                } 
            }
        }

        showTbl(net)
        preTicker = ticker 
        Sleep(500)
    }
}

Backtesting de estratégia:

Novatos em negociação quantitativa nos círculos de criptomoedas, dêem uma olhada nisso - Levando você mais perto da negociação quantitativa nos círculos de criptomoedas (V)

Novatos em negociação quantitativa nos círculos de criptomoedas, dêem uma olhada nisso - Levando você mais perto da negociação quantitativa nos círculos de criptomoedas (V)

Novatos em negociação quantitativa nos círculos de criptomoedas, dêem uma olhada nisso - Levando você mais perto da negociação quantitativa nos círculos de criptomoedas (V)

Pode-se observar que as características da estratégia de grade são que haverá grandes perdas flutuantes quando houver uma tendência de mercado, e os retornos só se recuperarão em um mercado volátil. Portanto, a estratégia de grade não é isenta de risco. A estratégia spot ainda pode ser sustentada, mas a estratégia de grade de contrato futuro é mais arriscada e requer configurações conservadoras para os parâmetros de grade.