
Filtrage des Signaux en Fonction des Données Statistiques de la Corrélation des Prix.
Comment cela a commencé
L'idée qui a conduit à la rédaction de cet article est apparue après avoir lu le livre de Larry Williams" de Long-Term Secrets court terme trading ", dans laquelle le détenteur du record du monde des investissements (au cours de 1987, il a augmenté son capital de 11 000%) défait complètement les mythes de "... des professeurs d'université et d'autres universitaires, riches en théorie et pauvres en connaissance du marché..." sur l'absence de corrélation entre le comportement passé des prix et les tendances futures.
Si vous lancez une pièce 100 fois, elle tombera 50 fois pile et 50 fois pile. À chaque lancer successif, la probabilité de pile est de 50 %, la même que celle de pile. La probabilité ne change pas d'un lancer à l'autre, car ce jeu est aléatoire et n'a pas de mémoire. Admettons que les marchés se comportent comme une pièce de monnaie, de manière chaotique.
Par conséquent, lorsqu'une nouvelle barre apparaît, un prix a la même chance de monter ou de descendre, et les barres précédentes n'affectent même pas le moins du monde la barre actuelle. Idylle! Créez un système de trading, définissez un bénéfice supérieur au stop loss (c'est-à-dire, définissez l'attente mathématique sur la zone positive), et le tour est joué. Tout simplement époustouflant. Cependant, le problème est que notre hypothèse sur le comportement du marché n'est pas tout à fait vraie. Franchement, c'est absurde ! Et je vais le prouver.
Créons un modèle Expert Advisor à l'aide de l'assistantMQL5 et en utilisant des interventions alphanumériques simples, présentons-le dans un état adapté à l'accomplissement de la tâche. Nous encoderons un Expert Advisor pour simuler l'achat qui suit une, deux et trois barres clôturées. La simulation indique que le programme se souviendra simplement des paramètres des barres analysées. L'envoi d'ordres (une manière plus habituelle) dans ce cas ne fonctionnera pas, car les spreads et les swaps peuvent remettre en cause la fiabilité des informations reçues.
Voici le code :
//+------------------------------------------------------------------+ //| explorer.mq5 | //| Copyright 2011, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2011, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" //---Variables--- double profit_percent,open_cur,close_cur; double profit_trades=0,loss_trades=0,day_cur,hour_cur,min_cur,count; double open[],close[]; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { return(0); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { /* Calculate percent of closures with increase from the total number */ profit_percent=NormalizeDouble(profit_trades*100/(profit_trades+loss_trades),2); Print("Percent of closures with increase ",profit_percent,"%"); // Enter data to the Journal } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //---find out the time--- MqlDateTime time; // Create a structure to store time TimeToStruct(TimeCurrent(),time); // Structuring the data day_cur=time.day_of_week; // Receive the value of the current day hour_cur=time.hour; // Receive the current hour min_cur=time.min; // Receive the current minute //---Find out the prices--- CopyOpen(NULL,0,0,4,open);ArraySetAsSeries(open,true); CopyClose(NULL,0,0,4,close);ArraySetAsSeries(close,true); if(close[1]<open[1]/*&&close[2]<open[2]&&close[3]<open[3]*/ && count==0) // If it closed with a loss { open_cur=open[0]; // Remember open price of the current bar count=1; } if(open_cur!=open[0] && count==1) // The current bar has closed { close_cur=close[1]; // Remember the close price of the formed bar count=0; if(close_cur>=open_cur)profit_trades+=1; // If the close price is higher than open, else loss_trades+=1; // +1 to closures with profit, otherwise +1 to closures with loss } } //+------------------------------------------------------------------+
Le test sera réalisé sur l'EUR/USD, sur l'intervalle du 1er janvier 2000 au 31 décembre 2010 :
.
Figure 1. Le pourcentage de clôtures avec l'augmentation
(La première colonne affiches les données pour toute la période, les deuxième, troisième et quatrième - après une clôture simple, double et triple)
C'est de cela que je parlais ! Les barres précédentes ont un impact assez important sur l'actuelle, car le prix cherche toujours à récupérer les pertes.
Un autre pas en avant
Super! Une fois que nous nous assurons que le comportement des prix n'est pas accidentel, nous devons utiliser ce fait étonnant dès que possible. Bien sûr, ce n'est pas suffisant pour un système de trading indépendant, mais ce sera un bel outil qui pourra vous libérer des signaux fastidieux et souvent erronés. Mettons-le en œuvre !
Voilà donc ce qu'il nous faut :
- Un système d'auto-trade, affichant des résultats positifs au moins pour la dernière année.
- Quelques exemples amusants qui confirment la présence de corrélations dans le comportement des prix.
J'ai trouvé beaucoup d'idées utiles dans le livre de L. Williams. Je vais partager l'un d'eux avec vous.
La stratégie TDW (Trade Day Of Week). Cela nous permettra de voir ce qui se passera si certains jours de la semaine nous n'achetons que, et les autres - n'ouvrent que des courtes positions.. Après tout, nous pouvons admettre que le prix au cours d'une journée augmente dans un plus grand pourcentage de cas que dans l'autre. Quelle en est la raison ? La situation géopolitique, les statistiques macroéconomiques, ou, comme l'écrit le livre de A. Elder, le lundi et le mardi sont les jours des profanes, tandis que les jeudis et vendredis sont ceux des professionnels ? Tentons de comprendre.
Tout d'abord, nous ne vendrons que chaque jour de la semaine, puis nous ne vendrons que. À la fin de l'étude, nous ferons correspondre les meilleurs résultats, et ce sera un filtre pour notre système de trading. D'ailleurs, j'ai quelques mots à ce sujet. C'est un pur classique !
Le système est basé sur deux MAs et MACDake. Signaux :
- Si la moyenne mobile rapide croise la moyenne lente de bas en haut et que l'histogramme MACD est en dessous de la ligne zéro, alorsBUY .
- Si la moyenne mobile rapide croise la lente à l'envers et que le MACD est au-dessus de zéro, alorsSELL .
Quittez une position en utilisant un stop suiveur à partir d'un point. Le lot est fixe - 0,1.
Par souci de commodité, j'ai placé la classe Expert Advisor dans un fichier d'en-tête séparé :
//+------------------------------------------------------------------+ //| moving.mqh | //| Copyright 2011, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2011, MetaQuotes Software Corp." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| Класс my_expert | //+------------------------------------------------------------------+ class my_expert { // Creating a class // Closed class members private: int ma_red_per,ma_yel_per; // Periods of MAs int ma_red_han,ma_yel_han,macd_han; // Handles double sl,ts; // Stop orders double lots; // Lot double MA_RED[],MA_YEL[],MACD[]; // Arrays for the indicator values MqlTradeRequest request; // Structure of a trade request MqlTradeResult result; // Structure of a server response // Open class members public: void ma_expert(); // Constructor void get_lot(double lot){lots=lot;} // Receiving a lot void get_periods(int red,int yel){ma_red_per=red;ma_yel_per=yel;} // Receiving the periods of MAs void get_stops(double SL,double TS){sl=SL;ts=TS;} // Receiving the values of stops void init(); // Receiving the indicator values bool check_for_buy(); // Checking for buy bool check_for_sell(); // Checking for sell void open_buy(); // Open buy void open_sell(); // Open sell void position_modify(); // Position modification }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ /* Function definition */ //---Constructor--- void my_expert::ma_expert(void) { //--- Reset the values of variables ZeroMemory(ma_red_han); ZeroMemory(ma_yel_han); ZeroMemory(macd_han); } //---The function for receiving the indicator values--- void my_expert::init(void) { ma_red_han=iMA(_Symbol,_Period,ma_red_per,0,MODE_EMA,PRICE_CLOSE); // Handle of the slow MA ma_yel_han=iMA(_Symbol,_Period,ma_yel_per,0,MODE_EMA,PRICE_CLOSE); // Handle of the fast MA macd_han=iMACD(_Symbol,_Period,12,26,9,PRICE_CLOSE); // Handle of MACDaka //---Copy data into arrays and set indexing like in a time-series--- CopyBuffer(ma_red_han,0,0,4,MA_RED); CopyBuffer(ma_yel_han,0,0,4,MA_YEL); CopyBuffer(macd_han,0,0,2,MACD); ArraySetAsSeries(MA_RED,true); ArraySetAsSeries(MA_YEL,true); ArraySetAsSeries(MACD,true); } //---Function to check conditions to open buy--- bool my_expert::check_for_buy(void) { init(); //Receive values of indicator buffers /* If the fast MA has crossed the slow MA from bottom up between 2nd and 3rd bars, and there was no crossing back. MACD-hist is below zero */ if(MA_RED[3]>MA_YEL[3] && MA_RED[1]<MA_YEL[1] && MA_RED[0]<MA_YEL[0] && MACD[1]<0) { return(true); } return(false); } //----Function to check conditions to open sell--- bool my_expert::check_for_sell(void) { init(); //Receive values of indicator buffers /* If the fast MA has crossed the slow MA from up downwards between 2nd and 3rd bars, and there was no crossing back. MACD-hist is above zero */ if(MA_RED[3]<MA_YEL[3] && MA_RED[1]>MA_YEL[1] && MA_RED[0]>MA_YEL[0] && MACD[1]>0) { return(true); } return(false); } //---Open buy--- /* Form a standard trade request to buy */ void my_expert::open_buy(void) { request.action=TRADE_ACTION_DEAL; request.symbol=_Symbol; request.volume=lots; request.price=SymbolInfoDouble(Symbol(),SYMBOL_ASK); request.sl=request.price-sl*_Point; request.tp=0; request.deviation=10; request.type=ORDER_TYPE_BUY; request.type_filling=ORDER_FILLING_FOK; OrderSend(request,result); return; } //---Open sell--- /* Form a standard trade request to sell */ void my_expert::open_sell(void) { request.action=TRADE_ACTION_DEAL; request.symbol=_Symbol; request.volume=lots; request.price=SymbolInfoDouble(Symbol(),SYMBOL_BID); request.sl=request.price+sl*_Point; request.tp=0; request.deviation=10; request.type=ORDER_TYPE_SELL; request.type_filling=ORDER_FILLING_FOK; OrderSend(request,result); return; } //---Position modification--- void my_expert::position_modify(void) { if(PositionGetSymbol(0)==_Symbol) { //If a position is for our symbol request.action=TRADE_ACTION_SLTP; request.symbol=_Symbol; request.deviation=10; //---If a buy position--- if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) { /* if distance from price to stop loss is more than trailing stop and the new stop loss is not less than the previous one */ if(SymbolInfoDouble(Symbol(),SYMBOL_BID)-PositionGetDouble(POSITION_SL)>_Point*ts) { if(PositionGetDouble(POSITION_SL)<SymbolInfoDouble(Symbol(),SYMBOL_BID)-_Point*ts) { request.sl=SymbolInfoDouble(Symbol(),SYMBOL_BID)-_Point*ts; request.tp=PositionGetDouble(POSITION_TP); OrderSend(request,result); } } } //---If it is a sell position--- else if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL) { /* if distance from price to stop loss is more than the trailing stop value and the new stop loss is not above the previous one. Or the stop loss from the moment of opening is equal to zero */ if((PositionGetDouble(POSITION_SL)-SymbolInfoDouble(Symbol(),SYMBOL_ASK))>(_Point*ts)) { if((PositionGetDouble(POSITION_SL)>(SymbolInfoDouble(Symbol(),SYMBOL_ASK)+_Point*ts)) || (PositionGetDouble(POSITION_SL)==0)) { request.sl=SymbolInfoDouble(Symbol(),SYMBOL_ASK)+_Point*ts; request.tp=PositionGetDouble(POSITION_TP); OrderSend(request,result); } } } } } //+------------------------------------------------------------------
Mes humbles hommages à l'auteur de l'article "Writing an Expert Advisor using the MQL5 Object-Oriented Approach". Que ferais-je sans ! Je recommande la lecture de cet article à tous ceux qui ne connaissent pas très bien cette programmation orientée objet maléfique mais extrêmement fonctionnelle.
Ajoutez le fichier avec la classe au code principal de l'Expert Advisor ? créez un objet et initialisez les fonctions :
//+------------------------------------------------------------------+ //| Moving.mq5 | //| Copyright 2011, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2011, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" //---Include a file with the class--- #include <moving.mqh> //---External Variables--- input int MA_RED_PERIOD=7; // The period of a slow MA input int MA_YEL_PERIOD=2; // The period of a fast MA input int STOP_LOSS=800; // Stop loss input int TRAL_STOP=800; // Trailing stop input double LOTS=0.1; // Lot //---Create an object--- my_expert expert; //---Initialize the MqlDataTime structure--- MqlDateTime time; int day_of_week; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //---Initialize the EA expert.get_periods(MA_RED_PERIOD,MA_YEL_PERIOD); // Set the MA periods expert.get_lot(LOTS); // Set the lot expert.get_stops(STOP_LOSS,TRAL_STOP); // Set stop orders return(0); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { TimeToStruct(TimeCurrent(),time); day_of_week=time.day_of_week; if(PositionsTotal()<1) { if(day_of_week==5 && expert.check_for_buy()==true){expert.open_buy();} else if(day_of_week==1 && expert.check_for_sell()==true){expert.open_sell();} } else expert.position_modify(); } //+------------------------------------------------------------------+
Terminé Je voudrais noter quelques spécificités Pour identifier les jours de la semaine au niveau logiciel, j'ai utilisé la structureMqlDateTime . Tout d'abord, nous transformons l'heure actuelle du serveur en un format structuré. Nous obtenons un indice du jour en cours (1-lundi, ..., 5-vendredi) et le comparons avec la valeur que nous avons fixée.
Essayez-en! Afin de ne pas vous alourdir de recherches fastidieuses et de chiffres supplémentaires, j'apporte tous les résultats dans le tableau.
C'est ici:
Tableau 1. Récap des achats tous les jours de la semaine
Tableau 2. Récap des ventes tous les jours de la semaine
Les meilleurs résultats sont surlignés en vert, les pires sont en orange.
Je fais une réserve, qu'après les actions décrites ci-dessus, le système doit assurer un bénéfice en combinaison avec un faible tirage relatif, un bon pourcentage de trades gagnants (ici, moins il y a de transactions, mieux c'est) et un bénéfice par trade relativement élevé.
De toute évidence, le système le plus efficace consiste à acheter le vendredi et à vendre le lundi. Combinez ces deux conditions :
if(PositionsTotal()<1){ if(day_of_week==5&&expert.check_for_buy()==true){expert.open_buy();} else if(day_of_week==1&&expert.check_for_sell()==true){expert.open_sell();}} else expert.position_modify();
Désormais, l'Expert Advisor ouvre des positions dans les deux sens, mais à des jours strictement définis. Pour plus de clarté, je vais dessiner les schémas obtenus sans et avec le filtre :
Figure 2. Les résultats des tests EA sans utiliser de filtre (EURUSD, H1, 01.01.2010-31.12.2010,)
Figure 3. Les résultats des tests EA utilisant le filtre (EURUSD, H1, 01.01.2010-31.12.2010)
Comment appréciez-vous le résultat? En utilisant le filtre, le système de trading est devenu plus stable. Avant les modifications, l'Expert Advisor augmentait principalement le solde dans la première moitié de la période de test, après la "mise à niveau", il augmente tout au long de la période.
Nous comparons les rapports :
Tableau 3. Résultats des tests avant et après utilisation du filtre
Le seul facteur affligeant, qui ne peut être ignoré, est la chute du bénéfice net de près de 1000 USD (26%). Mais nous réduisons le nombre de trades presque à 3,5 fois, c'est-à-dire en réduisant considérablement, d'une part, le potentiel de faire un trade négatif et, d'autre part, les dépenses pour le spread (218*2-62*2=312 USD et c'est uniquement pour EUR/USD). Le pourcentage de gain est porté à 57%, ce qui est déjà considérable. Alors que le bénéfice par trade augmente de 14% à 113 USD. Comme dirait L. Williams : « C'est le montant qui vaut la peine d'être échangé ! »
Conclusion
Les prix ne se comportent pas au hasard - c'est un fait. Ce fait peut et doit être utilisé. Je n'ai donné qu'un seul exemple, qui n'est qu'une infime fraction des innombrables variations et techniques qui peuvent améliorer les performances de votre système de trading. Cependant, cette diversité cache un vice. Pas tous les filtres peuvent être intégrés, ils doivent donc être choisis avec soin, en pensant à tous les scénarios possibles.
N'oubliez pas que peu importe la perfection du filtre, il élimine également les trades rentables, c'est-à-dire votre bénéfice... Bonne chance!
Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/269





- Applications de trading gratuites
- Plus de 8 000 signaux à copier
- Actualités économiques pour explorer les marchés financiers
Vous acceptez la politique du site Web et les conditions d'utilisation