328 Zeilen
Kein EOL
11 KiB
MQL5
328 Zeilen
Kein EOL
11 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Ichimoku_Complete_Pro.mq5 |
|
|
//| Version 2.10 - Daily Loss Limit + Direction Filter |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Educational - Optimized Version"
|
|
#property version "2.10"
|
|
#property strict
|
|
|
|
#include <Trade\Trade.mqh>
|
|
CTrade trade;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Eingabeparameter |
|
|
//+------------------------------------------------------------------+
|
|
input group "=== Ichimoku Einstellungen ==="
|
|
input int InpTenkanPeriod = 9;
|
|
input int InpKijunPeriod = 26;
|
|
input int InpSenkouPeriod = 52;
|
|
|
|
input group "=== ATR Risk Management ==="
|
|
input double InpSL_Multiplier = 1.5;
|
|
input double InpTP_Multiplier = 2.5;
|
|
input double InpTrail_Start = 1.2;
|
|
input double InpTrail_Distance = 1.0;
|
|
input double InpBE_Trigger = 1.0;
|
|
input double InpBE_Offset = 0.2;
|
|
|
|
input group "=== Handelsrichtung ==="
|
|
enum ENUM_TRADE_DIRECTION
|
|
{
|
|
DIR_BOTH = 0, // Beide Richtungen
|
|
DIR_LONG = 1, // Nur Long
|
|
DIR_SHORT = 2 // Nur Short
|
|
};
|
|
input ENUM_TRADE_DIRECTION InpTradeDirection = DIR_BOTH;
|
|
|
|
input group "=== Tagesverlust-Limit ==="
|
|
input bool InpUseDailyLossLimit = true;
|
|
input double InpMaxDailyLoss = 50.0; // Maximaler Verlust in Account-Währung (z.B. 50 $)
|
|
|
|
input group "=== Filter ==="
|
|
input bool InpUseSessionFilter = true;
|
|
input int InpLondonStart = 8;
|
|
input int InpLondonEnd = 17;
|
|
input int InpNYStart = 13;
|
|
input int InpNYEnd = 22;
|
|
input int InpMaxSpreadPoints = 25;
|
|
|
|
input group "=== Benachrichtigungen ==="
|
|
input bool InpSendPush = true;
|
|
input bool InpSendMail = false;
|
|
input string InpMailSubject = "Ichimoku EA";
|
|
|
|
input group "=== Allgemein ==="
|
|
input double InpLotSize = 0.01;
|
|
input int InpMagicNumber = 20260915;
|
|
input bool InpOnlyOneTrade = true;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Globale Variablen |
|
|
//+------------------------------------------------------------------+
|
|
int handleIchimoku = INVALID_HANDLE;
|
|
int handleATR = INVALID_HANDLE;
|
|
int atrPeriod = 14;
|
|
|
|
double tenkan[], kijun[], senkouA[], senkouB[], chikou[], atr[];
|
|
|
|
double dailyStartBalance = 0;
|
|
datetime lastDayChecked = 0;
|
|
bool tradingAllowedToday = true;
|
|
|
|
//+------------------------------------------------------------------+
|
|
int GetATRPeriodByTimeframe()
|
|
{
|
|
ENUM_TIMEFRAMES tf = Period();
|
|
if(tf <= PERIOD_M5) return 20;
|
|
if(tf <= PERIOD_M15) return 14;
|
|
if(tf <= PERIOD_M30) return 12;
|
|
if(tf <= PERIOD_H1) return 10;
|
|
if(tf <= PERIOD_H4) return 10;
|
|
return 8;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
atrPeriod = GetATRPeriodByTimeframe();
|
|
|
|
handleIchimoku = iIchimoku(_Symbol, PERIOD_CURRENT, InpTenkanPeriod, InpKijunPeriod, InpSenkouPeriod);
|
|
handleATR = iATR(_Symbol, PERIOD_CURRENT, atrPeriod);
|
|
|
|
if(handleIchimoku == INVALID_HANDLE || handleATR == INVALID_HANDLE)
|
|
{
|
|
Print("Fehler beim Erstellen der Indikatoren");
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
ArraySetAsSeries(tenkan, true);
|
|
ArraySetAsSeries(kijun, true);
|
|
ArraySetAsSeries(senkouA, true);
|
|
ArraySetAsSeries(senkouB, true);
|
|
ArraySetAsSeries(chikou, true);
|
|
ArraySetAsSeries(atr, true);
|
|
|
|
trade.SetExpertMagicNumber(InpMagicNumber);
|
|
trade.SetDeviationInPoints(30);
|
|
trade.SetTypeFilling(ORDER_FILLING_FOK);
|
|
|
|
// Tagesstart-Balance initialisieren
|
|
dailyStartBalance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
lastDayChecked = iTime(_Symbol, PERIOD_D1, 0);
|
|
tradingAllowedToday = true;
|
|
|
|
Print("Ichimoku EA v2.10 gestartet | ATR-Periode: ", atrPeriod);
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
if(handleIchimoku != INVALID_HANDLE) IndicatorRelease(handleIchimoku);
|
|
if(handleATR != INVALID_HANDLE) IndicatorRelease(handleATR);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void CheckDailyLossLimit()
|
|
{
|
|
if(!InpUseDailyLossLimit)
|
|
{
|
|
tradingAllowedToday = true;
|
|
return;
|
|
}
|
|
|
|
datetime currentDay = iTime(_Symbol, PERIOD_D1, 0);
|
|
|
|
// Neuer Tag → Reset
|
|
if(currentDay != lastDayChecked)
|
|
{
|
|
dailyStartBalance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
lastDayChecked = currentDay;
|
|
tradingAllowedToday = true;
|
|
Print("Neuer Handelstag – Tagesverlust-Limit zurückgesetzt");
|
|
}
|
|
|
|
double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
|
|
double dailyPL = currentEquity - dailyStartBalance;
|
|
|
|
if(dailyPL <= -InpMaxDailyLoss)
|
|
{
|
|
if(tradingAllowedToday)
|
|
{
|
|
tradingAllowedToday = false;
|
|
Notify("Tagesverlust-Limit erreicht (" + DoubleToString(dailyPL, 2) + "). Trading für heute gestoppt.");
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool IsTradingSession()
|
|
{
|
|
if(!InpUseSessionFilter) return true;
|
|
|
|
MqlDateTime dt;
|
|
TimeToStruct(TimeCurrent(), dt);
|
|
int hour = dt.hour;
|
|
|
|
bool london = (hour >= InpLondonStart && hour < InpLondonEnd);
|
|
bool ny = (hour >= InpNYStart && hour < InpNYEnd);
|
|
|
|
return (london || ny);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool IsSpreadOK()
|
|
{
|
|
return (SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) <= InpMaxSpreadPoints);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void Notify(string message)
|
|
{
|
|
if(InpSendPush) SendNotification(message);
|
|
if(InpSendMail) SendMail(InpMailSubject, message);
|
|
Print(message);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void ManageOpenPosition()
|
|
{
|
|
if(!PositionSelect(_Symbol)) return;
|
|
if(PositionGetInteger(POSITION_MAGIC) != InpMagicNumber) return;
|
|
|
|
if(CopyBuffer(handleATR, 0, 0, 2, atr) < 2) return;
|
|
double currentATR = atr[0];
|
|
if(currentATR <= 0) return;
|
|
|
|
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
|
|
|
|
long type = PositionGetInteger(POSITION_TYPE);
|
|
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
|
|
double currentSL = PositionGetDouble(POSITION_SL);
|
|
double currentTP = PositionGetDouble(POSITION_TP);
|
|
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
|
|
double beTrigger = currentATR * InpBE_Trigger;
|
|
double beOffset = currentATR * InpBE_Offset;
|
|
double trailStart = currentATR * InpTrail_Start;
|
|
double trailDistance = currentATR * InpTrail_Distance;
|
|
double minMove = currentATR * 0.12;
|
|
|
|
// LONG
|
|
if(type == POSITION_TYPE_BUY)
|
|
{
|
|
double profit = bid - openPrice;
|
|
|
|
if(profit >= beTrigger)
|
|
{
|
|
double newSL = NormalizeDouble(openPrice + beOffset, digits);
|
|
if(newSL > currentSL + minMove || currentSL == 0)
|
|
if(trade.PositionModify(_Symbol, newSL, currentTP))
|
|
Notify("Break-Even BUY | SL: " + DoubleToString(newSL, digits));
|
|
}
|
|
|
|
if(profit >= trailStart)
|
|
{
|
|
double newSL = NormalizeDouble(bid - trailDistance, digits);
|
|
if(newSL > currentSL + minMove)
|
|
trade.PositionModify(_Symbol, newSL, currentTP);
|
|
}
|
|
}
|
|
|
|
// SHORT
|
|
if(type == POSITION_TYPE_SELL)
|
|
{
|
|
double profit = openPrice - ask;
|
|
|
|
if(profit >= beTrigger)
|
|
{
|
|
double newSL = NormalizeDouble(openPrice - beOffset, digits);
|
|
if(currentSL == 0 || newSL < currentSL - minMove)
|
|
if(trade.PositionModify(_Symbol, newSL, currentTP))
|
|
Notify("Break-Even SELL | SL: " + DoubleToString(newSL, digits));
|
|
}
|
|
|
|
if(profit >= trailStart)
|
|
{
|
|
double newSL = NormalizeDouble(ask + trailDistance, digits);
|
|
if(currentSL == 0 || newSL < currentSL - minMove)
|
|
trade.PositionModify(_Symbol, newSL, currentTP);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
// Tagesverlust prüfen
|
|
CheckDailyLossLimit();
|
|
|
|
// Offene Positionen verwalten
|
|
ManageOpenPosition();
|
|
|
|
// Filter
|
|
if(!tradingAllowedToday) return;
|
|
if(!IsTradingSession()) return;
|
|
if(!IsSpreadOK()) return;
|
|
|
|
// Nur bei neuer Kerze
|
|
static datetime lastBarTime = 0;
|
|
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
|
|
if(currentBarTime == lastBarTime) return;
|
|
lastBarTime = currentBarTime;
|
|
|
|
if(InpOnlyOneTrade && PositionSelect(_Symbol)) return;
|
|
|
|
// Indikatoren
|
|
if(CopyBuffer(handleIchimoku, 0, 0, 3, tenkan) < 3) return;
|
|
if(CopyBuffer(handleIchimoku, 1, 0, 3, kijun) < 3) return;
|
|
if(CopyBuffer(handleIchimoku, 2, 0, 3, senkouA) < 3) return;
|
|
if(CopyBuffer(handleIchimoku, 3, 0, 3, senkouB) < 3) return;
|
|
if(CopyBuffer(handleIchimoku, 4, 0, 30, chikou) < 30) return;
|
|
if(CopyBuffer(handleATR, 0, 1, 2, atr) < 2) return;
|
|
|
|
double atrValue = atr[0];
|
|
double close1 = iClose(_Symbol, PERIOD_CURRENT, 1);
|
|
double cloudTop = MathMax(senkouA[1], senkouB[1]);
|
|
double cloudBottom = MathMin(senkouA[1], senkouB[1]);
|
|
|
|
bool buySignal =
|
|
(close1 > cloudTop) &&
|
|
(tenkan[1] > kijun[1] && tenkan[2] <= kijun[2]) &&
|
|
(chikou[26] > close1);
|
|
|
|
bool sellSignal =
|
|
(close1 < cloudBottom) &&
|
|
(tenkan[1] < kijun[1] && tenkan[2] >= kijun[2]) &&
|
|
(chikou[26] < close1);
|
|
|
|
// Handelsrichtung filtern
|
|
if(InpTradeDirection == DIR_LONG) sellSignal = false;
|
|
if(InpTradeDirection == DIR_SHORT) buySignal = false;
|
|
|
|
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
|
|
|
|
// BUY
|
|
if(buySignal)
|
|
{
|
|
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
double sl = NormalizeDouble(ask - atrValue * InpSL_Multiplier, digits);
|
|
double tp = NormalizeDouble(ask + atrValue * InpTP_Multiplier, digits);
|
|
|
|
if(trade.Buy(InpLotSize, _Symbol, ask, sl, tp, "Ichimoku Buy"))
|
|
Notify("BUY | " + _Symbol + " | SL: " + DoubleToString(sl, digits) + " | TP: " + DoubleToString(tp, digits));
|
|
}
|
|
|
|
// SELL
|
|
if(sellSignal)
|
|
{
|
|
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
double sl = NormalizeDouble(bid + atrValue * InpSL_Multiplier, digits);
|
|
double tp = NormalizeDouble(bid - atrValue * InpTP_Multiplier, digits);
|
|
|
|
if(trade.Sell(InpLotSize, _Symbol, bid, sl, tp, "Ichimoku Sell"))
|
|
Notify("SELL | " + _Symbol + " | SL: " + DoubleToString(sl, digits) + " | TP: " + DoubleToString(tp, digits));
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+ |