Dans l'article précédent, nous avons expliqué la prémisse de la mise en œuvre de la stratégie de trading à partir de l'introduction du langage C++, de la grammaire de base et de la structure de la stratégie.
L'un des indicateurs les plus couramment utilisés dans l'analyse technique, KDJ, a été reconnu par la plupart des traders du monde entier.
KDJ était basé sur la théorie statistique, une valeur aléatoire (RSV) a été calculée par le rapport entre le prix le plus élevé, le plus bas et le prix de clôture de la ligne 9 K récente. puis calculer la valeur K, la valeur D et la valeur J selon la moyenne mobile, et dessiner un graphique pour juger de l'évolution des prix.
En combinant les avantages du concept de momentum, de l'indicateur de force et de la moyenne mobile, nous mesurons le degré de variation du prix de l'action par rapport au mouvement de la plage normale. Lorsque la valeur K est supérieure à la valeur D, cela indique que le prix de l'action est actuellement en tendance haussière. Par conséquent, lorsque la ligne K traverse la ligne D de bas en haut, il est temps d'acheter l'action. Inversement, lorsque la valeur K est inférieure à la valeur D, cela indique que le marché boursier est actuellement en tendance baissière. Par conséquent, lorsque la ligne K traverse la ligne D de haut en bas, il est temps de vendre l'action.
Le calcul de l'indicateur KDJ est compliqué. Premièrement, la valeur aléatoire (RSV) est calculée, puis la valeur K, la valeur D et la valeur J. Sa méthode de calcul est la suivante:
RSV = (prix de clôture - prix le plus bas de la période N) / (prix le plus élevé de N cycles - prix le plus bas de N cycles) * 100
Valeur K = moyenne des N cycles RSV
D valeur = moyenne de N cycles K
J valeur = 3 * K valeur -2 * D valeur
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
}
}
Il existe de nombreuses façons d'utiliser le KDJ, qui peut être utilisé seul ou en combinaison avec d'autres indicateurs. Dans cet article, nous allons l'utiliser de la manière la plus simple, à savoir: si la valeur K est supérieure à la valeur D, nous pensons que le pouvoir d'achat se renforce, une vague de marché en hausse s'est formée et le signal de position longue d'ouverture est généré; si la valeur K est inférieure à la valeur D, nous pensons que le pouvoir de vente se renforce et une vague de tendance à la baisse a été formée, le signal d'ouverture de position courte est généré.
Si la valeur D change de haut en bas après l'ouverture de la position, nous pensons que le pouvoir d'achat s'affaiblit, ou que le pouvoir de vente se renforce, et le signal de fermeture de la position longue est généré; si la position courte est ouverte, la valeur D change de bas en haut, nous pensons que la force du pouvoir de vente s'affaiblit, ou que le pouvoir d'achat se renforce, et des signaux de fermeture de position courte sont générés.
Position longue ouverte: si aucune position n'existe et que la valeur K est supérieure à la valeur D
Position courte: si aucune position n'existe et que la valeur K est inférieure à la valeur D
Fermeture de positions longues: si une position longue est maintenue et que la valeur D est inférieure à la valeur D de la ligne K perméable
Fermeture de position courte: si une position courte est maintenue et que la valeur de D est supérieure à la valeur de D de la ligne K perméable
La première étape dans la mise en œuvre d'une stratégie avec du code est d'abord de considérer quelles données nous avons besoin? à travers quelle API pour obtenir? après avoir obtenu les données, comment calculer la logique de trading? ensuite, quelle façon de placer les ordres? enfin, laissez-nous l'implémenter étape par étape:
L'architecture dite de stratégie est la façon de concevoir l'ensemble de la stratégie. Comme indiqué ci-dessous, l'architecture se compose de deux fonctions: l'une est la fonction principale, le programme commence à partir de la fonction principale, et sa fonction est de traiter avec le noyau de la logique de stratégie. des choses comme: juger si la connexion avec l'échange est ok, filtrer les informations de journaux inutiles, contrôler l'intervalle de temps d'exécution des noyaux de logique de stratégie; et l'autre est la fonction onTick, dans cette fonction, principalement la logique de stratégie, comprenant: obtenir des données brutes, calculer des données, placer des commandes, et plus encore.
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
}
}
}
Le code ci-dessus est le framework de stratégie C++ créé par les outils de la plateforme FMZ Quant. Il s'agit d'un format de codage fixe, toute la logique de trading commence à partir de la ligne 2 et aucun changement n'est apporté ailleurs.
Vous pouvez considérer la bibliothèque de classe de trading comme un module fonctionnel. L'avantage de l'utilisation d'une bibliothèque de classe de trading est qu'elle vous permet de vous concentrer sur l'écriture de la logique de stratégie. Par exemple, lorsque nous utilisons la bibliothèque de classe de trading, afin d'ouvrir ou de fermer une position, nous pouvons directement utiliser l'interface API dans la bibliothèque de classe de trading; mais si nous n'utilisons pas la bibliothèque de classe de trading, nous devons obtenir le prix du marché lors de l'ouverture de la position.
Les différentes données brutes sont une partie importante de la logique de trading. De quel type de données avons-nous besoin? De notre logique de trading de stratégie, nous devons d'abord obtenir des données de ligne K. Avec les données de ligne K d'origine, nous pouvons calculer l'indicateur KDJ, et enfin comparer la relation entre la valeur K et la valeur D pour déterminer si nous devons passer des ordres.
Tout d'abord, nous devons obtenir la matrice de ligne K, parce que la matrice de ligne K sera utilisé pour calculer l'indicateur KDJ. comme suit:
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
}
}
}
Comme indiqué ci-dessus:
Ligne 1 : Définit une variable utilisée pour recevoir l'état de position.
Les lignes 3 à 12 : Une fonction onTick est définie, et cette fonction porte un paramètre. Ce paramètre doit être passé dans la gamme de négociation, dans ce cas, en utilisant la ligne k hebdomadaire.
Les lignes 14 à 24 : Définir une fonction principale qui gère la logique non stratégique. La seule chose qui peut être modifiée est le code de contrat
Concentrons-nous sur la fonction onTick et voyons comment elle obtient les données de la ligne K:
lignes 4 à 7 : définir le type de contrat et la variété de négociation, si la définition du type de contrat et de la variété de négociation est infructueuse, retourner false
Ligne 8: Obtenez un tableau en ligne K, qui est un format fixe.
Les lignes 9 à 11: Filtrer la longueur de la ligne K, car le paramètre que nous utilisons pour calculer l'indicateur KDJ est 9. Quand le nombre de lignes K est inférieur à 9, il est impossible de calculer l'indicateur KDJ. Donc ici nous voulons filtrer la longueur de la ligne K. Si la ligne K est inférieure à 10, retournez simplement faux directement et continuez à attendre la prochaine ligne K.
Ensuite, nous devons calculer les valeurs K et D de l'indicateur KDJ. Il est nécessaire d'obtenir d'abord un tableau d'indicateurs KDJ, et d'obtenir des valeurs K et D de ce tableau. Sur la plate-forme FMZ Quant, obtenir le tableau de KDJ est très simple, il suffit d'appeler l'API de KDJ, la difficulté est d'obtenir la valeur des valeurs K et D, car le tableau KDJ est un tableau bidimensionnel.
Le tableau bidimensionnel est en fait facile à comprendre, qui est un tableau de tableau, les séquences obtenues sont: d'abord obtenir le tableau spécifié dans le tableau, puis obtenir l'élément spécifié à partir du tableau spécifié, comme indiqué ci-dessous:
#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);
}
Comme indiqué ci-dessous, la 12e ligne utilise directement l'API du FMZ Quant pour obtenir un tableau d'indicateurs KDJ, qui est un tableau bidimensionnel: arr = [[valeur K, valeur K, valeur K...], [valeur D, valeur D, valeur D...], [valeur J, valeur J, valeur J...]]
La ligne 13 est d'obtenir la valeur k de la ligne K précédente, la valeur K est arr[0], puis obtenir l'élément avant-dernier de arr[0], arr[0].size() peut être utilisé pour acquérir la longueur du tableau de arr[0], arr[0].size() - 2 est le deuxième dernier élément du tableau, mis ensemble sont: auto k = arr [0] [arr [0].size () - 2 ]; les lignes 14 et 15 sont le même calcul.
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
}
}
}
Avec les données ci-dessus, nous pouvons écrire la logique de trading et la partie de placement des ordres maintenant. C'est également très simple, le plus couramment utilisé est l'instruction
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
}
}
}
Dans le code ci-dessus, les lignes 19 à 28 sont la logique de négociation et le code pour placer des ordres. Cependant, avant cela, nous devons définir une variable de chaîne " action " sur la ligne 16, qui est utilisé pour aider à déterminer l'action de l'ordre.
La ligne 19 à la ligne 21 sont: si vous détenez actuellement une position longue et que la valeur de D de la ligne K précédente est inférieure à la deuxième dernière valeur de D de la ligne K précédente, fermez toutes les positions, si vous détenez actuellement une position courte et que la valeur de D de la ligne K précédente est supérieure à la deuxième dernière valeur de D de la ligne K précédente, fermez toutes les positions. et changez la variable
Les lignes 21 à 25 sont: les conditions d'ouverture des positions longues et courtes.
La ligne 26 à la ligne 28 exécutent la logique des ordres de placement. Premièrement, selon la longueur de la variable de chaîne
Il y a deux endroits à noter:
Essayez (mais pas nécessairement) d'écrire la logique de stratégie lorsque la condition actuelle de la ligne K est établie, puis placez l'ordre sur la ligne k suivante. Ou la condition précédente de la ligne k est établie, placez des ordres sur la ligne k actuelle, de cette façon, le résultat du backtest et la performance réelle du marché ne sont pas très différents.
En général, la logique de la position de clôture devrait être écrite devant la logique de la position d'ouverture. Le but de cela est d'essayer de faire en sorte que la logique de la stratégie réponde à vos attentes. Par exemple, si la logique de la stratégie répond juste à la situation où elle doit faire le sens inverse de la négociation après avoir juste fermé une position, la règle de ce genre de situation est de fermer la position d'abord et d'ouvrir ensuite la nouvelle position. Si nous écrivons la logique de la position de clôture devant la logique de la position d'ouverture, elle remplira parfaitement cette règle.
Ci-dessus, nous avons appris comment analyser les indicateurs techniques de KDJ et les convertir en une stratégie de trading quantitative complète. y compris: introduction de la stratégie, méthode de calcul de l'indicateur de KDJ, logique de stratégie, conditions de trading, mise en œuvre du code de stratégie, etc. Grâce à ce cas de stratégie, non seulement nous nous familiarisons avec la méthode de programmation C ++ sur la plate-forme FMZ Quant, mais également les différentes stratégies peuvent être adaptées en fonction des cas de cette section.
Pour réaliser une stratégie de trading quantitative, il faut résumer notre propre expérience subjective de trading ou système, puis obtenir les données brutes requises séparément, et calculer les données nécessaires à la logique de stratégie, et enfin appeler l'API de placement des ordres pour réaliser le trading.
Jusqu'à présent, le tutoriel de rédaction de stratégie de cette série est arrivé à son terme, je crois que si vous suivez le tutoriel étape par étape qui vous mène ici, vous gagnerez beaucoup. En tout cas, du point de vue des cours de base de trading quantitatif, le long chemin a été plus de la moitié. Dans le dernier chapitre, nous vous apprendrons à utiliser les outils de trading de backtesting FMZ Quant, et comment éviter les trous dans le backtesting et faire les préparatifs finaux pour le trading réel sur le marché. Bien qu'il s'agisse d'une petite partie du contenu, c'est un grand pas en avant pour entrer dans le monde du trading quantitatif!
Essayez de mettre en œuvre l'algorithme d'indicateur KDJ en utilisant le langage C++ sur la plateforme FMZ Quant.
Essayez d'utiliser les connaissances contenues dans cette section pour élaborer une stratégie d'indicateur de la CCI.