//+------------------------------------------------------------------+
//| AccurateTPBot_MT5.mq5 |
//| Copyright 2023, Your Name |
//| your.email.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Your Name"
#property link "your.email.com"
#property version "1.00"
#property strict
#include <Trade\Trade.mqh> // Standard Trading class
//--- Enums for user inputs
enum ENUM_LOT_SIZING_METHOD
{
LOT_FIXED, // Fixed Lot Size
LOT_RISK_PERCENT // Risk Percentage of Account Balance
};
enum ENUM_TP_METHOD
{
TP_FIXED_PIPS, // Take Profit in Fixed Pips
TP_RR_RATIO // Take Profit based on Risk:Reward Ratio
};
//--- Input Parameters
input group "Strategy Parameters"
input int FastEMA_Period = 10; // Fast EMA Period
input int SlowEMA_Period = 20; // Slow EMA Period
input group "Trade Management"
input ENUM_LOT_SIZING_METHOD LotSizingMethod = LOT_RISK_PERCENT; // Lot Sizing
Method
input double FixedLotSize = 0.01; // Fixed Lot Size (if
LOT_FIXED)
input double RiskPercent = 1.0; // Risk Percentage (if
LOT_RISK_PERCENT)
input int StopLossPips = 20; // Stop Loss in Pips
input ENUM_TP_METHOD TakeProfitMethod = TP_RR_RATIO; // Take Profit Method
input int TakeProfitPips = 40; // Take Profit in Pips (if
TP_FIXED_PIPS)
input double RiskRewardRatio = 2.0; // Risk:Reward Ratio
(e.g., 2 for 1:2)
input ulong MagicNumber = 13579; // Magic Number
input int Slippage = 3; // Slippage in points
input string OrderComment = "AccurateTPBot"; // Order Comment
//--- Global Variables
CTrade trade; // Trading object
string expert_name = "AccurateTPBot_MT5";
int min_bars_required = 100; // Minimum bars to start trading
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print(expert_name, " v", _Symbol, ", ", EnumToString(_Period), " Initialized.");
Print("Lot Sizing: ", EnumToString(LotSizingMethod));
Print("TP Method: ", EnumToString(TakeProfitMethod));
if(StopLossPips <= 0)
{
Print("Error: StopLossPips must be greater than 0.");
return(INIT_FAILED);
}
if(TakeProfitMethod == TP_FIXED_PIPS && TakeProfitPips <= 0)
{
Print("Error: TakeProfitPips must be greater than 0 for TP_FIXED_PIPS
method.");
return(INIT_FAILED);
}
if(TakeProfitMethod == TP_RR_RATIO && RiskRewardRatio <= 0)
{
Print("Error: RiskRewardRatio must be greater than 0 for TP_RR_RATIO
method.");
return(INIT_FAILED);
}
trade.SetExpertMagicNumber(MagicNumber);
trade.SetMarginMode(); // Use account's margin mode
trade.SetTypeFillingBySymbol(_Symbol); // Set filling type based on symbol
trade.SetDeviationInPoints(Slippage);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Print(expert_name, " Deinitialized. Reason: ", reason);
Comment(""); // Clear chart comment
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- Check if enough bars are loaded
if(Bars(_Symbol, _Period) < min_bars_required)
{
Comment("Waiting for bars...");
return;
}
Comment(""); // Clear waiting message
//--- Only trade once per new bar
static datetime prevBarTime = 0;
datetime currentBarTime = (datetime)SeriesInfoInteger(_Symbol, _Period,
SERIES_LASTBAR_DATE);
if(prevBarTime == currentBarTime)
{
return;
}
prevBarTime = currentBarTime;
//--- Check if a position for this EA already exists for this symbol
if(PositionSelectByTicket(GetOpenPositionTicket(_Symbol, MagicNumber)))
{
// Optional: Add trailing stop or other management for open positions here
return; // Don't open a new position if one exists
}
//--- Get Indicator Data (YOUR STRATEGY LOGIC GOES HERE)
double ema_fast_val[2]; // 0 current, 1 previous
double ema_slow_val[2];
if(CopyBuffer(iEMA(_Symbol, _Period, FastEMA_Period, 0, PRICE_CLOSE), 0, 0, 2,
ema_fast_val) < 2 ||
CopyBuffer(iEMA(_Symbol, _Period, SlowEMA_Period, 0, PRICE_CLOSE), 0, 0, 2,
ema_slow_val) < 2)
{
Print("Error copying indicator buffers.");
return;
}
// ArraySetAsSeries for easier reading [0] is current, [1] is previous
ArraySetAsSeries(ema_fast_val, true);
ArraySetAsSeries(ema_slow_val, true);
//--- Define Entry Signals (Replace with YOUR "Chart Assassins" logic)
bool buy_signal = false;
bool sell_signal = false;
// Buy Signal: Fast EMA crossed above Slow EMA on the previous bar
if(ema_fast_val[1] > ema_slow_val[1] && ema_fast_val[2] <= ema_slow_val[2])
{
buy_signal = true;
}
// Sell Signal: Fast EMA crossed below Slow EMA on the previous bar
else if(ema_fast_val[1] < ema_slow_val[1] && ema_fast_val[2] >= ema_slow_val[2])
{
sell_signal = true;
}
//--- END OF STRATEGY LOGIC EXAMPLE ---
//--- If signal, proceed to trade execution
if(buy_signal || sell_signal)
{
double lot_size = CalculateLotSize();
if(lot_size <= 0)
{
Print("Invalid lot size calculated: ", lot_size);
return;
}
double entry_price = buy_signal ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) :
SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(entry_price == 0) // Ensure valid price
{
Print("Invalid entry price: ", entry_price);
return;
}
double sl_price = CalculateStopLossPrice(buy_signal ? ORDER_TYPE_BUY :
ORDER_TYPE_SELL, entry_price);
double tp_price = CalculateTakeProfitPrice(buy_signal ? ORDER_TYPE_BUY :
ORDER_TYPE_SELL, entry_price, sl_price);
if(sl_price == 0)
{
Print("Stop Loss price is 0, cannot place trade.");
return;
}
// For TP = 0, it means no TP will be set (which is valid)
// For SL = 0, it means no SL (which we are preventing via OnInit check)
string signal_type_str = buy_signal ? "BUY" : "SELL";
PrintFormat("%s Signal on %s: Entry=%.5f, SL=%.5f, TP=%.5f, Lots=%.2f",
signal_type_str, _Symbol, entry_price, sl_price, tp_price,
lot_size);
bool result = false;
if(buy_signal)
{
result = trade.Buy(lot_size, _Symbol, entry_price, sl_price, tp_price,
OrderComment);
}
else if(sell_signal)
{
result = trade.Sell(lot_size, _Symbol, entry_price, sl_price, tp_price,
OrderComment);
}
if(result)
{
PrintFormat("Trade %s successfully placed. Ticket: %d", signal_type_str,
(int)trade.ResultDeal());
}
else
{
PrintFormat("Trade %s failed. Error: %d, Code: %d, Retcode: %d, Message:
%s",
signal_type_str,
trade.ResultRetcode(),
trade.ResultOrder(),
(int)trade.ResultRetcode(),
trade.ResultComment());
}
}
}
//+------------------------------------------------------------------+
//| Calculate Stop Loss Price |
//+------------------------------------------------------------------+
double CalculateStopLossPrice(ENUM_ORDER_TYPE order_type, double entry_price)
{
if(StopLossPips <= 0) return 0.0; // No SL
double sl_points = StopLossPips * _Point * (_Digits == 3 || _Digits == 5 ? 10 :
1); // Pips to Points
double sl_price = 0.0;
if(order_type == ORDER_TYPE_BUY)
{
sl_price = entry_price - sl_points;
}
else if(order_type == ORDER_TYPE_SELL)
{
sl_price = entry_price + sl_points;
}
return NormalizeDouble(sl_price, _Digits);
}
//+------------------------------------------------------------------+
//| Calculate Take Profit Price |
//+------------------------------------------------------------------+
double CalculateTakeProfitPrice(ENUM_ORDER_TYPE order_type, double entry_price,
double stop_loss_price)
{
double tp_pips = 0;
double tp_price = 0.0; // 0.0 means no TP
if(TakeProfitMethod == TP_FIXED_PIPS)
{
if(TakeProfitPips <= 0) return 0.0; // No TP if set to 0 or less
tp_pips = TakeProfitPips;
}
else if(TakeProfitMethod == TP_RR_RATIO)
{
if(RiskRewardRatio <= 0 || StopLossPips <= 0) return 0.0; // Cannot calculate
R:R TP without SL or valid ratio
tp_pips = StopLossPips * RiskRewardRatio;
}
else
{
return 0.0; // Unknown method or no TP
}
if(tp_pips <= 0) return 0.0; // Ensure positive TP pips
double tp_points = tp_pips * _Point * (_Digits == 3 || _Digits == 5 ? 10 :
1); // Pips to Points
if(order_type == ORDER_TYPE_BUY)
{
tp_price = entry_price + tp_points;
}
else if(order_type == ORDER_TYPE_SELL)
{
tp_price = entry_price - tp_points;
}
return NormalizeDouble(tp_price, _Digits);
}
//+------------------------------------------------------------------+
//| Calculate Lot Size |
//+------------------------------------------------------------------+
double CalculateLotSize()
{
double lot = FixedLotSize; // Default to fixed lot size
if(LotSizingMethod == LOT_RISK_PERCENT)
{
if(StopLossPips <= 0 || RiskPercent <= 0)
{
Print("Cannot calculate risk-based lot size: SL Pips or Risk Percent is
zero/negative.");
return 0.0;
}
double account_balance = AccountInfoDouble(ACCOUNT_BALANCE);
double risk_amount = account_balance * (RiskPercent / 100.0);
// Calculate value of 1 pip for 1 lot
double tick_value = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tick_size = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double point_value = _Point;
// Value of 1 point for 1 lot
double one_point_value_per_lot = tick_value; // SYMBOL_TRADE_TICK_VALUE is
often the value of one tick (which is one point movement) for 1 lot.
// Value of 1 pip for 1 lot
double one_pip_value_per_lot = one_point_value_per_lot * (_Digits == 3 ||
_Digits == 5 ? 10 : 1);
if(one_pip_value_per_lot == 0)
{
Print("Error: one_pip_value_per_lot is zero. Cannot calculate lot size.");
return 0.0;
}
double loss_per_lot_for_sl = StopLossPips * one_pip_value_per_lot;
if(loss_per_lot_for_sl == 0)
{
Print("Error: loss_per_lot_for_sl is zero. Cannot calculate lot size.");
return 0.0;
}
lot = risk_amount / loss_per_lot_for_sl;
}
//--- Normalize Lot Size to symbol's constraints
double min_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double max_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double lot_step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
lot = MathMax(min_lot, lot); // Ensure at least min lot
lot = MathMin(max_lot, lot); // Ensure not more than max lot
lot = MathRound(lot / lot_step) * lot_step; // Normalize to lot step
if (lot < min_lot) lot = 0.0; // If after normalization it's less than min_lot,
it's invalid.
return lot;
}
//+------------------------------------------------------------------+
//| Get open position ticket for the current symbol and magic number |
//+------------------------------------------------------------------+
ulong GetOpenPositionTicket(string symbol, ulong magic)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionGetSymbol(i) == symbol && PositionGetInteger(POSITION_MAGIC) ==
magic)
{
return PositionGetInteger(POSITION_TICKET);
}
}
return 0; // No open position found
}
//+------------------------------------------------------------------+