derivado de chiki2bum2/SniperGold_ML
632 linhas
13 KiB
Text
632 linhas
13 KiB
Text
//+------------------------------------------------------------------+
| |||
//| XAUUSD MTF MARKET HEALTH EA - MT5 |
| |||
//| M5 Entry + M15 + H1 + H4 Confirmation |
| |||
//+------------------------------------------------------------------+
| |||
#property strict
| |||
| |||
#include <Trade/Trade.mqh>
| |||
CTrade trade;
| |||
| |||
//==================== INPUTS ========================================//
| |||
input ENUM_TIMEFRAMES EntryTF = PERIOD_M5;
| |||
| |||
input int FastEMA = 9;
| |||
input int SlowEMA = 15;
| |||
input int TrendEMA = 100;
| |||
input int RSIPeriod = 14;
| |||
input int ATRPeriod = 14;
| |||
| |||
input double MinHealthScore = 70.0;
| |||
| |||
input double RiskPercent = 1.0;
| |||
input double MaxDailyLossPercent = 3.0;
| |||
input int MaxTradesPerDay = 5;
| |||
| |||
input double SL_ATR_Multiplier = 1.5;
| |||
input double TP_ATR_Multiplier = 2.5;
| |||
| |||
input bool UseBreakEven = true;
| |||
input double BreakEvenATR = 1.0;
| |||
| |||
input bool UseTrailing = true;
| |||
input double TrailingATR = 1.0;
| |||
| |||
input int MaxSpreadPoints = 100;
| |||
| |||
input ulong MagicNumber = 9051501;
| |||
| |||
//==================== HANDLES ======================================//
| |||
int fastM5, slowM5, trendM5, rsiM5, atrM5;
| |||
| |||
int trendM15;
| |||
int trendH1;
| |||
int trendH4;
| |||
| |||
datetime lastBar = 0;
| |||
| |||
//==================== INIT ==========================================//
| |||
int OnInit()
| |||
{
| |||
fastM5 = iMA(_Symbol, EntryTF, FastEMA, 0, MODE_EMA, PRICE_CLOSE);
| |||
slowM5 = iMA(_Symbol, EntryTF, SlowEMA, 0, MODE_EMA, PRICE_CLOSE);
| |||
trendM5 = iMA(_Symbol, EntryTF, TrendEMA, 0, MODE_EMA, PRICE_CLOSE);
| |||
| |||
rsiM5 = iRSI(_Symbol, EntryTF, RSIPeriod, PRICE_CLOSE);
| |||
atrM5 = iATR(_Symbol, EntryTF, ATRPeriod);
| |||
| |||
trendM15 = iMA(_Symbol, PERIOD_M15, TrendEMA, 0,
| |||
MODE_EMA, PRICE_CLOSE);
| |||
| |||
trendH1 = iMA(_Symbol, PERIOD_H1, TrendEMA, 0,
| |||
MODE_EMA, PRICE_CLOSE);
| |||
| |||
trendH4 = iMA(_Symbol, PERIOD_H4, TrendEMA, 0,
| |||
MODE_EMA, PRICE_CLOSE);
| |||
| |||
if(fastM5 == INVALID_HANDLE ||
| |||
slowM5 == INVALID_HANDLE ||
| |||
trendM5 == INVALID_HANDLE ||
| |||
rsiM5 == INVALID_HANDLE ||
| |||
atrM5 == INVALID_HANDLE ||
| |||
trendM15 == INVALID_HANDLE ||
| |||
trendH1 == INVALID_HANDLE ||
| |||
trendH4 == INVALID_HANDLE)
| |||
{
| |||
Print("Indicator initialization failed.");
| |||
return INIT_FAILED;
| |||
}
| |||
| |||
trade.SetExpertMagicNumber(MagicNumber);
| |||
| |||
Print("MTF Market Health EA Started.");
| |||
| |||
return INIT_SUCCEEDED;
| |||
}
| |||
| |||
//==================== DEINIT ========================================//
| |||
void OnDeinit(const int reason)
| |||
{
| |||
IndicatorRelease(fastM5);
| |||
IndicatorRelease(slowM5);
| |||
IndicatorRelease(trendM5);
| |||
IndicatorRelease(rsiM5);
| |||
IndicatorRelease(atrM5);
| |||
| |||
IndicatorRelease(trendM15);
| |||
IndicatorRelease(trendH1);
| |||
IndicatorRelease(trendH4);
| |||
}
| |||
| |||
//==================== NEW BAR =======================================//
| |||
bool IsNewBar()
| |||
{
| |||
datetime t = iTime(_Symbol, EntryTF, 0);
| |||
| |||
if(t != lastBar)
| |||
{
| |||
lastBar = t;
| |||
return true;
| |||
}
| |||
| |||
return false;
| |||
}
| |||
| |||
//==================== GET VALUE =====================================//
| |||
double GetMAValue(int handle, int shift)
| |||
{
| |||
double buffer[];
| |||
| |||
if(CopyBuffer(handle, 0, shift, 1, buffer) != 1)
| |||
return 0;
| |||
| |||
return buffer[0];
| |||
}
| |||
| |||
//==================== RSI ===========================================//
| |||
double GetRSI()
| |||
{
| |||
double buffer[];
| |||
| |||
if(CopyBuffer(rsiM5, 0, 1, 1, buffer) != 1)
| |||
return 50;
| |||
| |||
return buffer[0];
| |||
}
| |||
| |||
//==================== ATR ===========================================//
| |||
double GetATR()
| |||
{
| |||
double buffer[];
| |||
| |||
if(CopyBuffer(atrM5, 0, 1, 1, buffer) != 1)
| |||
return 0;
| |||
| |||
return buffer[0];
| |||
}
| |||
| |||
//==================== TREND =========================================//
| |||
int GetTrend(ENUM_TIMEFRAMES tf, int handle)
| |||
{
| |||
double ema = GetMAValue(handle, 1);
| |||
double price = iClose(_Symbol, tf, 1);
| |||
| |||
if(ema == 0 || price == 0)
| |||
return 0;
| |||
| |||
if(price > ema)
| |||
return 1;
| |||
| |||
if(price < ema)
| |||
return -1;
| |||
| |||
return 0;
| |||
}
| |||
| |||
//==================== VOLUME ========================================//
| |||
bool VolumeBullish()
| |||
{
| |||
long currentVol = iVolume(_Symbol, EntryTF, 1);
| |||
long previousVol = iVolume(_Symbol, EntryTF, 2);
| |||
| |||
return currentVol >= previousVol;
| |||
}
| |||
| |||
//==================== SPREAD ========================================//
| |||
bool SpreadOK()
| |||
{
| |||
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
| |||
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
| |||
| |||
double spread = (ask - bid) / _Point;
| |||
| |||
return spread <= MaxSpreadPoints;
| |||
}
| |||
| |||
//==================== DAILY LOSS ====================================//
| |||
double TodayProfit()
| |||
{
| |||
datetime start =
| |||
StringToTime(TimeToString(TimeCurrent(), TIME_DATE));
| |||
| |||
if(!HistorySelect(start, TimeCurrent()))
| |||
return 0;
| |||
| |||
double profit = 0;
| |||
| |||
int total = HistoryDealsTotal();
| |||
| |||
for(int i=0; i<total; i++)
| |||
{
| |||
ulong ticket = HistoryDealGetTicket(i);
| |||
| |||
if(ticket == 0)
| |||
continue;
| |||
| |||
long magic =
| |||
HistoryDealGetInteger(ticket, DEAL_MAGIC);
| |||
| |||
if(magic != (long)MagicNumber)
| |||
continue;
| |||
| |||
profit += HistoryDealGetDouble(ticket, DEAL_PROFIT);
| |||
profit += HistoryDealGetDouble(ticket, DEAL_SWAP);
| |||
profit += HistoryDealGetDouble(ticket, DEAL_COMMISSION);
| |||
}
| |||
| |||
return profit;
| |||
}
| |||
| |||
//==================== TRADES TODAY ==================================//
| |||
int TradesToday()
| |||
{
| |||
datetime start =
| |||
StringToTime(TimeToString(TimeCurrent(), TIME_DATE));
| |||
| |||
if(!HistorySelect(start, TimeCurrent()))
| |||
return 0;
| |||
| |||
int count = 0;
| |||
| |||
int total = HistoryDealsTotal();
| |||
| |||
for(int i=0; i<total; i++)
| |||
{
| |||
ulong ticket = HistoryDealGetTicket(i);
| |||
| |||
if(ticket == 0)
| |||
continue;
| |||
| |||
long magic =
| |||
HistoryDealGetInteger(ticket, DEAL_MAGIC);
| |||
| |||
long entry =
| |||
HistoryDealGetInteger(ticket, DEAL_ENTRY);
| |||
| |||
if(magic == (long)MagicNumber &&
| |||
entry == DEAL_ENTRY_IN)
| |||
{
| |||
count++;
| |||
}
| |||
}
| |||
| |||
return count;
| |||
}
| |||
| |||
//==================== HEALTH SCORE ==================================//
| |||
double GetHealthScore(int direction)
| |||
{
| |||
double score = 0;
| |||
| |||
// M15 trend = 20
| |||
int m15 = GetTrend(PERIOD_M15, trendM15);
| |||
| |||
if(m15 == direction)
| |||
score += 20;
| |||
| |||
// H1 trend = 25
| |||
int h1 = GetTrend(PERIOD_H1, trendH1);
| |||
| |||
if(h1 == direction)
| |||
score += 25;
| |||
| |||
// H4 trend = 25
| |||
int h4 = GetTrend(PERIOD_H4, trendH4);
| |||
| |||
if(h4 == direction)
| |||
score += 25;
| |||
| |||
// M5 trend = 10
| |||
int m5 = GetTrend(EntryTF, trendM5);
| |||
| |||
if(m5 == direction)
| |||
score += 10;
| |||
| |||
// RSI = 10
| |||
double rsi = GetRSI();
| |||
| |||
if(direction == 1 && rsi >= 55)
| |||
score += 10;
| |||
| |||
if(direction == -1 && rsi <= 45)
| |||
score += 10;
| |||
| |||
// Volume = 10
| |||
if(VolumeBullish())
| |||
score += 10;
| |||
| |||
return score;
| |||
}
| |||
| |||
//==================== LOT SIZE ======================================//
| |||
double CalculateLot(double slDistance)
| |||
{
| |||
double balance =
| |||
AccountInfoDouble(ACCOUNT_BALANCE);
| |||
| |||
double riskMoney =
| |||
balance * RiskPercent / 100.0;
| |||
| |||
double tickValue =
| |||
SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
| |||
| |||
double tickSize =
| |||
SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
| |||
| |||
if(tickValue <= 0 || tickSize <= 0)
| |||
return SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
| |||
| |||
double lossPerLot =
| |||
(slDistance / tickSize) * tickValue;
| |||
| |||
if(lossPerLot <= 0)
| |||
return SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
| |||
| |||
double lot = riskMoney / lossPerLot;
| |||
| |||
double minLot =
| |||
SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
| |||
| |||
double maxLot =
| |||
SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
| |||
| |||
double step =
| |||
SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
| |||
| |||
lot = MathMax(lot, minLot);
| |||
lot = MathMin(lot, maxLot);
| |||
| |||
lot = MathFloor(lot / step) * step;
| |||
| |||
return NormalizeDouble(lot, 2);
| |||
}
| |||
| |||
//==================== BUY SIGNAL ====================================//
| |||
bool BuySignal()
| |||
{
| |||
double fast1 = GetMAValue(fastM5, 1);
| |||
double fast2 = GetMAValue(fastM5, 2);
| |||
| |||
double slow1 = GetMAValue(slowM5, 1);
| |||
double slow2 = GetMAValue(slowM5, 2);
| |||
| |||
if(fast1 == 0 || slow1 == 0)
| |||
return false;
| |||
| |||
bool crossover =
| |||
fast2 <= slow2 &&
| |||
fast1 > slow1;
| |||
| |||
return crossover;
| |||
}
| |||
| |||
//==================== SELL SIGNAL ===================================//
| |||
bool SellSignal()
| |||
{
| |||
double fast1 = GetMAValue(fastM5, 1);
| |||
double fast2 = GetMAValue(fastM5, 2);
| |||
| |||
double slow1 = GetMAValue(slowM5, 1);
| |||
double slow2 = GetMAValue(slowM5, 2);
| |||
| |||
if(fast1 == 0 || slow1 == 0)
| |||
return false;
| |||
| |||
bool crossover =
| |||
fast2 >= slow2 &&
| |||
fast1 < slow1;
| |||
| |||
return crossover;
| |||
}
| |||
| |||
//==================== BUY ===========================================//
| |||
void OpenBuy()
| |||
{
| |||
double atr = GetATR();
| |||
| |||
if(atr <= 0)
| |||
return;
| |||
| |||
double ask =
| |||
SymbolInfoDouble(_Symbol, SYMBOL_ASK);
| |||
| |||
double slDistance =
| |||
atr * SL_ATR_Multiplier;
| |||
| |||
double tpDistance =
| |||
atr * TP_ATR_Multiplier;
| |||
| |||
double lot =
| |||
CalculateLot(slDistance);
| |||
| |||
double sl =
| |||
ask - slDistance;
| |||
| |||
double tp =
| |||
ask + tpDistance;
| |||
| |||
trade.Buy(
| |||
lot,
| |||
_Symbol,
| |||
ask,
| |||
NormalizeDouble(sl, _Digits),
| |||
NormalizeDouble(tp, _Digits),
| |||
"MTF HEALTH BUY"
| |||
);
| |||
}
| |||
| |||
//==================== SELL ==========================================//
| |||
void OpenSell()
| |||
{
| |||
double atr = GetATR();
| |||
| |||
if(atr <= 0)
| |||
return;
| |||
| |||
double bid =
| |||
SymbolInfoDouble(_Symbol, SYMBOL_BID);
| |||
| |||
double slDistance =
| |||
atr * SL_ATR_Multiplier;
| |||
| |||
double tpDistance =
| |||
atr * TP_ATR_Multiplier;
| |||
| |||
double lot =
| |||
CalculateLot(slDistance);
| |||
| |||
double sl =
| |||
bid + slDistance;
| |||
| |||
double tp =
| |||
bid - tpDistance;
| |||
| |||
trade.Sell(
| |||
lot,
| |||
_Symbol,
| |||
bid,
| |||
NormalizeDouble(sl, _Digits),
| |||
NormalizeDouble(tp, _Digits),
| |||
"MTF HEALTH SELL"
| |||
);
| |||
}
| |||
| |||
//==================== POSITION MANAGEMENT ===========================//
| |||
void ManagePosition()
| |||
{
| |||
if(!PositionSelect(_Symbol))
| |||
return;
| |||
| |||
double atr = GetATR();
| |||
| |||
if(atr <= 0)
| |||
return;
| |||
| |||
long type =
| |||
PositionGetInteger(POSITION_TYPE);
| |||
| |||
double open =
| |||
PositionGetDouble(POSITION_PRICE_OPEN);
| |||
| |||
double sl =
| |||
PositionGetDouble(POSITION_SL);
| |||
| |||
double tp =
| |||
PositionGetDouble(POSITION_TP);
| |||
| |||
double bid =
| |||
SymbolInfoDouble(_Symbol, SYMBOL_BID);
| |||
| |||
double ask =
| |||
SymbolInfoDouble(_Symbol, SYMBOL_ASK);
| |||
| |||
// BUY
| |||
if(type == POSITION_TYPE_BUY)
| |||
{
| |||
double profit =
| |||
bid - open;
| |||
| |||
// Break-even
| |||
if(UseBreakEven &&
| |||
profit >= atr * BreakEvenATR)
| |||
{
| |||
double newSL = open;
| |||
| |||
if(sl < newSL)
| |||
{
| |||
trade.PositionModify(
| |||
_Symbol,
| |||
NormalizeDouble(newSL, _Digits),
| |||
tp
| |||
);
| |||
}
| |||
}
| |||
| |||
// Trailing
| |||
if(UseTrailing &&
| |||
profit >= atr * TrailingATR)
| |||
{
| |||
double newSL =
| |||
bid - atr * TrailingATR;
| |||
| |||
if(newSL > sl)
| |||
{
| |||
trade.PositionModify(
| |||
_Symbol,
| |||
NormalizeDouble(newSL, _Digits),
| |||
tp
| |||
);
| |||
}
| |||
}
| |||
}
| |||
| |||
// SELL
| |||
if(type == POSITION_TYPE_SELL)
| |||
{
| |||
double profit =
| |||
open - ask;
| |||
| |||
// Break-even
| |||
if(UseBreakEven &&
| |||
profit >= atr * BreakEvenATR)
| |||
{
| |||
double newSL = open;
| |||
| |||
if(sl == 0 || sl > newSL)
| |||
{
| |||
trade.PositionModify(
| |||
_Symbol,
| |||
NormalizeDouble(newSL, _Digits),
| |||
tp
| |||
);
| |||
}
| |||
}
| |||
| |||
// Trailing
| |||
if(UseTrailing &&
| |||
profit >= atr * TrailingATR)
| |||
{
| |||
double newSL =
| |||
ask + atr * TrailingATR;
| |||
| |||
if(sl == 0 || newSL < sl)
| |||
{
| |||
trade.PositionModify(
| |||
_Symbol,
| |||
NormalizeDouble(newSL, _Digits),
| |||
tp
| |||
);
| |||
}
| |||
}
| |||
}
| |||
}
| |||
| |||
//==================== MAIN ==========================================//
| |||
void OnTick()
| |||
{
| |||
// Position management runs continuously
| |||
ManagePosition();
| |||
| |||
// New candle only for entries
| |||
if(!IsNewBar())
| |||
return;
| |||
| |||
// Spread protection
| |||
if(!SpreadOK())
| |||
{
| |||
Print("Spread too high - trade skipped.");
| |||
return;
| |||
}
| |||
| |||
// Daily trade limit
| |||
if(TradesToday() >= MaxTradesPerDay)
| |||
{
| |||
Print("Daily trade limit reached.");
| |||
return;
| |||
}
| |||
| |||
// Daily loss protection
| |||
double balance =
| |||
AccountInfoDouble(ACCOUNT_BALANCE);
| |||
| |||
double maxLoss =
| |||
balance * MaxDailyLossPercent / 100.0;
| |||
| |||
if(TodayProfit() <= -maxLoss)
| |||
{
| |||
Print("Daily loss limit reached.");
| |||
return;
| |||
}
| |||
| |||
// One position at a time
| |||
if(PositionSelect(_Symbol))
| |||
return;
| |||
| |||
// BUY
| |||
if(BuySignal())
| |||
{
| |||
double score = GetHealthScore(1);
| |||
| |||
Print("BUY Health Score = ", score);
| |||
| |||
if(score >= MinHealthScore)
| |||
{
| |||
OpenBuy();
| |||
return;
| |||
}
| |||
}
| |||
| |||
// SELL
| |||
if(SellSignal())
| |||
{
| |||
double score = GetHealthScore(-1);
| |||
| |||
Print("SELL Health Score = ", score);
| |||
| |||
if(score >= MinHealthScore)
| |||
{
| |||
OpenSell();
| |||
return;
| |||
}
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
|