4.6 Cómo implementar estrategias en lenguaje C++

El autor:La bondad, Creado: 2019-05-06 13:00:27, Actualizado:

Resumen de las actividades

En el artículo anterior, explicamos la premisa de la implementación de la estrategia comercial desde la introducción del lenguaje C ++, la gramática básica y la estructura de la estrategia.

Introducción a la estrategia

Uno de los indicadores más utilizados en el análisis técnico, KDJ, fue reconocido por la mayoría de los operadores de todo el mundo. El nombre completo de KDJ es Random indicator, que era un indicador de análisis técnico muy novedoso y práctico utilizado en el mercado de futuros de productos básicos. También se utilizó ampliamente en el análisis de tendencias a corto plazo de acciones y bolsas de divisas.

KDJ se basó en la teoría estadística, un valor aleatorio (RSV) se calculó por la relación de los últimos 9 K líneas precio más alto, más bajo y de cierre. luego calcular el valor K, valor D y valor J de acuerdo con el promedio móvil, y dibujar un gráfico para juzgar la tendencia del precio.

img

Al combinar las ventajas del concepto de impulso, el indicador de fuerza y el promedio móvil, medimos el grado de variación del precio de las acciones desde el movimiento del rango normal. Cuando el valor K es mayor que el valor D, indica que el precio de las acciones está actualmente en una tendencia al alza. Por lo tanto, cuando la línea K cruza la línea D de abajo hacia arriba, es el momento de comprar la acción. Por el contrario, cuando el valor K es menor que el valor D, indica que el mercado de valores está actualmente en una tendencia a la baja. Por lo tanto, cuando la línea K cruza la línea D de arriba hacia abajo, es el momento de vender la acción.

Método de cálculo del indicador KDJ

El cálculo del indicador KDJ es complicado. Primero se calcula el valor aleatorio (RSV), y luego se calcula el valor K, el valor D y el valor J. Su método de cálculo es el siguiente:

  • RSV = (precio de cierre - precio más bajo del período N) / (precio más alto de N ciclos - precio más bajo de N ciclos) * 100

  • Valor K = media de los ciclos N RSV

  • D valor = la media de los N ciclos K

  • Valor J = 3 * valor K -2 * valor D

void main(){ // the program starts from this main function
    while (true){ // enter the loop
        auto ct = exchange.SetContractType(symblo); //set the contract type
        auto r = exchange.GetRecords(); // get the K line array
        auto arr = TA.KDJ(r, 9, 3, 3); // calculate the KDJ indicator 
        auto k = arr[0]arr[0].size() - 2]; // get the previous k line KDJ indicator K value
        auto d = arr[1]arr[1].size() - 2]; // get the previous k line KDJ indicator D value
        auto j = arr[2]arr[2].size() - 2]; // get the previous k line KDJ indicator J value
    }
}

Estrategia lógica

Hay muchas maneras de usar KDJ, que se pueden usar solos o en combinación con otros indicadores. En este artículo lo usaremos de la manera más simple, que son: Si el valor K es mayor que el valor D, creemos que el poder de compra se está fortaleciendo, se ha formado una ola de mercado ascendente, y se genera la señal de posición larga de apertura; si el valor K es menor que el valor D, creemos que el poder de venta se está fortaleciendo, y se ha formado una ola de tendencia a la baja, se genera la señal de apertura de posición corta.

img

Si el valor de D cambia de arriba a abajo después de que se abre la posición, creemos que el poder de compra se está debilitando, o el poder de venta se está fortaleciendo, y se genera la señal de cierre de la posición larga; si se abre la posición corta, el valor de D cambia de abajo a arriba, creemos que la fuerza del poder de venta se está debilitando, o que el poder de compra se está fortaleciendo, y se generan señales de cierre de la posición corta.

Condiciones de negociación

  • Posición larga abierta: si no existe posición y el valor K es mayor que el valor D

  • Posición corta: si no existe posición y el valor K es inferior al valor D

  • Cierre de posiciones largas: si existe una posición larga mantenida y el valor D es menor que el valor D de la línea K permeable

  • Posición corta de cierre: si hay una posición corta mantenida y el valor D es mayor que el valor D de la línea K permeable

Aplicación del código de estrategia

El primer paso en la implementación de una estrategia con código es primero considerar qué datos necesitamos? a través de qué API para obtener? después de que obtengamos los datos, cómo calcular la lógica de negociación?

Paso 1: utilizar la arquitectura de estrategias y la biblioteca de clases comerciales

