OnTesterInit

La funzione è chiamata nell' EA quando si verifica l'evento TesterInit per eseguire le azioni necessarie prima dell'ottimizzazione nel tester di strategia. Ci sono due tipi di funzione.

La versione che restituisce il risultato

int  OnTesterInit(void);

Valore di ritorno

valore del tipo int, zero significa inizializzazione di successo di un EA lanciato su un chart prima dell'inizio dell'ottimizzazione.

La chiamata OnTesterInit() che restituisce il risultato dell'esecuzione è consigliata per l'uso poiché non solo consente l'inizializzazione del programma, ma restituisce anche un codice di errore in caso di una fermata di ottimizzazione anticipata. Restituzione di qualsiasi valore diverso da INIT_SUCCEEDED (0) indica un errore; non viene avviata alcuna ottimizzazione.

La versione senza un risultato restituito è lasciata solo per compatibilità con i vecchi codici. Non raccomandato per l'uso

void  OnTesterInit(void);

Nota

L'evento TesterInit viene generato prima dell'inizio dell'ottimizzazione EA nel tester strategia. A questo evento, un EA con il gestore di eventi OnTesterDeInit() o OnTesterPass() viene scaricato automaticamente su un terminale separato. Ha il simbolo e il periodo che sono stati specificati nel tester.

Tale evento riceve gli eventi TesterInit, TesterDeinit e TesterPass, ma non quelli Init, Deinit e NewTick. Di conseguenza, tutta la logica necessaria per elaborare i risultati di ogni passaggio durante l'ottimizzazione dovrebbe essere implementata negli handlers OnTesterInit(), OnTesterDeinit() e OnTesterPass() gestori.

Il risultato di ogni singolo pass durante l'ottimizzazione della strategia può essere dato tramite un frame dall handler OnTester() usando la funzione FrameAdd().

La funzione OnTesterInit() viene utilizzata per avviare un Expert Advisor prima dell'inizio dell'ottimizzazione elaborazione dei risultati di ottimizzazione. Viene sempre utilizzato insieme al gestore OnTesterDeinit().

Il tempo per l'esecuzione di OnTesterInit() è limitato. Se viene superato, l'EA viene fermato forzatamente, mentre l'ottimizzazione stessa viene annullata. Un messaggio viene visualizzato nel journal del tester:

Tester        OnTesterInit funziona troppo a lungo. Il tester non può essere inizializzato.

L'esempio è preso da OnTick. Il gestore OnTesterInit() viene aggiunto per l'impostazione dei parametri di ottimizzazione:

//+------------------------------------------------------------------+
//|                                          OnTesterInit_Sample.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#proprietàdescrizione"Esempio EA con il gestore OnTesterInit()"
#property description "in cui valori e limiti di"
#property description "inputs durante l'ottimizzazione sono impostati"
 
input double lots=0. 1;       // volume in lots
input double kATR=3;          // signal lunghezza candela in ATR
input int    ATRperiod=20;    // ATR indicator period
input int    holdbars=8;      // numero di barre per mantenere la posizione attiva
input int    slippage=10;     // slippage consentito
input bool   revers=false;    // inverto il segnale? 
input ulong  EXPERT_MAGIC=0;  // EA MagicNumber
//--- per memorizzare l'handle dell'indicatore ATR
int atr_handle;
//--- qui memorizzeremo gli ultimi valori ATR e il corpo della candela
double last_atr,last_body;
datetime lastbar_timeopen;
double trade_lot;
//--- ricorda l'ora di inizio dell'ottimizzazione
datetime optimization_start;
//--- per visualizzare la durata su un chart dopo la fine dell'ottimizzazione
string report;
//+------------------------------------------------------------------+
//| Funzione TesterInit                                              |
//+------------------------------------------------------------------+
void OnTesterInit()
  {
// --- imposta i valori degli input per l'ottimizzazione
   ParameterSetRange("lots",false,0.1,0,0,0);
   ParameterSetRange("kATR",true,3.0,1.0,0.3,7.0);
   ParameterSetRange("ATRperiod",true,10,15,1,30);
   ParameterSetRange("holdbars",true,5,3,1,15);
   ParameterSetRange("slippage",false,10,0,0,0);
   ParameterSetRange("revers",true,false,false,1,true);
   ParameterSetRange("EXPERT_MAGIC",false,123456,0,0,0);
   Print("I valori iniziali e le limitazioni dei parametri di ottimizzazione sono impostati");
//--- ricorda l'inizio dell'ottimizzazione
   optimization_start=TimeLocal();
   report=StringFormat("%s: ottimizzazione lanciata a %s",
                       __FUNCTION__,TimeToString(TimeLocal(),TIME_MINUTES|TIME_SECONDS));
//--- mostra i messaggi sul chart e sul journal del terminale
   Print(report);
   Comment(report);
//---   
  }
