0% found this document useful (0 votes)
160 views9 pages

First Role - mq5

The document is a MetaTrader 5 Expert Advisor (EA) script designed for automated trading based on specific technical indicators like ATR, Bollinger Bands, RSI, and EMA. It includes user-configurable parameters for trading settings, risk management, and indicator periods, and implements functions for trade execution and signal generation. The EA checks for existing positions, calculates trade parameters, and places buy or sell orders based on trading signals derived from the indicators.

Uploaded by

muhapikarim
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
160 views9 pages

First Role - mq5

The document is a MetaTrader 5 Expert Advisor (EA) script designed for automated trading based on specific technical indicators like ATR, Bollinger Bands, RSI, and EMA. It includes user-configurable parameters for trading settings, risk management, and indicator periods, and implements functions for trade execution and signal generation. The EA checks for existing positions, calculates trade parameters, and places buy or sell orders based on trading signals derived from the indicators.

Uploaded by

muhapikarim
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 9

//+------------------------------------------------------------------+

//| TranslatedPythonBotEA.mq5 |
//| Based on Python Bot Logic Mentor |
//| Your Name Here |
//+------------------------------------------------------------------+
#property copyright "Your Name Here"
#property link "Your Link Here"
#property version "1.01" // Incremented version
#property strict

// Include necessary standard library files


#include <Trade\Trade.mqh> // For CTrade class (trading functions)
#include <Trade\SymbolInfo.mqh> // For CSymbolInfo class (symbol properties)
#include <Trade\AccountInfo.mqh> // For CAccountInfo class (account properties)

// --- Input Parameters (User-configurable EA settings) ---


input group "Symbol & Timeframe Settings"
// string InpSymbolToTrade = "Volatility 75 Index"; // EA uses
_Symbol (chart symbol) by default
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_M1; //
Timeframe for indicator calculations

input group "Indicator Parameters"


input int InpATRPeriod = 14;
input int InpBBandsPeriod = 20;
input double InpBBandsStdDev = 2.0;
input int InpRSIPeriod = 14;
input int InpEMAFastPeriod = 12;
input int InpEMASlowPeriod = 50;

input group "Risk & Trade Management"


input double InpRiskPerTradePercent = 1.0; // e.g., 1.0 for 1% of
equity
input double InpATR_SL_Multiplier = 1.5; // Stop Loss based on ATR *
Multiplier
input double InpATR_TP_Multiplier = 3.0; // Take Profit based on ATR
* Multiplier
input int InpDefaultSLPips = 100; // Fallback Stop Loss in
Pips if ATR fails
input int InpDefaultTPPips = 200; // Fallback Take Profit in
Pips if ATR fails
input ulong InpBotMagicNumber = 23052025; // Unique Magic Number
for this EA's trades
input int InpSlippagePips = 20; // Max allowed slippage in
points (not pips)

// --- Global Variables ---


CTrade trade; // Trading object from Trade.mqh
CSymbolInfo symbol; // Symbol information object from SymbolInfo.mqh
CAccountInfo account; // Account information object from
AccountInfo.mqh
string G_CurrentSymbol; // Stores the symbol the EA is running on

// Indicator Handles (to store references to initialised indicators)


int h_ATR;
int h_BB;
int h_RSI;
int h_EMAFast;
int h_EMASlow;
// Arrays to store indicator and price data
double atr_buffer[];
double bb_main_buffer[]; // Bollinger Bands Middle line
double bb_upper_buffer[]; // Bollinger Bands Upper line
double bb_lower_buffer[]; // Bollinger Bands Lower line
double rsi_buffer[];
double ema_fast_buffer[];
double ema_slow_buffer[];
MqlRates rates[]; // For OHLC, Time, Volume (price data)

//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
G_CurrentSymbol = _Symbol; // Get the symbol of the chart the EA is attached to
PrintFormat("OnInit: EA Starting on symbol %s, timeframe %s", G_CurrentSymbol,
EnumToString(InpTimeframe));

// Initialize SymbolInfo and AccountInfo objects


if(!symbol.Name(G_CurrentSymbol)) // Set the symbol for the CSymbolInfo object
{
PrintFormat("Error setting symbol '%s' for CSymbolInfo: %d", G_CurrentSymbol,
GetLastError());
return(INIT_FAILED);
}
account.Refresh(); // Refresh account data (initial fetch)