La llamada arquitectura de estrategia es la forma de diseñar toda la estrategia. Como se muestra a continuación, la arquitectura consta de dos funciones: una es la función principal, el programa comienza desde la función principal, y su función es tratar con el núcleo de la lógica de la estrategia. cosas como: juzgar si la conexión con el intercambio está bien, filtrar información de registro innecesaria, controlar el intervalo de tiempo de ejecución de los núcleos de la lógica de la estrategia; y el otro es la función onTick, en esta función, principalmente es la lógica de la estrategia, que comprende: Obtener datos en bruto, calcular datos, colocar órdenes y más.

bool onTick(){  // onTick function
    // strategy logic
}

void main(){ // program starts from here
    while (true){  // enter the loop
        if (exchange.IO("status") == 0) // if the connection with the exchange if not stable.
            sleep(1000); // pause for 1 second
            continue; // skip this loop, enter the next loop
        }
        if(!onTick()){ // if the connection with the exchange is stable, enter this if loop, start executing the onTick function
            sleep(1000); // pause for 1 second
        }
    }
} 

El código anterior es el marco de estrategia C ++ que fue creado por las herramientas de la plataforma FMZ Quant. Este es un formato de codificación fijo, toda la lógica de negociación comienza desde la línea 2 y no se hacen cambios en ningún otro lugar. Además, si eres un veterano, puedes agregar o modificar las características según tu necesidad.

Puede pensar en la biblioteca de clase de trading como un módulo funcional. La ventaja de usar una biblioteca de clase de trading es que le permite centrarse en escribir lógica de estrategia. Por ejemplo, cuando usamos la biblioteca de clase de trading, para abrir o cerrar una posición, podemos usar directamente la interfaz API en la biblioteca de clase de trading; pero si no usamos la biblioteca de clase de trading, necesitamos obtener el precio de mercado al abrir la posición. Necesitamos considerar el tema de las órdenes no ejecutadas y el tema de las órdenes de retiro, y así sucesivamente.

Paso 2: Obtener todo tipo de datos

Los diversos datos en bruto son una parte importante de la lógica de negociación. ¿Qué tipo de datos necesitamos? Desde nuestra lógica de negociación estratégica, primero necesitamos obtener datos de la línea K. Con los datos originales de la línea K, podemos calcular el indicador KDJ y, finalmente, comparar la relación entre el valor K y el valor D para determinar si se deben realizar órdenes.

  • Obtenga los datos de la línea K.

Primero, necesitamos obtener la matriz de línea K, porque la matriz de línea K se utilizará para calcular el indicador KDJ. como sigue:

double position = 0; // position status parameter, the default is 0 

bool onTick(string symbol){ // onTick function, all strategy logic are in this function
    auto ct = exchange.SetContractType(symbol); // set the contract type and trading variety
    if(ct == false){ // if the setting contract type and trading variety is not successful 
        return false; // return false
    }
    auto r = exchange.GetRecords(); // get the k-line array
    if(!r.Valid || r.size() < 10){ // if getting the k-line array or the number of k-line is less than 10
        return false; // return false
    }
}

void main(){ // program starts from here
    while (true){  // enter the loop
        if (exchange.IO("status") == 0) // if the connection with the exchange if not stable.
            sleep(1000); // pause for 1 second
            continue; // skip this loop, enter the next loop
        }
        if(!onTick("this_week")){ // if the connection with the exchange is stable, enter this if loop, start executing the onTick function
            sleep(1000); // pause for 1 second
        }
    }
} 

Como se muestra anteriormente:

Línea 1: Define una variable que se utiliza para recibir el estado de la posición.

Líneas 3 a 12: se define una función onTick, y esta función lleva un parámetro. Este parámetro se pasa en la variedad de negociación, en este caso, utilizando la línea k semanal.

Líneas 14 a 24: Define una función principal que maneja la lógica no estratégica. Lo único que se puede cambiar es el código de contrato this_week en la línea 20, que no necesita ser modificado en otro lugar, ya que este es un formato fijo.

Vamos a centrarnos en la función onTick y ver cómo obtiene los datos de la línea K:

Líneas 4 a 7 : establecer el tipo de contrato y la variedad de negociación, si no se cumple el tipo de contrato y la variedad de negociación, devolver false

Línea 8: Obtener una matriz K-línea, que es un formato fijo.

Líneas 9 a 11: Filtrar la longitud de la línea K, porque el parámetro que usamos para calcular el indicador KDJ es 9. Cuando el número de líneas K es menor que 9, es imposible calcular el indicador KDJ. Así que aquí queremos filtrar la longitud de la línea K. Si la línea K es menor que 10, solo devuelva falso directamente y continúa esperando la próxima línea K.

  • Obtener indicadores de KDJ, valor K y valores D

