English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Filtraggio dei segnali basati su dati statistici di correlazione dei prezzi

Filtraggio dei segnali basati su dati statistici di correlazione dei prezzi

MetaTrader 5Trading | 17 dicembre 2021, 15:30
112 0
Михаил Тарачков
Михаил Тарачков

Com’è iniziato

L'idea che mi ha portato a scrivere questo articolo è apparsa dopo aver letto il libro di Larry Williams "Long-Term Secrets to Short-Term Trading", in cui il detentore del record mondiale in investimenti (durante il 1987 ha aumentato il suo capitale dell’ 11.000%) sta completamente dissipando i miti con "... professori universitari e altri accademici che sono ricchi di teoria e poveri di conoscenza del mercato ..." sull'assenza di qualsiasi correlazione tra il comportamento passato dei prezzi e le tendenze future.

Se lanci una moneta 100 volte, 50 volte cadrà sulle teste e 50 volte sulle code. Ad ogni lancio successivo, la probabilità delle teste è del 50%, la stessa delle code. La probabilità non cambia da lancio a lancio, perché questo gioco è casuale e non ha memoria. Supponiamo che i mercati si comportino come una moneta, in modo caotico.

Di conseguenza, quando appare una nuova barra, un prezzo ha pari opportunità di salire o scendere e le barre precedenti non influenzano nemmeno minimamente quella attuale. Idillio! Crea un sistema di trading, imposta il take profit più grande dello stop loss (cioè imposta l’aspettativa matematica sulla zona positiva) e il gioco è fatto. Semplicemente mozzafiato. Tuttavia, il problema è che la nostra ipotesi sul comportamento del mercato non è del tutto vera. Francamente parlando, è assurda! E lo dimostrerò.

Creiamo un modello di Expert Advisor utilizzando il Wizard MQL5 e, con semplici interventi alfanumerici, presentiamolo in una condizione adatta all'espletamento dell'attività. Codificheremo un Expert Advisor per simulare l'acquisto che segue una, due e tre barre chiuse. Simulazione significa che il programma ricorderà semplicemente i parametri delle barre analizzate. L'invio di ordini (un modo più usuale) in questo caso non funzionerà, perché gli spread e gli swap sono in grado di mettere in discussione l'affidabilità delle informazioni ricevute.

Ecco il codice:

//+------------------------------------------------------------------+
//|                                                     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
     }
  }
//+------------------------------------------------------------------+

Il test sarà effettuato su EUR/USD, nell'intervallo dal 1 gennaio 2000 al 31 dicembre 2010:

Figura 1. La percentuale di chiusure con l'aumento.

Figura 1. La percentuale di chiusure con l'aumento

(La prima colonna mostra i dati per l'intero periodo, la seconda, la terza e la quarta dopo una chiusura singola, doppia e tripla)

Questo è ciò di cui parlavo! Le barre precedenti hanno un impatto abbastanza significativo su quella attuale perché il prezzo cerca sempre di riconquistare le perdite.


Un altro passo avanti

Benissimo! Una volta che siamo sicuri che il comportamento dei prezzi non sia casuale, dobbiamo usare questo fatto sorprendente il prima possibile. Certo, non è sufficiente per un sistema di trading indipendente, ma sarà un ottimo strumento in grado di liberarti dai segnali noiosi e spesso errati. Implementiamolo!

Quindi questo è ciò di cui abbiamo bisogno:

  1. Un sistema di self-trading che mostra risultati positivi almeno per l'ultimo anno.
  2. Qualche esempio divertente che conferma la presenza di correlazioni nel comportamento dei prezzi.

Ho trovato molte idee utili nel libro di L. Williams. Ne condividerò uno con voi.

La strategia TDW (Trade Day Of Week). Ci permetterà di vedere cosa accadrà se in alcuni giorni della settimana compreremo solamente e negli altri apriremo solo posizioni short. Dopotutto, possiamo supporre che il prezzo in un giorno cresca in una percentuale maggiore di casi rispetto a un altro. Qual è la ragione? La situazione geopolitica, le statistiche macroeconomiche o, come scritto nel libro di A. Elder, il lunedì e il martedì sono i giorni dei laici, mentre il giovedì e il venerdì rappresentano il momento dei professionisti? Proviamo a capire.

In primo luogo, venderemo solo per ogni giorno della settimana e poi venderemo e basta. Alla fine dello studio abbineremo i risultati migliori e questo sarà un filtro per il nostro sistema di trading. A proposito, ho un paio di parole a riguardo. È un classico puro!

Il sistema si basa su due MA e MACDake. Segnali:                                                            

  1. Se la media mobile veloce attraversa quella lenta dal basso verso l'alto e l'istogramma MACD è al di sotto della linea dello zero, allora ACQUISTA.
  2. Se la media mobile veloce attraversa quella lenta da capovolto e MACD è sopra lo zero, allora VENDI

Esci da una posizione utilizzando un trailing stop da un punto. Il lotto è fisso - 0,1. 

 Per comodità, ho inserito la classe Expert Advisor in un file di intestazione separato:

//+------------------------------------------------------------------+
//|                                                       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);
              }
           }
        }
     }
  }
