//+------------------------------------------------------------------+
//| TradeByATR.mq5 |
//| Copyright 2018, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property description "Sample EA trading in the \"explosive\" candle direction"
#property description "\"Explosive\" candle has the body size exceeding k*ATR"
#property description "The \"revers\" parameter reverses the signal direction"
input double lots=0.1; // Volumen in Lots
input double kATR=3; // Länge der Signalkerze in ATR
input int ATRperiod=20; // Periodenlänge des ATR
input int holdbars=8; // Anzahl der Bars, die die Position gehalten werden soll
input int slippage=10; // Erlaubter Schlupf
input bool revers=false; // Signal umkehren?
input ulong EXPERT_MAGIC=0; // Des EA's Magicnummer
//--- zum Sichern des Handles des Indikators ATR
int atr_handle;
//--- hier werden die letzten Werte des ATR und die Kerzenkörper gesichert
double last_atr,last_body;
datetime lastbar_timeopen;
double trade_lot;
//+------------------------------------------------------------------+
//| Expert Initialisierungsfunktion |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Initialisierung der Globalen Variablen
last_atr=0;
last_body=0;
//--- Setzen des korrekten Volumens
double min_lot=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
trade_lot=lots>min_lot? lots:min_lot;
//--- Erstellen des Handles des Indikators ATR
atr_handle=iATR(_Symbol,_Period,ATRperiod);
if(atr_handle==INVALID_HANDLE)
{
PrintFormat("%s: failed to create iATR, error code %d",__FUNCTION__,GetLastError());
return(INIT_FAILED);
}
//--- Erfolgreiche Initialisierung des EA
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Deinitialisierungsfunktion des Experten |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- Information über das Ende der Arbeit des EAs
Print(__FILE__,": Deinitialization reason code = ",reason);
}
//+------------------------------------------------------------------+
//| Tick-Funktion des Experten |
//+------------------------------------------------------------------+
void OnTick()
{
//--- Handelssignal
static int signal=0; // +1 heißt Kaufsignal, -1 Verkaufssignal
//--- Prüfen und Schließen alter Positionen, die vor mehr als 'holdbars' eröffnet wurden
ClosePositionsByBars(holdbars,slippage,EXPERT_MAGIC);
//--- Prüfen auf eine neue Bar
if(isNewBar())
{
//--- Prüfen auf ein Signal
signal=CheckSignal();
}
//--- Wenn eine Netting-Position eröffnet wurde - warten bis sie geschlossen wurde
if(signal!=0 && PositionsTotal()>0 && (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_NETTING)
{
signal=0;
return; // die Ereignisbehandlung von NewTick beenden und kein Markteintritt vor dem nächsten Tick
}
//--- für ein Hedging-Konto wird jede Position separat gehalten und geschlossen
if(signal!=0)
{
//--- Kaufsignal
if(signal>0)
{
PrintFormat("%s: Buy signal! Revers=%s",__FUNCTION__,string(revers));
if(Buy(trade_lot,slippage,EXPERT_MAGIC))
signal=0;
}
//--- Verkaufssignal
if(signal<0)
{
PrintFormat("%s: Sell signal! Revers=%s",__FUNCTION__,string(revers));
if(Sell(trade_lot,slippage,EXPERT_MAGIC))
signal=0;
}
}
//--- Ende der Funktion OnTick
}
//+------------------------------------------------------------------+
//| Prüfen auf ein neues Handelssignal |
//+------------------------------------------------------------------+
int CheckSignal()
{
//--- 0 beutet klein Signal
int res=0;
//--- Abfrage des Wertes der ATR der vorletzten kompletten Bar (Indes der Bar ist 2)
double atr_value[1];
if(CopyBuffer(atr_handle,0,2,1,atr_value)!=-1)
{
last_atr=atr_value[0];
//--- Datenabfrage der letzten geschlossenen Bar von Array des Typs MqlRates
MqlRates bar[1];
if(CopyRates(_Symbol,_Period,1,1,bar)!=-1)
{
//--- Berechnen der Körpergröße der letzten, vollständigen Kerze
last_body=bar[0].close-bar[0].open;
//--- wenn der Körper der letzten Bar (mit Index 1) den vorherigen ATR-Wert überschreitet (auf der Bar mit Index 2), wird ein Handelssignal empfangen.
if(MathAbs(last_body)>kATR*last_atr)
res=last_body>0?1:-1; // positiver Wert der Aufwärtskerze
}
else
PrintFormat("%s: Failed to receive the last bar! Error",__FUNCTION__,GetLastError());
}
else
PrintFormat("%s: Failed to receive ATR indicator value! Error",__FUNCTION__,GetLastError());
//--- falls der umgekehrte Handelsmodus aktiviert ist
res=revers?-res:res; // Signal umkehren, wenn nötig (Rückgabe von -1 statt 1 und vice versa)
//--- Rückgabe des Wertes des Handelssignals
return (res);
}
//+------------------------------------------------------------------+
//| Rückgabe von 'true' wenn eine neue Bar erscheint |
//+------------------------------------------------------------------+
bool isNewBar(const bool print_log=true)
{
static datetime bartime=0; // Sichern der Eröffnungszeit der aktuellen Bar
//--- Abfrage der Eröffnungszeit der Bar Null
datetime currbar_time=iTime(_Symbol,_Period,0);
//--- Wenn sich die Eröffnungszeit änderte, gibt es eine neue Bar
if(bartime!=currbar_time)
{
bartime=currbar_time;
lastbar_timeopen=bartime;
//--- Eintragen der Eröffnungszeit der neuen Bar in das Log
if(print_log && !(MQLInfoInteger(MQL_OPTIMIZATION)||MQLInfoInteger(MQL_TESTER)))
{
//--- Anzeige der Nachricht mit der Eröffnungszeit der neuen bar
PrintFormat("%s: new bar on %s %s opened at %s",__FUNCTION__,_Symbol,
StringSubstr(EnumToString(_Period),7),
TimeToString(TimeCurrent(),TIME_SECONDS));
//--- Datenabfrage beim letzten Tick
MqlTick last_tick;
if(!SymbolInfoTick(Symbol(),last_tick))
Print("SymbolInfoTick() failed, error = ",GetLastError());
//--- Anzeige der Zeit des letzten Ticks bis zur Millisekunde
PrintFormat("Last tick was at %s.%03d",
TimeToString(last_tick.time,TIME_SECONDS),last_tick.time_msc%1000);
}
//--- wir haben eine neue Bar
return (true);
}
//--- keine neue Bar
return (false);
}
//+------------------------------------------------------------------+
//| Kauf zum Marktpreis mit angegebenen Volumen |
//+------------------------------------------------------------------+
bool Buy(double volume,ulong deviation=10,ulong magicnumber=0)
{
//--- Kauf zum Marktpreis
return (MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber));
}
//+------------------------------------------------------------------+
//| Verkauf zum Marktpreis mit angegebenen Volumen |
//+------------------------------------------------------------------+
bool Sell(double volume,ulong deviation=10,ulong magicnumber=0)
{
//--- Verkauf zum Marktpreis
return (MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber));
}
//+------------------------------------------------------------------+
//| Position schließen wegen der Haltezeit |
//+------------------------------------------------------------------+
void ClosePositionsByBars(int holdtimebars,ulong deviation=10,ulong magicnumber=0)
{
int total=PositionsTotal(); // Anzahl der offenen Positionen
//--- Iterieren über die offenen Position
for(int i=total-1; i>=0; i--)
{
//--- Parameter der Position
ulong position_ticket=PositionGetTicket(i); // Ticketnummer der Position
string position_symbol=PositionGetString(POSITION_SYMBOL); // Symbol
ulong magic=PositionGetInteger(POSITION_MAGIC); // MagicNumber der Position
datetime position_open=(datetime)PositionGetInteger(POSITION_TIME); // Eröffnungszeit der Position
int bars=iBarShift(_Symbol,PERIOD_CURRENT,position_open)+1; // wie viele Bars vorher wurde die Position eröffnet
//--- wenn die Lebenszeit der Position lang genug ist, und MagicNummer und Symbol übereinstimme
if(bars>holdtimebars && magic==magicnumber && position_symbol==_Symbol)
{
int digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS); // Dezimalstellen
double volume=PositionGetDouble(POSITION_VOLUME); // Volumen der Position
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type
string str_type=StringSubstr(EnumToString(type),14);
StringToLower(str_type); // Kleinschreibung für das korrekte Nachrichtenformat
PrintFormat("Close position #%d %s %s %.2f",
position_ticket,position_symbol,str_type,volume);
//--- Setzen des Auftragsart und Senden der Handelsanfrage
if(type==POSITION_TYPE_BUY)
MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber,position_ticket);
else
MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber,position_ticket);
}
}
}
//+------------------------------------------------------------------+
//| Vorbereiten und Senden der Handelsanfrage |
//+------------------------------------------------------------------+
bool MarketOrder(ENUM_ORDER_TYPE type,double volume,ulong slip,ulong magicnumber,ulong pos_ticket=0)
{
//--- Deklarieren und Initialisieren der Strukturen
MqlTradeRequest request={};
MqlTradeResult result={};
double price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
if(type==ORDER_TYPE_BUY)
price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
//--- Abfrage der Parameter
request.action =TRADE_ACTION_DEAL; // Typ der Handelsoperation
request.position =pos_ticket; // Ticketnummer der zu schließenden Position
request.symbol =Symbol(); // Symbol
request.volume =volume; // Volumen
request.type =type; // Auftragsart
request.price =price; // Handelspreis
request.deviation=slip; // erlaubter Schlupf vom Preis
request.magic =magicnumber; // MagicNumber des Auftrags
//--- Senden einer Anfrage
if(!OrderSend(request,result))
{
//--- Datenanzeige im Fehlerfall
PrintFormat("OrderSend %s %s %.2f at %.5f error %d",
request.symbol,EnumToString(type),volume,request.price,GetLastError());
return (false);
}
//--- Information über eine erfolgreiche Operation
PrintFormat("retcode=%u deal=%I64u order=%I64u",result.retcode,result.deal,result.order);
return (true);
}
|