//+------------------------------------------------------------------+
//| TesterDeinit function                                            |
//+------------------------------------------------------------------+
void OnTesterDeinit()
  {
//--- durata dell'ottimizzazione
   string log_message=StringFormat("%s: l'ottimizzazione ha richiesto %d secondi",
                                   __FUNCTION__,TimeLocal()-optimization_start);
   PrintFormat(log_message);
   report=report+"\r\n"+log_message;
   Comment(report);
  }
//+------------------------------------------------------------------+
//| Funzione di inizializzazione Expert                              |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- inizializza le variabili globali
   last_atr=0;
   last_body=0;
//--- imposta il volume corretto
   double min_lot=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   trade_lot=lots>min_lot? lots:min_lot;   
//--- crea l'handle dell'indicatore ATR
   atr_handle=iATR(_Symbol,_Period,ATRperiod);
   if(atr_handle==INVALID_HANDLE)
     {
      PrintFormat("%s: impossibile creare iATR, codice di errore %d",__FUNCTION__,GetLastError());
      return(INIT_FAILED);
     }
//--- inizializzazione EA di successo
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Funzione tick Expert                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- segnale di trading
staticoint segnale = 0; // +1 significa un segnale di acquisto, -1 indica un segnale di vendita
//--- controlla e chiude le vecchie posizioni aperte più di barre 'holdbars' fa
   ClosePositionsByBars(holdbars,slippage,EXPERT_MAGIC);
//--- controlla una nuova barra
   if(isNewBar())
     {
      // --- controlla la presenza del segnale      
      signal=CheckSignal();
     }
// --- se si apre una posizione netting, saltare il segnale - attendere fino a quando non si chiude
   if(signal!=0 && PositionsTotal()>0 && (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_NETTING)
     {
      signal=0;
      return// esce dal gestore eventi NewTick e non entra nel mercato prima che appaia una nuova barra
     }
//--- per un conto hedging, ogni posizione viene tenuta e chiusa separatamente
   if(signal!=0)
     {
      //--- segnale buy
      if(signal>0)
        {
         PrintFormat("%s: Segnale Buy! Revers=%s",__FUNCTION__,string(revers));
         if(Buy(trade_lot,slippage,EXPERT_MAGIC))
            signal=0;
        }
      //--- segnale sell
      if(signal<0)
        {
         PrintFormat("%s: segnale Sell! Revers=%s",__FUNCTION__,string(revers));
         if(Sell(trade_lot,slippage,EXPERT_MAGIC))
            signal=0;
        }
     }
//--- Fine funzione OnTick
  }
//+------------------------------------------------------------------+
//| Controlla un nuovo segnale di trading                            |
//+------------------------------------------------------------------+
int CheckSignal()
  {
//--- 0 significa nessun segnale
   int res=0;
//--- ottiene il valore ATR su una penultima barra completa (l'indice della barra è 2)
   double atr_value[1];
   if(CopyBuffer(atr_handle,0,2,1,atr_value)!=-1)
     {
      last_atr=atr_value[0];
      // --- recupera i dati sull'ultima barra chiusa sull'array di tipo MqlRates
      MqlRates bar[1];
      if(CopyRates(_Symbol,_Period,1,1,bar)!=-1)
        {
         // --- calcola la misura del corpo della barra sull'ultima barra completa
         last_body=bar[0].close-bar[0].open;
// --- se il corpo dell'ultima barra (con indice 1) supera il precedente valore ATR (sulla barra con indice 2), viene ricevuto un segnale di trading
         if(MathAbs(last_body)>kATR*last_atr)
            res=last_body>0?1:-1; // valore positivo per la candela verso l'alto
        }
      else
         PrintFormat("% s: impossibile ricevere l'ultima barra! Error",__FUNCTION__,GetLastError());
     }
   else
      PrintFormat("% s: impossibile ricevere il valore dell'indicatore ATR! Error",__FUNCTION__,GetLastError());
//--- se la modalità di trading inverso è abilitata
   res=revers?-res:res;  // inverte il segnale se necessario (restituisci -1 invece di 1 e viceversa)
//--- restituisce un valore del segnale di trading
   return (res);
  }