//+------------------------------------------------------------------

I miei umili omaggi all'autore dell'articolo "Writing an Expert Advisor using the MQL5 Object-Oriented Approach". Cosa farei senza di lui! Consiglio di leggere questo articolo a chiunque non sia molto esperto in questa programmazione orientata agli oggetti malvagia,ma estremamente funzionale.

Aggiungi il file con la classe al codice principale di Expert Advisor? Crea un oggetto e inizializza le funzioni:

//+------------------------------------------------------------------+
//|                                                       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();
  }
//+------------------------------------------------------------------+

Fatto! Vorrei far notare alcune caratteristiche speciali. Per identificare i giorni della settimana a livello di software, ho usato la struttura MqlDateTime. Innanzitutto, trasformiamo l'ora corrente del server in un formato strutturato. Otteniamo un indice del giorno corrente (1-lunedì, ..., 5-venerdì) e lo confrontiamo con il valore che abbiamo impostato.

Prova! Per non appesantirti con ricerche noiose e cifre extra, sto riportando tutti i risultati nella tabella.

Eccola: 

Tabella 1. Riepilogo degli acquisti per tutti i giorni della settimana

Tabella 1. Riepilogo degli acquisti per tutti i giorni della settimana

Tabella 2. Riepilogo delle vendite per tutti i giorni della settimana

Tabella 2. Riepilogo delle vendite per tutti i giorni della settimana

I migliori risultati sono evidenziati in verde, i peggiori in arancione.

Faccio una premessa, ovvero che dopo le azioni descritte sopra il sistema deve garantire il profitto in combinazione con un drawdown basso relativo, una buona percentuale di operazioni vincenti (qui, meno operazioni esegui e meglio è) e un profitto relativamente alto per operazione.

Ovviamente, il sistema più efficace consiste nell'acquistare il venerdì e vendere il lunedì. Combina entrambe queste condizioni:

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();

Ora l'Expert Advisor apre posizioni in entrambe le direzioni, ma in giorni rigorosamente definiti. Per chiarezza, disegnerò i diagrammi ottenuti senza e con il filtro:

Figura 2. I risultati dei test EA senza l'utilizzo di un filtro (EURUSD, H1, 01.01.2010-31.12.2010,)

Figura 2. I risultati dei test EA senza l'utilizzo di un filtro (EURUSD, H1, 01.01.2010-31.12.2010,)

Figura 3. I risultati dei test EA utilizzando il filtro (EURUSD, H1, 01.01.2010-31.12.2010,)

Figura 3. I risultati dei test EA utilizzando il filtro (EURUSD, H1, 01.01.2010-31.12.2010)