A continuación, necesitamos calcular los valores K y D del indicador KDJ. Primero es necesario obtener una matriz de indicadores KDJ, y obtener valores K y valores D de esta matriz. En la plataforma FMZ Quant, obtener la matriz de KDJ es muy simple, simplemente llame a la API de KDJ, la dificultad es obtener el valor de los valores K y D, porque la matriz KDJ es una matriz bidimensional.

La matriz bidimensional es realmente fácil de entender, que es una matriz de matriz, las secuencias de obtención son: primero obtener la matriz especificada en la matriz, y luego obtener el elemento especificado de la matriz especificada, como se muestra a continuación:

#include <iostream>
using namespace std;

int main(){
    int hour [3][2] = {{100, 50}, {66, 88}, {10, 90}};
    cout << hours[0][0]; // get the hours array first elements of first element, the result is 100
    cout << hours[0][1]; // get the hours array first elements of second element, the result is 50
    cout << hours[1][0]; // get the hours array second elements of first element, the result is 66
    return(0);
}

Como se muestra a continuación, la línea 12 utiliza directamente la API del FMZ Quant para obtener una matriz de indicadores KDJ, que es una matriz bidimensional: arr = [[valor K, valor K, valor K...], [valor D, valor D, valor D...], [valor J, valor J, valor J...]]

La línea 13 es obtener el valor k de la línea K anterior, el valor K es arr[0], luego obtener el penúltimo elemento de arr[0], arr[0].size() se puede utilizar para adquirir la longitud de la matriz de arr[0], arr[0].size() - 2 es el segundo último elemento de la matriz, ponerlo juntos son: auto k = arr [0] [arr [0].size () - 2 ]; las líneas 14 y 15 son el mismo cálculo.

double position = 0; // position status parameter, the default is 0 

bool onTick(string symbol){ // onTick function, all strategy logic are in this function
    auto ct = exchange.SetContractType(symbol); // set the contract type and trading variety
    if(ct == false){ // if the setting contract type and trading variety is not successful 
        return false; // return false
    }
    auto r = exchange.GetRecords(); // get the k-line array
    if(!r.Valid || r.size() < 10){ // if getting the k-line array or the number of k-line is less than 10
        return false; // return false
    }
    auto arr = TA.KDJ(r, 9, 3, 3); // calculate the KDJ indicator 
    auto k = arr[0][arr[0].size() - 2]; // get the K value of the previous K line 
    auto d = arr[1][arr[1].size() - 2]; // get the D value of the previous K line
    auto dPre = arr[1][arr[1].size() - 3]; // get the D value of the second last of the K line
}

void main(){ // program starts from here
    while (true){  // enter the loop
        if (exchange.IO("status") == 0) // if the connection with the exchange if not stable.
            sleep(1000); // pause for 1 second
            continue; // skip this loop, enter the next loop
        }
        if(!onTick("this_week")){ // if the connection with the exchange is stable, enter this if loop, start executing the onTick function
            sleep(1000); // pause for 1 second
        }
    }
} 

Paso 3: Poner órdenes

Con los datos anteriores, podemos escribir la lógica de negociación y la parte de la orden de colocación ahora. También es muy simple, la más comúnmente utilizada es la declaración if, que se puede describir como: si la condición 1 y la condición 2 son ciertas, coloque el pedido; si la condición 3 o la condición 4 son ciertas, coloque el pedido. Como se muestra a continuación:

double position = 0; // position status parameter, the default is 0 

bool onTick(string symbol){ // onTick function, all strategy logic are in this function
    auto ct = exchange.SetContractType(symbol); // set the contract type and trading variety
    if(ct == false){ // if the setting contract type and trading variety is not successful 
        return false; // return false
    }
    auto r = exchange.GetRecords(); // get the k-line array
    if(!r.Valid || r.size() < 10){ // if getting the k-line array or the number of k-line is less than 10
        return false; // return false
    }
    auto arr = TA.KDJ(r, 9, 3, 3); // calculate the KDJ indicator 
    auto k = arr[0][arr[0].size() - 2]; // get the K value of the previous K line 
    auto d = arr[1][arr[1].size() - 2]; // get the D value of the previous K line
    auto dPre = arr[1][arr[1].size() - 3]; // get the D value of the second last of the K line
    string action; // define a string variable action
    // if currently holding long position, and the previous K line's D value is less than the second last k line's D value, close all position
    // if currently holding short position, and the previous K line's D value is greater than the second last k line's D value, close all position
    if((d < dPre && position > 0) || (d > dPre && position <0)){
        action = "cover";
    }else if (k > d && position <= 0){ // if the previous K line's K value is greater than the previous K line's D value, and there are no long positions
        action = "buy"; // set the variable action to "buy"
    }else if (k < d && position >= 0){ // if the previous K line's K value is less than the previous K line's D value, and there are no short positions
        action = "sell"; // set the variable action to "sell"
    }
    if (action.size() > 0){ // if there are placing order instruction
        position = ext::Trade(action, symbol, 1); // calling the C++ trading class library, placing orders according the direction of variable "action". and also renew the position status. 
    }
    return true; // return true
    } 
}

