bots/ Ichimoku_Complete_Pro/Ichimoku_Complete_Pro.mq5

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