avatar of 发明者量化-小小梦 发明者量化-小小梦
Seguir Mensajes Privados
4
Seguir
1271
Seguidores

Si eres un principiante en el trading cuantitativo en el ámbito de las criptomonedas, echa un vistazo a este artículo: te acercamos al trading cuantitativo en el ámbito de las criptomonedas (V)

Creado el: 2021-05-28 09:50:12, Actualizado el: 2023-09-21 21:06:08
comments   14
hits   2531

Si eres un principiante en el trading cuantitativo en el ámbito de las criptomonedas, echa un vistazo a este artículo: te acercamos al trading cuantitativo en el ámbito de las criptomonedas (V)

Si eres un principiante en el trading cuantitativo en el ámbito de las criptomonedas, echa un vistazo a este artículo: te acercamos al trading cuantitativo en el ámbito de las criptomonedas (V)

En el artículo anterior, explicamos el análisis de la lógica comercial de una estrategia de cuadrícula simple. En este artículo, continuaremos completando el diseño de esta estrategia de enseñanza.

  • Análisis de la lógica de transacciones En el artículo anterior, mencionamos que siempre que recorremos cada línea de la cuadrícula y determinamos si el precio actual cruza por encima o por debajo de la línea de la cuadrícula, se puede activar la acción de transacción. Pero, en realidad, todavía hay muchos detalles lógicos. Los novatos que no entienden cómo escribir estrategias a menudo forman una percepción errónea de que “la lógica es muy simple y el código debería tener solo unas pocas líneas, pero en la escritura real, todavía hay muchos detalles.”

El primer detalle que debemos considerar es el diseño de la cuadrícula infinita. Recuerde que en el último artículo diseñamos una función para generar la estructura de datos de la cuadrícula inicial.createNet¿Qué? Esta función genera una estructura de datos de cuadrícula con un número finito de líneas de cuadrícula. ¿Qué pasa entonces si el precio excede los límites de esta estructura de datos de la cuadrícula (más allá de la línea superior de la cuadrícula con el precio más alto y la línea inferior de la cuadrícula con el precio más bajo) cuando se ejecuta la estrategia? Primero debemos agregar un mecanismo de extensión a la estructura de datos de la cuadrícula.

Comience a escribir la función principal de la estrategia, que es el código que inicia la ejecución de la estrategia.

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

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

El código que hace que la estructura de datos de la cuadrícula sea extensible es este (extraído del código anterior):

        // 检查网格范围
        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,
            })
        }

El siguiente paso es considerar cómo implementar la activación de transacciones en detalle.

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

Puedes ver:

  • Condición de cruzar la línea de la cuadrícula:preTicker.Last < p.price && ticker.Last > p.price
  • Condición de cruzar la línea de la cuadrícula:preTicker.Last > p.price && ticker.Last < p.price

Esto es de lo que hablamos en el artículo anterior:

Si eres un principiante en el trading cuantitativo en el ámbito de las criptomonedas, echa un vistazo a este artículo: te acercamos al trading cuantitativo en el ámbito de las criptomonedas (V)

Cruzar hacia arriba o hacia abajo es solo el primer paso para determinar si se puede realizar una operación, lo que también requiere determinar las marcas en los datos de las líneas de la cuadrícula.

Si se trata de un cruce ascendente, se considera que el precio es inferior a la línea de cuadrícula actual y a la marca de compra en la línea de cuadrícula más cercana. Si el valor de la marca de compra es verdadero, significa que se ha comprado la línea de cuadrícula anterior. y se restablece la línea de cuadrícula anterior. La marca de compra de la raíz es falsa y la marca de venta de la línea de cuadrícula actual se restablece a falsa.

Después de juzgar la condición anterior, si no se activa, continúe juzgando. Si las marcas de compra/venta en la línea de cuadrícula actual son ambas falsas, significa que se puede negociar la línea de cuadrícula actual. Dado que es un cruce ascendente, Ejecute la operación de venta aquí. Después de la ejecución, marque la bandera de venta de la línea de cuadrícula actual como verdadera.

La lógica para el manejo de los pasos subterráneos es la misma (esto queda a criterio de los novatos).

Backtesting de estrategia completa

Para poder ver algunos datos de backtesting, se escribe una funciónshowTblMostrar los datos.

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

Prueba retrospectiva de estrategia:

Si eres un principiante en el trading cuantitativo en el ámbito de las criptomonedas, echa un vistazo a este artículo: te acercamos al trading cuantitativo en el ámbito de las criptomonedas (V)

Si eres un principiante en el trading cuantitativo en el ámbito de las criptomonedas, echa un vistazo a este artículo: te acercamos al trading cuantitativo en el ámbito de las criptomonedas (V)

Si eres un principiante en el trading cuantitativo en el ámbito de las criptomonedas, echa un vistazo a este artículo: te acercamos al trading cuantitativo en el ámbito de las criptomonedas (V)

Se puede observar que las características de la estrategia de cuadrícula son que habrá grandes pérdidas flotantes cuando hay un mercado en tendencia, y los retornos solo rebotarán en un mercado volátil. Por lo tanto, la estrategia de red no está libre de riesgos. La estrategia al contado todavía se puede mantener, pero la estrategia de red de contratos de futuros es más riesgosa y requiere configuraciones conservadoras para los parámetros de la red.