// Initialize CTrade object (for sending trade orders)


trade.SetExpertMagicNumber(InpBotMagicNumber);
trade.SetDeviationInPoints(InpSlippagePips); // Set allowed slippage for
orders
trade.SetTypeFillingBySymbol(G_CurrentSymbol); // Auto-detect filling mode,
or set specific like ORDER_FILLING_IOC

// --- Initialize Indicator Handles ---


h_ATR = iATR(G_CurrentSymbol, InpTimeframe, InpATRPeriod);
if(h_ATR == INVALID_HANDLE) { PrintFormat("Error creating ATR indicator: %d",
GetLastError()); return(INIT_FAILED); }

h_BB = iBands(G_CurrentSymbol, InpTimeframe, InpBBandsPeriod, 0,


InpBBandsStdDev, PRICE_CLOSE);
if(h_BB == INVALID_HANDLE) { PrintFormat("Error creating Bollinger Bands
indicator: %d", GetLastError()); return(INIT_FAILED); }

h_RSI = iRSI(G_CurrentSymbol, InpTimeframe, InpRSIPeriod, PRICE_CLOSE);


if(h_RSI == INVALID_HANDLE) { PrintFormat("Error creating RSI indicator: %d",
GetLastError()); return(INIT_FAILED); }

h_EMAFast = iMA(G_CurrentSymbol, InpTimeframe, InpEMAFastPeriod, 0, MODE_EMA,


PRICE_CLOSE);
if(h_EMAFast == INVALID_HANDLE) { PrintFormat("Error creating Fast EMA
indicator: %d", GetLastError()); return(INIT_FAILED); }

h_EMASlow = iMA(G_CurrentSymbol, InpTimeframe, InpEMASlowPeriod, 0, MODE_EMA,


PRICE_CLOSE);
if(h_EMASlow == INVALID_HANDLE) { PrintFormat("Error creating Slow EMA
indicator: %d", GetLastError()); return(INIT_FAILED); }
// Set arrays as series (important for correct indexing: latest data at index 0)
ArraySetAsSeries(rates, true);
ArraySetAsSeries(atr_buffer, true);
ArraySetAsSeries(bb_main_buffer, true);
ArraySetAsSeries(bb_upper_buffer, true);
ArraySetAsSeries(bb_lower_buffer, true);
ArraySetAsSeries(rsi_buffer, true);
ArraySetAsSeries(ema_fast_buffer, true);
ArraySetAsSeries(ema_slow_buffer, true);

Print("OnInit: Initialization successful.");


return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
PrintFormat("OnDeinit: EA Stopping. Reason code: %d", reason);
// Release indicator handles to free resources
IndicatorRelease(h_ATR);
IndicatorRelease(h_BB);
IndicatorRelease(h_RSI);
IndicatorRelease(h_EMAFast);
IndicatorRelease(h_EMASlow);
}

//+------------------------------------------------------------------+
//| Expert tick function (called on every new price tick) |
//+------------------------------------------------------------------+
void OnTick()
{
// --- 0. Check if trading is allowed ---
if(!TerminalInfoInteger(TERMINAL_CONNECTED))
{
// Comment("Not connected to trade server."); // Optional: display status on
chart
return;
}
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
{
// Comment("Trading is not allowed on this account/server (TerminalInfo).");
return;
}
if(!MQLInfoInteger(MQL_TRADE_ALLOWED)) // Checks client terminal settings
{
// Comment("Trading is not allowed by client terminal settings (MQLInfo).");
return;
}
if(IsStopped()) // Check if EA was stopped from Experts tab
{
return;
}

// --- 1. Get Latest Data (OHLC and Indicators) ---


// Refresh symbol data (like current Ask/Bid, point size)
symbol.RefreshRates(); // Crucial for up-to-date Ask/Bid
// Copy price data (OHLCV) for a few recent bars
// Using 3 bars: index 0 = current (developing), 1 = last closed, 2 = bar before
last closed
if(CopyRates(G_CurrentSymbol, InpTimeframe, 0, 3, rates) < 3)
{
PrintFormat("Error copying rates for %s: %d", G_CurrentSymbol,
GetLastError());
return;
}

// Copy indicator buffers


// For signals, it's generally safer to use data from the most recently
COMPLETED bar (index 1)
int bars_to_copy = 3; // Copy data for a few bars
if(CopyBuffer(h_ATR, 0, 0, bars_to_copy, atr_buffer) < bars_to_copy)
{ Print("Error copying ATR buffer"); return; }
if(CopyBuffer(h_BB, 0, 0, bars_to_copy, bb_main_buffer) < bars_to_copy)
{ Print("Error copying BB Main buffer"); return; }
if(CopyBuffer(h_BB, 1, 0, bars_to_copy, bb_upper_buffer) < bars_to_copy)
{ Print("Error copying BB Upper buffer"); return; }
if(CopyBuffer(h_BB, 2, 0, bars_to_copy, bb_lower_buffer) < bars_to_copy)
{ Print("Error copying BB Lower buffer"); return; }
if(CopyBuffer(h_RSI, 0, 0, bars_to_copy, rsi_buffer) < bars_to_copy)
{ Print("Error copying RSI buffer"); return; }
if(CopyBuffer(h_EMAFast, 0, 0, bars_to_copy, ema_fast_buffer) < bars_to_copy)
{ Print("Error copying EMA Fast buffer"); return; }
if(CopyBuffer(h_EMASlow, 0, 0, bars_to_copy, ema_slow_buffer) < bars_to_copy)
{ Print("Error copying EMA Slow buffer"); return; }

// --- 2. Check for Existing Position by this Bot ---


if(CheckExistingPosition())
{
// Print("An active trade with magic number ", InpBotMagicNumber, " already
exists for ", G_CurrentSymbol);
return; // Don't open new trades if one is already open by this EA for this
symbol
}

// --- 3. Get Trading Signal ---


// Using data from index 1 (most recent fully closed bar) for signal generation
double ema_fast_prev = ema_fast_buffer[1];
double ema_slow_prev = ema_slow_buffer[1];
double rsi_prev = rsi_buffer[1]; // RSI on the last closed bar
// For EMA crossover, we need to compare the current state to the previous bar's
state
double ema_fast_bar2 = ema_fast_buffer[2]; // EMA fast on bar before previous
double ema_slow_bar2 = ema_slow_buffer[2]; // EMA slow on bar before previous

string signal = "HOLD";

// Buy signal: Fast EMA crossed ABOVE Slow EMA on the close of the last bar, AND
RSI is not overbought
if (ema_fast_bar2 <= ema_slow_bar2 && ema_fast_prev > ema_slow_prev && rsi_prev
< 70.0)
{
signal = "BUY";
}
// Sell signal: Fast EMA crossed BELOW Slow EMA on the close of the last bar,
AND RSI is not oversold
else if (ema_fast_bar2 >= ema_slow_bar2 && ema_fast_prev < ema_slow_prev &&
rsi_prev > 30.0)
{
signal = "SELL";
}

// Optional: Print signal status


// PrintFormat("Signal: %s, EMAFast(1):%.5f, EMASlow(1):%.5f, RSI(1):%.2f",
signal, ema_fast_prev, ema_slow_prev, rsi_prev);

// --- 4. If No Existing Position and Valid Signal, then Prepare and Execute
Trade ---
if(signal != "HOLD")
{
double current_atr_value = atr_buffer[1]; // Use ATR from the last closed bar
for stability
if(current_atr_value <= 0 || NormalizeDouble(current_atr_value,
symbol.Digits()) <= symbol.Point()/10.0) // Check if ATR is valid and not extremely
small
{
PrintFormat("ATR value (%.5f) is zero or too small. Using default Pips for
SL/TP.", current_atr_value);
// Convert default pips to price distance (points)
// A "pip" for Volatility Indices usually means the last digit shown, but
point is more precise
// If 1 pip = 10 points for your symbol (e.g. price 123.45, point = 0.01,
1 pip = 0.10 means 10 points)
// This needs careful checking for your specific VIX symbol. Assuming
InpDefaultSLPips means "points" for simplicity here.
// For true "pips", you'd need to know how many points constitute a pip
for that symbol.
// Let's assume InpDefaultSLPips are actually "points" as MT5 defines them
(smallest price change unit * InpDefaultSLPips)
double sl_distance_price_units = InpDefaultSLPips * symbol.Point();
double tp_distance_price_units = InpDefaultTPPips * symbol.Point();

if(sl_distance_price_units <=0 ) sl_distance_price_units = 100 *


symbol.Point(); // Min fallback
if(tp_distance_price_units <=0 ) tp_distance_price_units = 200 *
symbol.Point(); // Min fallback

PlaceTrade(signal, sl_distance_price_units, tp_distance_price_units);


}
else
{
// a. Calculate SL and TP distances in price units (e.g., for USDJPY, this
would be in JPY)
double sl_distance_price_units = current_atr_value * InpATR_SL_Multiplier;
double tp_distance_price_units = current_atr_value * InpATR_TP_Multiplier;
PlaceTrade(signal, sl_distance_price_units, tp_distance_price_units);
}
}
}

//+------------------------------------------------------------------+
//| Helper Function: Place Trade |
//+------------------------------------------------------------------+
void PlaceTrade(string signal_type, double sl_distance_price_units, double
tp_distance_price_units)
{
// b. Calculate Lot Size
double lot_size = CalculateLotSize(sl_distance_price_units);
if(lot_size < symbol.LotsMin())
{
PrintFormat("Calculated lot size %.2f is less than minimum allowed %.2f.
Skipping trade.", lot_size, symbol.LotsMin());
// Or optionally: lot_size = symbol.LotsMin(); if you want to trade min lot
return;
}

// c. Define SL and TP price levels


// Ensure symbol.RefreshRates() was called in OnTick for fresh Ask/Bid
double entry_price_ask = symbol.Ask();
double entry_price_bid = symbol.Bid();
double sl_price = 0.0;
double tp_price = 0.0;
string comment = "EA_Trade_" + TimeToString(TimeCurrent(), TIME_SECONDS);

if(signal_type == "BUY")
{
sl_price = entry_price_ask - sl_distance_price_units;
tp_price = entry_price_ask + tp_distance_price_units;
sl_price = NormalizeDouble(sl_price, symbol.Digits()); // Normalize to
symbol's decimal places
tp_price = NormalizeDouble(tp_price, symbol.Digits());

PrintFormat("Attempting BUY: Lot=%.2f, EntryAsk=%.*f, SL=%.*f, TP=%.*f",


lot_size, symbol.Digits(), entry_price_ask, symbol.Digits(),
sl_price, symbol.Digits(), tp_price);

if(!trade.Buy(lot_size, G_CurrentSymbol, entry_price_ask, sl_price, tp_price,


comment))
{
PrintFormat("BUY order failed: %d - %s", trade.ResultRetcode(),
trade.ResultComment());
}
else
{
PrintFormat("BUY order placed successfully. Ticket: %d",
(int)trade.ResultOrder());
}
}
else if(signal_type == "SELL")
{
sl_price = entry_price_bid + sl_distance_price_units;
tp_price = entry_price_bid - tp_distance_price_units;
sl_price = NormalizeDouble(sl_price, symbol.Digits());
tp_price = NormalizeDouble(tp_price, symbol.Digits());

PrintFormat("Attempting SELL: Lot=%.2f, EntryBid=%.*f, SL=%.*f, TP=%.*f",


lot_size, symbol.Digits(), entry_price_bid, symbol.Digits(),
sl_price, symbol.Digits(), tp_price);

if(!trade.Sell(lot_size, G_CurrentSymbol, entry_price_bid, sl_price,


tp_price, comment))
{
PrintFormat("SELL order failed: %d - %s", trade.ResultRetcode(),
trade.ResultComment());
}
else
{
PrintFormat("SELL order placed successfully. Ticket: %d",
(int)trade.ResultOrder());
}
}
}

//+------------------------------------------------------------------+
//| Helper Function: Calculate Lot Size based on Risk % and SL |
//+------------------------------------------------------------------+
double CalculateLotSize(double sl_distance_price_units) // sl_distance_price_units
is the distance from entry to SL in PRICE units
{
account.Refresh(); // Get latest account info
double acc_equity = account.Equity();
double risk_amount_deposit_currency = acc_equity * (InpRiskPerTradePercent /
100.0);

if(sl_distance_price_units <= symbol.Point() / 2.0) // SL distance too small or


zero
{
PrintFormat("SL distance (%.*f) is too small. Cannot accurately calculate lot
size. Using min lot.", symbol.Digits(), sl_distance_price_units);
return(symbol.LotsMin());
}

// Calculate value of 1 lot SL in deposit currency


// This requires knowing the value of a one-point move for the specific symbol.
// SYMBOL_TRADE_TICK_VALUE is the value of a SYMBOL_TRADE_TICK_SIZE move for 1
lot.
// If SYMBOL_TRADE_TICK_SIZE is not equal to SYMBOL_POINT, adjustment is needed.
double tick_value = symbol.TickValue(); // Value of a tick_size move for 1.0 lot
double tick_size = symbol.TickSize(); // Size of a tick (minimal price change
recognized by broker for contract)
double point_size = symbol.Point(); // Smallest possible price change (e.g.
0.00001 for EURUSD)

if(tick_size <= 0 || point_size <= 0)


{
Print("Symbol tick_size or point_size is zero or negative. Cannot calculate
lot. Using min lot.");
return(symbol.LotsMin());
}

// Value per point for 1 lot:


// (Value of a TickSize move / Number of Points in a TickSize move)
double value_per_point_one_lot = tick_value / (tick_size / point_size);

// Total value of the SL for 1 lot


double sl_value_for_one_lot = (sl_distance_price_units / point_size) *
value_per_point_one_lot;

if(sl_value_for_one_lot <= 0)
{
PrintFormat("SL value per lot (%.2f) is zero or negative. Cannot calculate
lot size. Using min lot.", sl_value_for_one_lot);
return(symbol.LotsMin());
}

double desired_lot_size = risk_amount_deposit_currency / sl_value_for_one_lot;

// Normalize lot size according to symbol's contract specification


double min_lot = symbol.LotsMin();
double max_lot = symbol.LotsMax(); // Make sure it's reasonable, some brokers
have high max_lot
double step_lot = symbol.LotsStep();

// Apply constraints
desired_lot_size = MathMax(min_lot, desired_lot_size);
if(max_lot > 0) desired_lot_size = MathMin(max_lot, desired_lot_size); // Only
apply max_lot if it's > 0

// Adjust to volume step: round down to the nearest valid step


if(step_lot > 0)
{
desired_lot_size = MathFloor(desired_lot_size / step_lot) * step_lot;
}

// Determine correct number of decimal places for lot size based on step_lot
int lot_digits = 0;
string step_str = DoubleToString(step_lot, 8);
int dot_pos = StringFind(step_str, ".");
if(dot_pos >= 0)
{
lot_digits = StringLen(step_str) - dot_pos - 1;
// Remove trailing zeros for correct digit count if step is e.g. 0.10
while(lot_digits > 0 && StringGetCharacter(step_str, StringLen(step_str) - 1)
== '0')
{
step_str = StringSubstr(step_str, 0, StringLen(step_str) -1);
lot_digits--;
}
}

desired_lot_size = NormalizeDouble(desired_lot_size, lot_digits);

// Final check against min_lot after normalization


if (desired_lot_size < min_lot) desired_lot_size = min_lot;

PrintFormat("LotCalc: Equity=%.2f, RiskAmt=%.2f, SL_Dist_Price=%.*f,


SL_Val_Per_Lot=%.2f, CalcLot=%.*f",
acc_equity, risk_amount_deposit_currency,
symbol.Digits(), sl_distance_price_units,
sl_value_for_one_lot,
lot_digits, desired_lot_size);

return(desired_lot_size);
}

//+------------------------------------------------------------------+
//| Helper Function: Check if a position by this EA already exists |
//+------------------------------------------------------------------+
bool CheckExistingPosition()
{
for(int i = PositionsTotal() - 1; i >= 0; i--) // Loop through all open
positions
{
ulong pos_ticket = PositionGetTicket(i); // Get ticket of position at
index i
if(pos_ticket == 0) continue; // Should not happen, but good
check

// Select the position to access its properties.


// No need to call PositionSelectByTicket() if directly getting properties by
ticket.
// However, some PositionGet Functions require the position to be pre-
selected by ticket or symbol/index.
// Let's select to be safe and consistent.
if(PositionSelectByTicket(pos_ticket))
{
if(PositionGetString(POSITION_SYMBOL) == G_CurrentSymbol &&
PositionGetInteger(POSITION_MAGIC) == InpBotMagicNumber)
{
return(true); // Position found for this symbol and magic number
}
}
else
{
PrintFormat("Error selecting position ticket %d: %d", (int)pos_ticket,
GetLastError());
}
}
return(false); // No matching position found
}
//+------------------------------------------------------------------+

You might also like