//+------------------------------------------------------------------+
//| Restituisce 'true' quando appare una nuova barra                 |
//+------------------------------------------------------------------+
bool isNewBar(const bool print_log=true)
  {
   static datetime bartime=0; // memorizza l'orario di apertura della barra corrente
//--- ottiene l'orario di apertura della barra zero
   datetime currbar_time=iTime(_Symbol,_Period,0);
// --- se l'orario di apertura cambia, è arrivata una nuova barra
   if(bartime!=currbar_time)
     {
      bartime=currbar_time;
      lastbar_timeopen=bartime;
      //--- visualizza i dati sull'orario di apertura di una nuova barra nel log      
      if(print_log && !(MQLInfoInteger(MQL_OPTIMIZATION)||MQLInfoInteger(MQL_TESTER)))
        {
         //--- visualizza un messaggio con una nuova barra di apertura
         PrintFormat("%s: nuova barra su %s %s aperta a %s",__FUNCTION__,_Symbol,
                     StringSubstr(EnumToString(_Period),7),
                     TimeToString(TimeCurrent(),TIME_SECONDS));
         //--- recupera i dati sull'ultimo tick
         MqlTick last_tick;
         if(!SymbolInfoTick(Symbol(),last_tick))
            Print("SymbolInfoTick() fallito, errore = ",GetLastError());
         //--- mostra l'orario dell'ultimo tick fino ai millisecondi
         PrintFormat("L'ultimo tick era alle %s.%03d",
                     TimeToString(last_tick.time,TIME_SECONDS),last_tick.time_msc%1000);
        }
      //--- abbiamo una nuova barra
      return (true);
     }
//--- nessuna nuova barra
   return (false);
  }
//+------------------------------------------------------------------+
//| Acquista ad un prezzo di mercato con un volume specificato       |
//+------------------------------------------------------------------+
bool Buy(double volume,ulong deviation=10,ulong  magicnumber=0)
  {
//--- compra a prezzo di mercato
   return (MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber));
  }
//+------------------------------------------------------------------+
//| Vendi ad un prezzo di mercato con un volume specificato          |
//+------------------------------------------------------------------+
bool Sell(double volume,ulong deviation=10,ulong  magicnumber=0)
  {
//--- vendi a prezzo di mercato
   return (MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber));
  }
//+------------------------------------------------------------------+
//| Chiusura le posizioni per hold time in barre                     |
//+------------------------------------------------------------------+
void ClosePositionsByBars(int holdtimebars,ulong deviation=10,ulong  magicnumber=0)
  {
   int total=PositionsTotal(); // numero di posizioni aperte   
//--- itera su posizioni aperte
   for(int i=total-1; i>=0; i--)
     {
      //--- parametri dell posizione
      ulong  position_ticket=PositionGetTicket(i);                                      // ticket posizione
      string position_symbol=PositionGetString(POSITION_SYMBOL);                        // simbolo 
      ulong  magic=PositionGetInteger(POSITION_MAGIC);                                  // MagicNumber della posizione
      datetime position_open=(datetime)PositionGetInteger(POSITION_TIME);               // orario d'apertura della posizione
      int bars=iBarShift(_Symbol,PERIOD_CURRENT,position_open)+1;                       // quante barre fa una posizione è stata aperta
 
      //--- se la durata(lifetime) di una posizione è già grande, mentre MagicNumber e il simbolo corrispondono
      if(bars>holdtimebars && magic==magicnumber && position_symbol==_Symbol)
        {
         int    digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);           // numero di posizioni decimali
         double volume=PositionGetDouble(POSITION_VOLUME);                              // volume della posizione
         ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // tipo di posizione
         string str_type=StringSubstr(EnumToString(type),14);
         StringToLower(str_type); // abbassa il case del testo per la corretta formattazione del messaggio
         PrintFormat("Chiusura posizione #%I64u %s %s %.2f",
                     position_ticket,position_symbol,str_type,volume);
         //--- imposta un tipo di ordine e invia una richiesta di trade
         if(type==POSITION_TYPE_BUY)
            MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber,position_ticket);
         else
            MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber,position_ticket);
        }
     }
  }
//+------------------------------------------------------------------+
//| Preparare e inviare una richiesta di trade                       |
//+------------------------------------------------------------------+
bool MarketOrder(ENUM_ORDER_TYPE type,double volume,ulong slip,ulong magicnumber,ulong pos_ticket=0)
  {
//--- dichiarare e inizializzare le strutture
   MqlTradeRequest request={};
   MqlTradeResult  result={};
   double price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
   if(type==ORDER_TYPE_BUY)
      price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
//--- richiesta parametri
   request.action   =TRADE_ACTION_DEAL;                     // tipi di operazioni di trading
   request.position =pos_ticket;                            // ticket della posizione, se chiusura
   request.symbol   =Symbol();                              // symbol
   request.volume   =volume;                                // volume 
   request.type     =type;                                  // tipo di ordine
   request.price    =price;                                 // prezzo di trade
   request.deviation=slip;                                  // deviazione ammissibile dal prezzo
   request.magic    =magicnumber;                           // MagicNumber dell'ordine
//--- invia richiesta
   if(!OrderSend(request,result))
     {
      //--- mostra dati sul fallimento
      PrintFormat("OrderSend %s %s %.2f at %.5f errore %d",
                  request.symbol,EnumToString(type),volume,request.price,GetLastError());
      return (false);
     }
//--- informa di un'operazione riuscita
   PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
   return (true);
  }

Guarda anche

Testing delle strategie di trading, Lavorare con i risultati di ottimizzazione, OnTesterDeinit, OnTesterPass, ParameterGetRange, ParameterSetRange