void main(){ // program starts from here
    while (true){  // enter the loop
        if (exchange.IO("status") == 0) // if the connection with the exchange if not stable.
            sleep(1000); // pause for 1 second
            continue; // skip this loop, enter the next loop
        }
        if(!onTick("this_week")){ // if the connection with the exchange is stable, enter this if loop, start executing the onTick function
            sleep(1000); // pause for 1 second
        }
    }
} 

En el código anterior, las líneas 19 a 28 son la lógica de negociación y el código para colocar órdenes. Sin embargo, antes de esto, necesitamos definir una variable de cadena "acción" en la línea 16, que se utiliza para ayudar a determinar la acción de la orden.

La línea 19 a la línea 21 son: si actualmente se mantiene una posición larga, y el valor anterior de la línea Ks D es menor que el segundo último valor de la línea ks D, cierre toda la posición, si actualmente se mantiene una posición corta, y el valor anterior de la línea Ks D es mayor que el segundo último valor de la línea ks D, cierre toda la posición. y cambie la variable acción a cover.

Las líneas 21 a 25 son: las condiciones para abrir una posición larga y corta.

La línea 26 a la línea 28 ejecutan la lógica de orden de colocación. En primer lugar, de acuerdo con la longitud de la variable de cadena action, se juzga si hay una instrucción para colocar órdenes. Si existe, el código entrará en la línea 27, y luego llamará a la biblioteca de clases de comercio FMZ Quant, preformando las funciones de orden de colocación.

Hay dos lugares que hay que tener en cuenta:

  1. Intentar (pero no necesariamente) escribir la lógica de la estrategia a medida que se establece la condición actual de la línea K, y luego colocar el pedido en la siguiente línea K. O la condición anterior de la línea K se establece, colocando pedidos en la línea K actual, de esta manera, el resultado de la prueba de retroceso y el rendimiento real del mercado no son muy diferentes.

  2. En general, la lógica de posición de cierre debe escribir frente a la lógica de posición de apertura. El propósito de esto es tratar de hacer que la lógica de estrategia cumpla con sus expectativas. Por ejemplo, si la lógica de estrategia sólo cumple con la situación en la que necesita hacer la dirección opuesta de la negociación después de cerrar una posición, la regla de este tipo de situación es cerrar la posición primero y luego abrir la nueva posición. Si escribimos la lógica de posición de cierre frente a la lógica de posición de apertura, se cumplirá perfectamente esta regla.

En resumen

En la sección anterior aprendimos cómo analizar los indicadores técnicos de KDJ y convertirlos en una estrategia de negociación cuantitativa completa. Incluyendo: introducción de la estrategia, método de cálculo del indicador de KDJ, lógica de estrategia, condiciones de negociación, implementación del código de estrategia, etc. A través de este caso de estrategia, no solo nos familiarizamos con el método de programación C ++ en la plataforma FMZ Quant, sino que también las diferentes estrategias se pueden adaptar de acuerdo con los casos en esta sección.

Para lograr una estrategia de negociación cuantitativa es resumir nuestra propia experiencia o sistema de negociación subjetivo, y luego obtener los datos en bruto requeridos por separado, y calcular los datos necesarios para la lógica de la estrategia, y finalmente llamar a la API de órdenes de colocación para realizar la negociación.

Notificación de la siguiente sección

Hasta ahora, el tutorial de escritura de estrategias en esta serie ha llegado a su fin, creo que si sigues el tutorial paso a paso que te lleva aquí, ganarás mucho. En cualquier caso, desde la perspectiva de los cursos básicos de comercio cuantitativo, el largo camino ha ido más de la mitad. En el último capítulo, te enseñaremos cómo usar las herramientas de trading de backtesting de FMZ Quant, y cómo evitar los agujeros en el backtesting y hacer los preparativos finales para el trading de mercado real. Aunque es una pequeña parte del contenido, es un gran paso para entrar en el mundo del trading cuantitativo!

Ejercicios extraescolares

  1. Trate de implementar el algoritmo de indicadores KDJ utilizando el lenguaje C ++ en la plataforma FMZ Quant.

  2. Trate de utilizar los conocimientos de esta sección para elaborar una estrategia de indicadores de CCI.


Más.