La experiencia en el desarrollo de estrategias de negociación

El autor:Un sueño pequeño., Creado: 2019-08-06 17:15:13, Actualizado: 2023-10-20 20:06:49

img

La experiencia en el desarrollo de estrategias de negociación

El objetivo de este artículo es contar algunas experiencias en el desarrollo de estrategias, así como pequeños trucos que pueden ayudar al lector a obtener una idea rápida del desarrollo de estrategias comerciales. Cuando se encuentran con problemas similares de detalle en el diseño de la estrategia, se pueden idear soluciones razonables de inmediato. La plataforma de comercio cuantificado de los inventores es una plataforma para enseñar, probar y practicar. Lenguaje de programación estratégico: JavaScript Mercado de operaciones: el mercado de activos de blockchain (BTC, ETH, etc.)

  • Acceso y tratamiento de datos

    Generalmente, según la lógica de la estrategia, es posible obtener datos de mercado con las siguientes interfaces diferentes, ya que la lógica de negociación de las estrategias generalmente está impulsada por los datos de mercado. (Por supuesto, también hay algunas estrategias que no se fijan en el mercado, como las estrategias de apuestas fijas).

    • GetTicker: Obtener ticks en tiempo real. Generalmente se usa para obtener rápidamente los precios más recientes actuales, comprar a un precio, vender a un precio.

    • GetDepth: Obtención de pedidos de mercado de poca profundidad. Generalmente se usa para obtener precios por paquete, tamaño de pedido y cantidad de pedido. Para hacer estrategias de cobertura, hacer estrategias de mercado, etc.

    • GetTrade: Obtener los registros de transacciones más recientes en el mercado. Generalmente se utiliza para analizar el comportamiento del mercado en un corto período de tiempo, para analizar los cambios microscópicos del mercado. Se usa generalmente para estrategias de alta frecuencia, estrategias de algoritmos.

    • GetRecords: obtener datos de línea K del mercado. Se utiliza comúnmente como estrategia de seguimiento de tendencias. Para el cálculo de los indicadores.

    • No hay razón.

      En el diseño de la estrategia, los principiantes suelen pasar por alto los errores, intuitivamente pensando que el resultado de cada uno de los enlaces de la estrategia está establecido. Pero en realidad no es así. En el funcionamiento de los programas de estrategia, también se encuentran situaciones inesperadas cuando se solicitan datos de mercado. Por ejemplo, algunas interfaces de mercado devuelven datos inusuales:

      var depth = exchange.GetDepth()
      
      // depth.Asks[0].Price < depth.Bids[0].Price      卖一价格低于了买一价格,这种情况不可能存在于盘面上,
      //                                                因为卖出的价格低于买入的价格,必定已经成交了。
      // depth.Bids[n].Amount = 0                       订单薄买入列表第n档,订单量为0
      // depth.Asks[m].Price = 0                        订单薄卖出列表第m档,订单价格为0
      

      O puede ser directamente exchange.GetDepth() devuelve el valor null.

      Hay muchas situaciones extrañas como esta. Por lo tanto, es necesario hacer frente a estos problemas previsibles, y este tipo de tratamiento se llama tratamiento de errores.

      La forma habitual de manejar el error es desechar los datos y recuperarlos.

      Por ejemplo:

      function main () {
          while (true) {
              onTick()
              Sleep(500)
          }
      }
      
      function GetTicker () {
          while (true) {
              var ticker = exchange.GetTicker()
              if (ticker.Sell > ticker.Buy) {       // 以 检测卖一价格是不是小于买一价这个错误的容错处理为例,
                                                    // 排除这个错误,当前函数返回 ticker 。
                  return ticker
              }
              Sleep(500)
          }
      }
      
      function onTick () {
          var ticker = GetTicker()                  // 确保获取到的 ticker 不会存在 卖一价格小于买一价格这种数据错误的情况。
          // ...  具体的策略逻辑
      }
      

      Otras soluciones de errores previsibles pueden usarse de manera similar. El principio de diseño es que absolutamente no se puede dar datos erróneos para conducir la lógica estratégica.

    • Uso de datos de línea K

      Se obtienen datos de línea K y se llama:

      var r = exchange.GetRecords()
      

      El resultado de la línea K es una matriz, por ejemplo, algo así:

      [
          {"Time":1562068800000,"Open":10000.7,"High":10208.9,"Low":9942.4,"Close":10058.8,"Volume":6281.887000000001},
          {"Time":1562072400000,"Open":10058.6,"High":10154.4,"Low":9914.5,"Close":9990.7,"Volume":4322.099},
          ...
          {"Time":1562079600000,"Open":10535.1,"High":10654.6,"Low":10383.6,"Close":10630.7,"Volume":5163.484000000004}
      ]
      

      Se puede ver cada paréntesis.{}El medio incluye el tiempo, el precio abierto, el precio máximo, el precio mínimo, el precio de cierre, el volumen. Este es un pilar de la línea K. Los datos generales de la línea K se utilizan para calcular indicadores, por ejemplo: línea media MA, MACD, etc. Introduzcamos los datos de la línea K como parámetros (datos de las materias primas) y establecemos los parámetros de los indicadores para calcular las funciones de los datos de los indicadores, que llamamos funciones de indicadores. Hay muchas funciones de indicadores en las plataformas de comercio cuantitativo de los inventores.

      Por ejemplo, calculamos el indicador de la línea uniforme, según el ciclo de los datos de la línea K que hemos transmitido, lo que se calcula es la línea media del ciclo correspondiente. Por ejemplo, si se transmite datos de la línea K diaria (una columna de K representa un día), se calcula la línea media diaria, lo mismo que si se transmite datos de la línea K de la función de indicadores de la línea media de 1 hora, entonces se calcula la línea media de 1 hora.

      Normalmente, cuando se calcula un indicador, se suele pasar por alto un problema: si tengo que calcular un indicador de la línea media de 5 días, primero tenemos que preparar los datos de la línea K:

      var r = exchange.GetRecords(PERIOD_D1)  // 给GetRecords 函数传入参数 PERIOD_D1就是指定获取日K线,
                                              // 具体函数使用可以参看:https://www.fmz.com/api#GetRecords
      

      Con los datos de la línea K del día, podemos calcular el indicador de la línea media, y si vamos a calcular la línea media de 5 días, entonces tenemos que establecer el parámetro del indicador de la función del indicador a 5.

      var ma = TA.MA(r, 5)        // TA.MA() 就是指标函数,用来计算均线指标,第一个参数设置刚才获取的日K线数据r,
                                  // 第二个参数设置5,计算出来的就是5日均线,其它指标函数同理。
      

      ¿Qué hacemos si hay menos de 5 columnas de K en los datos de la línea K de r días, si se puede calcular un indicador de la línea media de 5 días eficaz? La respuesta es que no. Como el indicador de la línea media es el valor medio del precio de cierre de un cierto número de columnas de la línea K.

      img

      Por lo tanto, antes de usar datos de línea K para calcular datos de línea, se debe determinar si el número de columnas de línea K en los datos de línea K cumple con las condiciones para calcular los indicadores (parámetros de indicadores).

      Así que antes de calcular la línea media de 5 días, a juzgar, el código completo es el siguiente:

      function CalcMA () {
          var r = _C(exchange.GetRecords, PERIOD_D1)     // _C() 是容错函数,目的就是避免 r 为 null , 具体可以查询文档:https://www.fmz.com/api#_C
          if (r.length > 5) {
              return TA.MA(r, 5)                         // 用均线指标函数 TA.MA 计算出均线数据,做为函数返回值,返回。
          }
      
          return false 
      }
      
      function main () {
          var ma = CalcMA()
          Log(ma)
      }
      

      img

      Los resultados muestran: [null, null, null, null, 4228.7, 4402.9400000000005,... ]

      Se puede ver que el indicador de la línea media de 5 días calculado, los primeros 4 son nulos, es decir, porque el número de columnas de la línea K es inferior a 5, no se puede calcular el valor medio.

    • Un pequeño truco para determinar la actualización de la línea K

      A menudo hay escenarios en los que escribimos algunas políticas y tenemos que procesar algunas operaciones o imprimir algunos registros cuando se completa cada ciclo de K-line. Para los principiantes que no tienen experiencia en programación, es posible que no sepan qué mecanismo usar para manejarlo, y aquí les damos algunos consejos.

      Decidimos que un ciclo de K columnas está terminado, podemos comenzar con la propiedad de tiempo en los datos de K columnas, y cada vez que obtenemos datos de K columnas, determinamos si el valor de la propiedad Time ha cambiado en los datos del último K columnas de los datos de K columnas, si es que hay un cambio, significa que hay un nuevo K columnas generadas (lo que demuestra que el ciclo de K columnas anteriores a los nuevos K columnas se ha completado), si no hay cambios, significa que no hay un nuevo K columnas generadas el último actual (el ciclo de K columnas no se ha completado).

      Así que tenemos que tener una variable para registrar el tiempo de la última columna de la línea K de datos.

      var r = exchange.GetRecords()
      var lastTime = r[r.length - 1].Time       // lastTime 用来记录最后一根K线柱的时间。
      

      En la práctica, la estructura es generalmente la siguiente:

      function main () {
          var lastTime = 0
          while (true) {
              var r = _C(exchange.GetRecords)
              if (r[r.length - 1].Time != lastTime) {
                  Log("新K线柱产生")
                  lastTime = r[r.length - 1].Time      // 一定要更新 lastTime ,这个至关重要。
      
                  // ... 其它处理逻辑
                  // ...
              }
      
              Sleep(500)
          }
      }
      

      img

      Como se puede ver en la revisión, el ciclo de K líneas está configurado para el día (exchange.GetRecords no especifica parámetros cuando se llama la función, es el parámetro predeterminado según el ciclo de K líneas configurado para la revisión), y se imprime un registro cada vez que aparece un nuevo pilar de K.

  • Calculación numérica

    • Calcula el tiempo de acceso a las interfaces de los intercambios

      Si desea tener una cierta visualización o control sobre el tiempo de uso de la interfaz para acceder a una bolsa estratégica, puede usar el siguiente código:

      function main () {
          while (true) {
              var beginTime = new Date().getTime()
              var ticker = exchange.GetTicker()
              var endTime = new Date().getTime()
      
              LogStatus(_D(), "GetTicker() 函数耗时:", endTime - beginTime, "毫秒")
              Sleep(1000)
          } 
      }
      

      En pocas palabras, se calcula la cantidad de milisegundos de experiencia, es decir, el tiempo que tarda la función GetTicker en ejecutarse y devolver el resultado, utilizando el tiempo registrado después de la llamada de la función GetTicker menos el tiempo registrado antes de la llamada.

    • Usar Math.min / Math.max para limitar el valor de las cifras

      Si se desea que el valor tenga un límite, se suele usar el límite de Math.min.

      Por ejemplo, en el proceso de venta, la cantidad de monedas vendidas no debe ser mayor que la cantidad de monedas en la cuenta. Si el número de monedas disponibles en la cuenta es mayor que el número de monedas disponibles en la cuenta, la orden se volverá incorrecta.

      La mayoría de las veces se controla de esta manera: Por ejemplo, el plan de rebaja de la orden de 0.2 monedas.

      var planAmount = 0.2
      var account = _C(exchange.GetAccount)
      var amount = Math.min(account.Stocks, planAmount)
      

      Esto garantiza que el monto de la orden que se va a realizar no exceda el número de monedas disponibles en la cuenta.

      Del mismo modo, Math.max se utiliza para asegurar el límite inferior de un valor numérico. ¿Cuál es el escenario en el que esto suele aplicarse? En general, los intercambios tienen un límite de volumen de pedido mínimo para ciertos pares de transacciones, y rechazan el pedido si está por debajo de este volumen de pedido mínimo. Supongamos que el mínimo de BTC es normalmente de 0.01. La estrategia de transacción es que a veces es posible obtener menos de 0.01 unidades por el cálculo, por lo que podemos usar Math.max para asegurar el mínimo de unidades.

    • Los precios, el control de precisión.

      Puede utilizar la función _N() o la función SetPrecision para controlar la precisión.

      La función SetPrecision (()) se configura una vez y automáticamente intercepta los dígitos de unidad y precio en exceso en el sistema.

      La función _N() es una función para realizar un corte numérico de cifras de un determinado valor (control de precisión).

      Por ejemplo:

      var pi = _N(3.141592653, 2)
      Log(pi)
      

      El valor de pi es cortado por decimales y se mantiene con dos decimales, es decir: 3.14

      Para más información, consulte el documento de la API.

  • Algunos ajustes lógicos

    • Tiempo de ejecución de algunas operaciones en un ciclo de tiempo determinado

      Se puede utilizar un mecanismo como el de detección de horarios, para determinar el horario actual menos el horario en el que se terminó la última tarea de cronometraje, y calcular en tiempo real el tiempo que ha pasado cuando este tiempo ha superado una longitud de tiempo establecida, es decir, para ejecutar una nueva operación.

      Por ejemplo, en estrategias de inversión.

      var lastActTime = 0
      var waitTime = 1000 * 60 * 60 * 12   // 一天的毫秒数
      function main () {
          while (true) {
              var nowTime = new Date().getTime()
              if (nowTime - lastActTime > waitTime) {
                  Log("执行定投")
                  // ... 具体的定投操作,买入操作。
      
      
                  lastActTime = nowTime
              }
      
              Sleep(500)
          }
      }
      

      Este es un ejemplo sencillo.

    • Diseñar mecanismos de recuperación automática para la estrategia

      Utilizando la función _G ()) cuantificada por el inventor, y la función de salida de la función de conservación, es muy conveniente diseñar una política para salir del progreso de la conservación y reiniciar la función de recuperación automática.

      var hold = {
          price : 0, 
          amount : 0,
      }
      
      function main () {
          if (_G("hold")) {
              var ret = _G("hold")
              hold.price = ret.price
              hold.amount = ret.amount
              Log("恢复 hold:", hold)
          }
      
          var count = 1
          while (true) {
              // ... 策略逻辑
              // ... 策略运行中,可能开仓,交易,把开仓的持仓价格赋值给 hold.price ,开仓的数量赋值给 hold.amount,用以记录持仓信息。
      
              hold.price = count++     // 模拟一些数值
              hold.amount = count/10   // 模拟一些数值
      
              Sleep(500)
          }
      }
      
      function onexit () {    // 点击机器人上的停止按钮,会触发执行这个函数,执行完毕机器人停止。
          _G("hold", hold)
          Log("保存 hold:", JSON.stringify(hold))
      }
      

      img

      Se puede ver que cada vez que el robot se detiene, se guarda los datos en el objeto hold, y cada vez que se reinicia, se lee los datos, restaurando el valor del hold al estado en el que se detuvo antes. Por supuesto, este es un ejemplo sencillo, y si se utiliza en una estrategia práctica, debe diseñarse en función de los datos clave que se requieren para recuperar en la estrategia (generalmente información sobre la cuenta, las tenencias, el valor de las ganancias, la dirección de la operación, etc.). Por supuesto, también se pueden establecer algunas condiciones para que se recupere.

Estos son algunos pequeños trucos para desarrollar estrategias, que espero que sean útiles para los principiantes y los desarrolladores de estrategias. ¡La práctica manual es la mejor manera de progresar!


Relacionados

Más.

- ¿Por qué?Gracias por compartir, es muy adecuado para los principiantes que no entienden el API, también consulte si nuestra plataforma soporta versiones más altas de es, por ejemplo, ¿habéis usado?.

- ¿ Qué?¡Gracias Dreamweaver! Dreamweaver, es un maestro muy bueno, tiene una alta tecnología de programación, un buen artículo y una buena lectura, ¡muy bueno para admirar!

Un sueño pequeño.Hola, ahora soportamos el estándar ES8.

Un sueño pequeño.¡Gracias por apoyar la cuantificación FMZ!