Thinkwealth-Smart-Signal-Pr.../ThinkwealthSmartSignalProEA_V2.mq5
Nwobodo27 Solomon Ikechukwu 752c64cc03 ThinkwealthSmartSignalProEA_V2.mq5
Thinkwealth Smart Signal Pro EA V2
Smart Structure + Momentum Trading System for MetaTrader 5. Uses MACD, Stochastic, and Parabolic SAR on M5 with optional M15 confirmation. Includes automatic BUY/SELL execution, risk-based or fixed lot sizing, Stop Loss, Take Profit, trailing stop, alerts, sound notifications, chart signals, and one-trade-at-a-time protection.
Before publishing the final V2, compile and test the .mq5 source in MetaEditor to confirm there are no compilation errors or warnings
2026-08-14 20:49:39 +00:00

940 lines
No EOL
22 KiB
MQL5

//+------------------------------------------------------------------+
//| Thinkwealth Smart Signal Pro EA V2 |
//| Smart Structure + Momentum Trading System |
//| Platform: MetaTrader 5 |
//| Primary Timeframe: M5 |
//| Confirmation Timeframe: M15 |
//+------------------------------------------------------------------+
#property strict
#property version "2.00"
#property description "Thinkwealth Smart Signal Pro EA V2"
#property description "MACD + Stochastic + Parabolic SAR trading system"
//--- Trade library
#include <Trade/Trade.mqh>
CTrade trade;
//+------------------------------------------------------------------+
//| INPUT PARAMETERS |
//+------------------------------------------------------------------+
//--- General
input group "=== GENERAL SETTINGS ==="
input ulong InpMagicNumber = 20260814;
input bool InpEnableTrading = true;
input bool InpOneTradeAtATime = true;
input bool InpEnableAlerts = true;
input bool InpEnableSound = true;
input string InpSoundFile = "alert.wav";
//--- Timeframes
input group "=== TIMEFRAME SETTINGS ==="
input ENUM_TIMEFRAMES InpSignalTF = PERIOD_M5;
input ENUM_TIMEFRAMES InpConfirmTF = PERIOD_M15;
//--- MACD
input group "=== MACD SETTINGS ==="
input int InpMACDFast = 12;
input int InpMACDSlow = 26;
input int InpMACDSignal = 9;
//--- Stochastic
input group "=== STOCHASTIC SETTINGS ==="
input int InpStochK = 5;
input int InpStochD = 3;
input int InpStochSlowing = 3;
input double InpOversold = 20.0;
input double InpOverbought = 80.0;
//--- Parabolic SAR
input group "=== PARABOLIC SAR SETTINGS ==="
input double InpSARStep = 0.02;
input double InpSARMaximum = 0.20;
//--- Risk
input group "=== MONEY MANAGEMENT ==="
input bool InpUseRiskPercent = false;
input double InpFixedLot = 0.01;
input double InpRiskPercent = 1.0;
//--- Stop Loss / Take Profit
input group "=== STOP LOSS / TAKE PROFIT ==="
input bool InpUseStopLoss = true;
input double InpStopLossPoints = 500.0;
input bool InpUseTakeProfit = true;
input double InpTakeProfitPoints = 1000.0;
//--- Trailing stop
input group "=== TRAILING STOP ==="
input bool InpUseTrailingStop = false;
input double InpTrailingStopPoints = 500.0;
//--- Signal confirmation
input group "=== SIGNAL CONFIRMATION ==="
input bool InpUseM15Confirmation = true;
input bool InpRequireStochZone = false;
input bool InpUseClosedCandle = true;
//+------------------------------------------------------------------+
//| INDICATOR HANDLES |
//+------------------------------------------------------------------+
int hMACD_M5 = INVALID_HANDLE;
int hSTOCH_M5 = INVALID_HANDLE;
int hSAR_M5 = INVALID_HANDLE;
int hMACD_M15 = INVALID_HANDLE;
int hSTOCH_M15 = INVALID_HANDLE;
int hSAR_M15 = INVALID_HANDLE;
//--- Last processed candle
datetime g_lastBarTime = 0;
//--- Last signal candle
datetime g_lastBuySignal = 0;
datetime g_lastSellSignal = 0;
//+------------------------------------------------------------------+
//| Expert initialization |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Set magic number
trade.SetExpertMagicNumber(InpMagicNumber);
//--- Set reasonable deviation
trade.SetDeviationInPoints(20);
//--- M5 MACD
hMACD_M5 = iMACD(
_Symbol,
InpSignalTF,
InpMACDFast,
InpMACDSlow,
InpMACDSignal,
PRICE_CLOSE
);
if(hMACD_M5 == INVALID_HANDLE)
{
Print("ERROR: Failed to create M5 MACD handle.");
return INIT_FAILED;
}
//--- M5 Stochastic
hSTOCH_M5 = iStochastic(
_Symbol,
InpSignalTF,
InpStochK,
InpStochD,
InpStochSlowing,
MODE_SMA,
STO_LOWHIGH
);
if(hSTOCH_M5 == INVALID_HANDLE)
{
Print("ERROR: Failed to create M5 Stochastic handle.");
return INIT_FAILED;
}
//--- M5 SAR
hSAR_M5 = iSAR(
_Symbol,
InpSignalTF,
InpSARStep,
InpSARMaximum
);
if(hSAR_M5 == INVALID_HANDLE)
{
Print("ERROR: Failed to create M5 SAR handle.");
return INIT_FAILED;
}
//--- M15 confirmation indicators
if(InpUseM15Confirmation)
{
hMACD_M15 = iMACD(
_Symbol,
InpConfirmTF,
InpMACDFast,
InpMACDSlow,
InpMACDSignal,
PRICE_CLOSE
);
if(hMACD_M15 == INVALID_HANDLE)
{
Print("ERROR: Failed to create M15 MACD handle.");
return INIT_FAILED;
}
hSTOCH_M15 = iStochastic(
_Symbol,
InpConfirmTF,
InpStochK,
InpStochD,
InpStochSlowing,
MODE_SMA,
STO_LOWHIGH
);
if(hSTOCH_M15 == INVALID_HANDLE)
{
Print("ERROR: Failed to create M15 Stochastic handle.");
return INIT_FAILED;
}
hSAR_M15 = iSAR(
_Symbol,
InpConfirmTF,
InpSARStep,
InpSARMaximum
);
if(hSAR_M15 == INVALID_HANDLE)
{
Print("ERROR: Failed to create M15 SAR handle.");
return INIT_FAILED;
}
}
Print("==========================================");
Print("Thinkwealth Smart Signal Pro EA V2");
Print("Initialization successful.");
Print("Symbol: ", _Symbol);
Print("Signal TF: ", EnumToString(InpSignalTF));
Print("Confirmation TF: ", EnumToString(InpConfirmTF));
Print("==========================================");
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(hMACD_M5 != INVALID_HANDLE)
IndicatorRelease(hMACD_M5);
if(hSTOCH_M5 != INVALID_HANDLE)
IndicatorRelease(hSTOCH_M5);
if(hSAR_M5 != INVALID_HANDLE)
IndicatorRelease(hSAR_M5);
if(hMACD_M15 != INVALID_HANDLE)
IndicatorRelease(hMACD_M15);
if(hSTOCH_M15 != INVALID_HANDLE)
IndicatorRelease(hSTOCH_M15);
if(hSAR_M15 != INVALID_HANDLE)
IndicatorRelease(hSAR_M15);
Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- Manage existing trade
if(InpUseTrailingStop)
ManageTrailingStop();
//--- Only process a new candle
if(!IsNewBar())
return;
//--- Do not trade if trading is disabled
if(!InpEnableTrading)
return;
//--- Check if there is already a position
if(InpOneTradeAtATime && HasOpenPosition())
return;
//--- Check signal
CheckForSignal();
}
//+------------------------------------------------------------------+
//| Detect new candle |
//+------------------------------------------------------------------+
bool IsNewBar()
{
datetime currentBarTime = iTime(_Symbol, InpSignalTF, 0);
if(currentBarTime == 0)
return false;
if(currentBarTime != g_lastBarTime)
{
g_lastBarTime = currentBarTime;
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Check for trading signal |
//+------------------------------------------------------------------+
void CheckForSignal()
{
//--- We use closed candles
int shift = 1;
//--- Arrays
double macdMain[3];
double macdSignal[3];
double stochK[3];
double stochD[3];
double sar[3];
double closePrice[3];
ArraySetAsSeries(macdMain, true);
ArraySetAsSeries(macdSignal, true);
ArraySetAsSeries(stochK, true);
ArraySetAsSeries(stochD, true);
ArraySetAsSeries(sar, true);
ArraySetAsSeries(closePrice, true);
//--- Copy M5 MACD
if(CopyBuffer(hMACD_M5, 0, 0, 3, macdMain) < 3)
return;
if(CopyBuffer(hMACD_M5, 1, 0, 3, macdSignal) < 3)
return;
//--- Copy M5 stochastic
if(CopyBuffer(hSTOCH_M5, 0, 0, 3, stochK) < 3)
return;
if(CopyBuffer(hSTOCH_M5, 1, 0, 3, stochD) < 3)
return;
//--- Copy M5 SAR
if(CopyBuffer(hSAR_M5, 0, 0, 3, sar) < 3)
return;
//--- Copy prices
if(CopyClose(_Symbol, InpSignalTF, 0, 3, closePrice) < 3)
return;
//==============================================================
// BUY CONDITIONS
//==============================================================
bool macdBuy =
(macdMain[2] <= macdSignal[2] &&
macdMain[1] > macdSignal[1]);
bool stochBuy =
(stochK[2] <= stochD[2] &&
stochK[1] > stochD[1]);
bool sarBuy =
(sar[1] < closePrice[1]);
bool stochBuyZone = true;
if(InpRequireStochZone)
stochBuyZone = (stochK[2] < InpOversold ||
stochD[2] < InpOversold);
bool m15Buy = true;
if(InpUseM15Confirmation)
m15Buy = CheckM15Buy();
bool buySignal =
macdBuy &&
stochBuy &&
sarBuy &&
stochBuyZone &&
m15Buy;
//==============================================================
// SELL CONDITIONS
//==============================================================
bool macdSell =
(macdMain[2] >= macdSignal[2] &&
macdMain[1] < macdSignal[1]);
bool stochSell =
(stochK[2] >= stochD[2] &&
stochK[1] < stochD[1]);
bool sarSell =
(sar[1] > closePrice[1]);
bool stochSellZone = true;
if(InpRequireStochZone)
stochSellZone = (stochK[2] > InpOverbought ||
stochD[2] > InpOverbought);
bool m15Sell = true;
if(InpUseM15Confirmation)
m15Sell = CheckM15Sell();
bool sellSignal =
macdSell &&
stochSell &&
sarSell &&
stochSellZone &&
m15Sell;
//--- Execute BUY
if(buySignal)
{
datetime signalTime = iTime(_Symbol, InpSignalTF, 1);
if(signalTime != g_lastBuySignal)
{
g_lastBuySignal = signalTime;
DrawBuyArrow(signalTime, closePrice[1]);
SendSignalAlert("BUY");
OpenBuy();
}
return;
}
//--- Execute SELL
if(sellSignal)
{
datetime signalTime = iTime(_Symbol, InpSignalTF, 1);
if(signalTime != g_lastSellSignal)
{
g_lastSellSignal = signalTime;
DrawSellArrow(signalTime, closePrice[1]);
SendSignalAlert("SELL");
OpenSell();
}
}
}
//+------------------------------------------------------------------+
//| M15 BUY confirmation |
//+------------------------------------------------------------------+
bool CheckM15Buy()
{
double macdMain[2];
double macdSignal[2];
double stochK[2];
double stochD[2];
double sar[2];
double closePrice[2];
ArraySetAsSeries(macdMain, true);
ArraySetAsSeries(macdSignal, true);
ArraySetAsSeries(stochK, true);
ArraySetAsSeries(stochD, true);
ArraySetAsSeries(sar, true);
ArraySetAsSeries(closePrice, true);
if(CopyBuffer(hMACD_M15, 0, 0, 2, macdMain) < 2)
return false;
if(CopyBuffer(hMACD_M15, 1, 0, 2, macdSignal) < 2)
return false;
if(CopyBuffer(hSTOCH_M15, 0, 0, 2, stochK) < 2)
return false;
if(CopyBuffer(hSTOCH_M15, 1, 0, 2, stochD) < 2)
return false;
if(CopyBuffer(hSAR_M15, 0, 0, 2, sar) < 2)
return false;
if(CopyClose(_Symbol, InpConfirmTF, 0, 2, closePrice) < 2)
return false;
bool macdOK = macdMain[1] > macdSignal[1];
bool stochOK = stochK[1] > stochD[1];
bool sarOK = sar[1] < closePrice[1];
return (macdOK && stochOK && sarOK);
}
//+------------------------------------------------------------------+
//| M15 SELL confirmation |
//+------------------------------------------------------------------+
bool CheckM15Sell()
{
double macdMain[2];
double macdSignal[2];
double stochK[2];
double stochD[2];
double sar[2];
double closePrice[2];
ArraySetAsSeries(macdMain, true);
ArraySetAsSeries(macdSignal, true);
ArraySetAsSeries(stochK, true);
ArraySetAsSeries(stochD, true);
ArraySetAsSeries(sar, true);
ArraySetAsSeries(closePrice, true);
if(CopyBuffer(hMACD_M15, 0, 0, 2, macdMain) < 2)
return false;
if(CopyBuffer(hMACD_M15, 1, 0, 2, macdSignal) < 2)
return false;
if(CopyBuffer(hSTOCH_M15, 0, 0, 2, stochK) < 2)
return false;
if(CopyBuffer(hSTOCH_M15, 1, 0, 2, stochD) < 2)
return false;
if(CopyBuffer(hSAR_M15, 0, 0, 2, sar) < 2)
return false;
if(CopyClose(_Symbol, InpConfirmTF, 0, 2, closePrice) < 2)
return false;
bool macdOK = macdMain[1] < macdSignal[1];
bool stochOK = stochK[1] < stochD[1];
bool sarOK = sar[1] > closePrice[1];
return (macdOK && stochOK && sarOK);
}
//+------------------------------------------------------------------+
//| Check existing position |
//+------------------------------------------------------------------+
bool HasOpenPosition()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0)
continue;
if(!PositionSelectByTicket(ticket))
continue;
string symbol = PositionGetString(POSITION_SYMBOL);
ulong magic = (ulong)PositionGetInteger(POSITION_MAGIC);
if(symbol == _Symbol && magic == InpMagicNumber)
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Calculate lot size |
//+------------------------------------------------------------------+
double CalculateLotSize()
{
if(!InpUseRiskPercent)
return NormalizeVolume(InpFixedLot);
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double riskMoney =
balance * (InpRiskPercent / 100.0);
double tickSize =
SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double tickValue =
SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
if(tickSize <= 0.0 || tickValue <= 0.0)
return NormalizeVolume(InpFixedLot);
double stopDistance =
InpStopLossPoints * _Point;
double lossPerLot =
(stopDistance / tickSize) * tickValue;
if(lossPerLot <= 0.0)
return NormalizeVolume(InpFixedLot);
double lots =
riskMoney / lossPerLot;
return NormalizeVolume(lots);
}
//+------------------------------------------------------------------+
//| Normalize lot size |
//+------------------------------------------------------------------+
double NormalizeVolume(double volume)
{
double minLot =
SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot =
SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double step =
SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
if(step <= 0.0)
step = 0.01;
volume = MathMax(volume, minLot);
volume = MathMin(volume, maxLot);
volume =
MathFloor(volume / step) * step;
int digits = VolumeDigits(step);
return NormalizeDouble(volume, digits);
}
//+------------------------------------------------------------------+
//| Volume digits |
//+------------------------------------------------------------------+
int VolumeDigits(double step)
{
int digits = 0;
while(step < 1.0 && digits < 8)
{
step *= 10.0;
digits++;
}
return digits;
}
//+------------------------------------------------------------------+
//| Open BUY |
//+------------------------------------------------------------------+
void OpenBuy()
{
double ask =
SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(ask <= 0.0)
return;
double lot =
CalculateLotSize();
double sl = 0.0;
double tp = 0.0;
if(InpUseStopLoss)
sl = ask - InpStopLossPoints * _Point;
if(InpUseTakeProfit)
tp = ask + InpTakeProfitPoints * _Point;
sl = NormalizePrice(sl);
tp = NormalizePrice(tp);
bool result =
trade.Buy(
lot,
_Symbol,
ask,
sl,
tp,
"Thinkwealth V2 BUY"
);
if(result)
{
Print(
"BUY opened successfully. Ticket: ",
trade.ResultOrder(),
" Lot: ",
lot
);
}
else
{
Print(
"BUY failed. Retcode: ",
trade.ResultRetcode(),
" - ",
trade.ResultRetcodeDescription()
);
}
}
//+------------------------------------------------------------------+
//| Open SELL |
//+------------------------------------------------------------------+
void OpenSell()
{
double bid =
SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(bid <= 0.0)
return;
double lot =
CalculateLotSize();
double sl = 0.0;
double tp = 0.0;
if(InpUseStopLoss)
sl = bid + InpStopLossPoints * _Point;
if(InpUseTakeProfit)
tp = bid - InpTakeProfitPoints * _Point;
sl = NormalizePrice(sl);
tp = NormalizePrice(tp);
bool result =
trade.Sell(
lot,
_Symbol,
bid,
sl,
tp,
"Thinkwealth V2 SELL"
);
if(result)
{
Print(
"SELL opened successfully. Ticket: ",
trade.ResultOrder(),
" Lot: ",
lot
);
}
else
{
Print(
"SELL failed. Retcode: ",
trade.ResultRetcode(),
" - ",
trade.ResultRetcodeDescription()
);
}
}
//+------------------------------------------------------------------+
//| Normalize price |
//+------------------------------------------------------------------+
double NormalizePrice(double price)
{
if(price == 0.0)
return 0.0;
int digits =
(int)SymbolInfoInteger(
_Symbol,
SYMBOL_DIGITS
);
return NormalizeDouble(price, digits);
}
//+------------------------------------------------------------------+
//| Draw BUY arrow |
//+------------------------------------------------------------------+
void DrawBuyArrow(datetime time, double price)
{
string name =
"Thinkwealth_V2_BUY_" +
IntegerToString((long)time);
if(ObjectFind(0, name) >= 0)
return;
if(ObjectCreate(
0,
name,
OBJ_ARROW,
0,
time,
price
))
{
ObjectSetInteger(
0,
name,
OBJPROP_ARROWCODE,
233
);
ObjectSetInteger(
0,
name,
OBJPROP_COLOR,
clrLime
);
ObjectSetInteger(
0,
name,
OBJPROP_WIDTH,
2
);
}
}
//+------------------------------------------------------------------+
//| Draw SELL arrow |
//+------------------------------------------------------------------+
void DrawSellArrow(datetime time, double price)
{
string name =
"Thinkwealth_V2_SELL_" +
IntegerToString((long)time);
if(ObjectFind(0, name) >= 0)
return;
if(ObjectCreate(
0,
name,
OBJ_ARROW,
0,
time,
price
))
{
ObjectSetInteger(
0,
name,
OBJPROP_ARROWCODE,
234
);
ObjectSetInteger(
0,
name,
OBJPROP_COLOR,
clrRed
);
ObjectSetInteger(
0,
name,
OBJPROP_WIDTH,
2
);
}
}
//+------------------------------------------------------------------+
//| Signal alert |
//+------------------------------------------------------------------+
void SendSignalAlert(string signal)
{
string message =
"Thinkwealth Smart Signal Pro EA V2 | " +
signal +
" SIGNAL | " +
_Symbol +
" | M5";
Print(message);
if(InpEnableAlerts)
Alert(message);
if(InpEnableSound)
PlaySound(InpSoundFile);
}
//+------------------------------------------------------------------+
//| Trailing stop |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
if(!PositionSelect(_Symbol))
return;
ulong magic =
(ulong)PositionGetInteger(POSITION_MAGIC);
if(magic != InpMagicNumber)
return;
ENUM_POSITION_TYPE type =
(ENUM_POSITION_TYPE)
PositionGetInteger(POSITION_TYPE);
double currentSL =
PositionGetDouble(POSITION_SL);
double currentTP =
PositionGetDouble(POSITION_TP);
double bid =
SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask =
SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double newSL = 0.0;
if(type == POSITION_TYPE_BUY)
{
newSL =
bid -
InpTrailingStopPoints * _Point;
newSL = NormalizePrice(newSL);
if(currentSL == 0.0 || newSL > currentSL)
{
trade.PositionModify(
_Symbol,
newSL,
currentTP
);
}
}
else if(type == POSITION_TYPE_SELL)
{
newSL =
ask +
InpTrailingStopPoints * _Point;
newSL = NormalizePrice(newSL);
if(currentSL == 0.0 || newSL < currentSL)
{
trade.PositionModify(
_Symbol,
newSL,
currentTP
);
}
}
}
//+------------------------------------------------------------------+
//| END OF EXPERT ADVISOR |
//+------------------------------------------------------------------+