Ti piace il risultato? Utilizzando il filtro, il sistema di trading è diventato più stabile. Prima delle modifiche, l'Expert Advisor aumentava principalmente il saldo nella prima metà del periodo di test, ma dopo l'"aggiornamento" è in aumento per tutto il periodo.

Confrontiamo i rapporti:

Tabella 3. Risultati dei test prima e dopo l'utilizzo del filtro

Tabella 3. Risultati dei test prima e dopo l'utilizzo del filtro

L'unico fattore angosciante, che non può essere ignorato, è il calo dell'utile netto di quasi 1000 USD (26%). Ma stiamo riducendo il numero di operazioni quasi in 3,5 volte, quindi stiamo riducendo significativamente, in primo luogo, il potenziale di fare un trading negativo e, in secondo luogo, le spese per lo spread (218 * 2-62 * 2 = 312 USD ed è solo per EUR / USD). La percentuale di vincita è aumentata al 57%, che è già significativa. Mentre il profitto per operazione aumenta del 14% a 113 USD. Come direbbe L. Williams: "Questo è l'importo con cui vale la pena fare trading!"


Conclusione

I prezzi non si comportano in modo casuale: è un dato di fatto. Questo fatto può e deve essere usato. Ho fatto solo un esempio che è una piccola frazione delle innumerevoli variazioni e tecniche che possono migliorare le prestazioni del tuo sistema di trading. Tuttavia, questa diversità nasconde un vizio. Non tutti i filtri possono essere integrati, quindi deve essere scelto con attenzione, pensando a tutti i possibili scenari.

Non dimenticare che non importa quanto sia perfetto il filtro, eliminerà anche le operazioni redditizie, cioè il tuo profitto ... Buona Fortuna!


Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/269

File allegati |
explorer.mq5 (2.84 KB)
moving.mq5 (2.28 KB)
moving.mqh (6.98 KB)
3 Metodi di accelerazione degli indicatori mediante l'esempio della regressione lineare 3 Metodi di accelerazione degli indicatori mediante l'esempio della regressione lineare
L'articolo tratta i metodi di ottimizzazione degli algoritmi di calcolo degli indicatori. Ciascuno troverà il metodo più adatto alle proprie esigenze. Qui sono descritti tre metodi. Uno di questi è abbastanza semplice, il successivo richiede una solida conoscenza della matematica e l'ultimo richiede un po' di arguzia. Gli indicatori o le funzionalità di progettazione del terminale MetaTrader5 vengono utilizzati per realizzare la maggior parte dei metodi descritti. I metodi sono abbastanza universali e possono essere utilizzati non solo per l'accelerazione del calcolo della regressione lineare, ma anche per molti altri indicatori.
Il ruolo delle distribuzioni statistiche nel lavoro del trader Il ruolo delle distribuzioni statistiche nel lavoro del trader
Questo articolo è una continuazione logica del mio articolo Statistical Probability Distributions in MQL5 che espone le classi per lavorare con alcune distribuzioni statistiche teoriche. Ora che abbiamo una base teorica, suggerisco di procedere direttamente a set di dati reali e provare a fare un uso informativo di questa base.
Distribuzioni statistiche di probabilità in MQL5 Distribuzioni statistiche di probabilità in MQL5
L'articolo affronta le distribuzioni di probabilità (normale, log-normale, binomiale, logistica, esponenziale, distribuzione di Cauchy, distribuzione t di Student, distribuzione di Laplace, distribuzione di Poisson, distribuzione iperbolica delle secanti, distribuzione Beta e Gamma) delle variabili casuali utilizzate nella statistica applicata. Dispone anche di classi per la gestione di queste distribuzioni.
Utilizzo di pseudo-modelli come alternativa ai modelli C++ Utilizzo di pseudo-modelli come alternativa ai modelli C++
L'articolo descrive un modo per programmare senza usare i modelli, ma mantenendo lo stile di programmazione inerente ad essi. L’articolo parla dell'implementazione dei modelli utilizzando metodi personalizzati e ha uno script già pronto allegato per la creazione di un codice sulla base di modelli specificati.