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