img

Building a Simple Trading Bot in MetaTrader 5 (MT5)

img
valuezone 19 November 2023

Building a Simple Trading Bot in MetaTrader 5 (MT5)

We’ll break down the provided code, explaining its structure and functionality, to help you understand how to create your own automated trading system.


Environment Setup:

#include <Trade/Trade.mqh>

CTrade trade;
void ClosePosition(){}
ulong trade_ticket = 0;
bool time_passed = true;
int operacion_abierta = 0;
double price_flag = 0;

Explanation:

  • The #include <Trade/Trade.mqh> statement includes the Trade library, providing trading functions.
  • CTrade trade; creates an instance of the CTrade class for managing trading operations.
  • trade_tickettime_passedoperacion_abierta, and price_flag are variables for tracking trade information.

Handlers and Settings:

int stoch_h, rsi_h;
input int startHour = 8;
input int stopHour = 16;
input double coef_BUY_TP = 1.02;
input double coef_BUY_SL = 0.095;
input double coef_SELL_TP = 0.99;
input double coef_SELL_SL = 1.005;
input double Lot_size_BUY = 0.1;
input double Lot_size_SELL = 0.1;

Explanation:

  • stoch_h and rsi_h store the handlers for Stochastic and RSI indicators.
  • startHour and stopHour define the start and stop hours for trading.
  • Coefficients and lot sizes for buy and sell operations are specified as input parameters.

Signal Arrays:

double stoch0[], stoch1[], rsi[];
double global_TP = 0;
double global_SL = 0;
double global_lotsize = 0.1;
datetime global_trading_time = 0;
MqlRates price_information[];

Explanation:

  • Arrays (stoch0stoch1rsi) store indicator values.
  • global_TPglobal_SLglobal_lotsize, and global_trading_time hold global trade information.
  • price_information is an array for storing historical price data.

Candle Array and Constants:

int CANDLES_TO_USE = 10;
int CANDLES_TO_CHECK = 20;
int TS = 530;
int MARGIN = 30;
int TP = 600;
int SL = 200;

Explanation:

  • Constants CANDLES_TO_USE and CANDLES_TO_CHECK define the number of candles for different purposes.
  • TSMARGINTP, and SL set parameters for trailing stop, margin, take profit, and stop loss.

This is the first part of the code breakdown. Let me know if you’d like to continue with the next sections!

Trade Handling Function: handle_trade

void handle_trade(ulong t_ticket)
{
ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

double new_sl = 0, new_tp = 0;
double cur_price = PositionGetDouble(POSITION_PRICE_CURRENT);

if(type == POSITION_TYPE_BUY && cur_price > price_flag)
{
price_flag += 20*_Point;
new_tp = cur_price+MARGIN*_Point;
new_sl = cur_price-MARGIN*_Point*3;
trade.PositionModify(trade_ticket, new_sl, new_tp);
}
else if(type == POSITION_TYPE_SELL && cur_price < price_flag)
{
price_flag -= 20*_Point;
new_tp = cur_price-MARGIN*_Point;
new_sl = cur_price+MARGIN*_Point*3;
trade.PositionModify(trade_ticket, new_sl, new_tp);
}
}

Explanation:

  • This function is responsible for modifying the stop loss and take profit during market movements.
  • It checks the type of the current position (buy or sell) and adjusts SL and TP accordingly.

Initialization Function: OnInit

int OnInit()
{
/* Handlers */
stoch_h = iStochastic(_Symbol, _Period, 5, 3, 3, MODE_SMA, STO_LOWHIGH);
rsi_h = iRSI(_Symbol, _Period, 14, PRICE_CLOSE);

/* Settings the arrays */
ArraySetAsSeries(stoch0, true);
ArraySetAsSeries(stoch1, true);
ArraySetAsSeries(rsi, true);
ArraySetAsSeries(price_information, true);

return(INIT_SUCCEEDED);
}

Explanation:

  • The OnInit function initializes the Expert Advisor.
  • It sets up handlers for Stochastic and RSI indicators, and it configures the necessary arrays.

Signal Generation Functions: stoch_sell_signalstoch_buy_signalrsi_buy_signalrsi_sell_signal

bool stoch_sell_signal()
{
if(stoch0[0] > 80 && stoch1[0] > 80)
return true;

return false;
}

bool stoch_buy_signal()
{
if(stoch0[0] < 20 && stoch1[0] < 20)
return true;

return false;
}

bool rsi_buy_signal()
{
return rsi[0] > 50;
}

bool rsi_sell_signal()
{
return rsi[0] < 50;
}

Explanation:

  • These functions generate signals based on Stochastic and RSI conditions.
  • For example, stoch_sell_signal returns true if both Stochastic lines are above 80.

Trading Time Validation Function: IsTradingAllowed

bool IsTradingAllowed()
{
datetime currentServerTime = TimeCurrent();

MqlDateTime timeInfo;
TimeToStruct(currentServerTime, timeInfo);
int currentHour = timeInfo.hour;

if (currentHour >= startHour && currentHour < stopHour)
{
return true; // Trading is allowed
}
else
{
return false; // Trading is not allowed
}
}

Explanation:

  • This function checks if the current hour is within the specified trading hours (startHour to stopHour).

~~~FULL CODE~~~

#include <Trade/Trade.mqh>

CTrade trade;
void ClosePosition(){}
ulong trade_ticket = 0;
bool time_passed = true;
int operacion_abierta = 0;
double price_flag = 0;
/* Handlers */
int stoch_h, rsi_h;
// Define the start and stop hours for trading
input int startHour = 8;
input int stopHour = 16;
input double coef_BUY_TP = 1.02 ;
input double coef_BUY_SL = 0.095 ;
input double coef_SELL_TP = 0.99 ;
input double coef_SELL_SL = 1.005 ;
input double Lot_size_BUY = 0.1 ;
input double Lot_size_SELL = 0.1 ;
/* Signal arrays */
double stoch0[], stoch1[], rsi[];
double global_TP = 0;
double global_SL = 0;
double global_lotsize = 0.1; // Set your initial lot size here
datetime global_trading_time = 0;
/* Candle array */
MqlRates price_information[];

int CANDLES_TO_USE = 10;
int CANDLES_TO_CHECK = 20; // For sl and tp

/* TS and TP */
int TS = 530; // Trailing stop
int MARGIN = 30; // Margin
int TP = 600; // Take profit
int SL = 200; // Stop loss

//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void handle_trade(ulong t_ticket)
{
ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

double new_sl = 0, new_tp = 0;
double cur_price = PositionGetDouble(POSITION_PRICE_CURRENT);

/* Modifying the stop loss during the ticks */
if(type == POSITION_TYPE_BUY && cur_price > price_flag)
{
price_flag += 20*_Point;
new_tp = cur_price+MARGIN*_Point;
new_sl = cur_price-MARGIN*_Point*3;
trade.PositionModify(trade_ticket, new_sl, new_tp);
}
else
if(type == POSITION_TYPE_SELL && cur_price < price_flag)
{
price_flag -= 20*_Point;
new_tp = cur_price-MARGIN*_Point;
new_sl = cur_price+MARGIN*_Point*3;
trade.PositionModify(trade_ticket, new_sl, new_tp);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int OnInit()
{
/* Handlers */
stoch_h = iStochastic(_Symbol, _Period, 5, 3, 3, MODE_SMA, STO_LOWHIGH);
rsi_h = iRSI(_Symbol, _Period, 14, PRICE_CLOSE);

/* Settings the arrays */
ArraySetAsSeries(stoch0, true);
ArraySetAsSeries(stoch1, true);
ArraySetAsSeries(rsi, true);
ArraySetAsSeries(price_information, true);

return(INIT_SUCCEEDED);
}

/**** Private functions ****/

//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool stoch_sell_signal()
{
if(stoch0[0] > 80 && stoch1[0] > 80)
return true;

return false;
}

//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool stoch_buy_signal()
{
if(stoch0[0] < 20 && stoch1[0] < 20)
return true;
return false;
}

//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool rsi_buy_signal()
{
return rsi[0] > 50;
}

//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool rsi_sell_signal()
{
return rsi[0] < 50;
}


bool IsTradingAllowed()
{
datetime currentServerTime = TimeCurrent();

// Get the current hour using StructTime
MqlDateTime timeInfo;
TimeToStruct(currentServerTime, timeInfo);
int currentHour = timeInfo.hour;

// Check if the current hour is within the allowed trading hours
if (currentHour >= startHour && currentHour < stopHour)
{
return true; // Trading is allowed
}
else
{
return false; // Trading is not allowed
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double nearest_high()
{
int i = 0;
double high = 0;

for(i = 0; i < CANDLES_TO_CHECK; i++)
if(high < price_information[i].close)
high = price_information[i].close;

return high;
}

//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double nearest_low()
{
int i = 0;
double low = 100000;

for(i = 0; i < CANDLES_TO_CHECK; i++)
if(low > price_information[i].close)
low = price_information[i].close;

return low;
}


//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnTick()
{
/* Loading indicator values */
CopyBuffer(stoch_h, MAIN_LINE, 0, CANDLES_TO_USE, stoch0);
CopyBuffer(stoch_h, SIGNAL_LINE, 0, CANDLES_TO_USE, stoch1);
CopyBuffer(rsi_h, 0, 0, CANDLES_TO_USE, rsi);
CopyRates(_Symbol, _Period, 0, CANDLES_TO_CHECK, price_information);

/* This won't allow two open operations at the same time */
if(PositionSelectByTicket(trade_ticket) == false){
trade_ticket = 0;}
/* Buy? */
if(trade_ticket == 0 && time_passed && operacion_abierta == 0
&& IsTradingAllowed()
&& stoch_buy_signal() // Current stoch is in buy
&& rsi_buy_signal()){ // Current rsi is in buy

/* Current price */
double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);

//--- Open Buy
double sl = coef_BUY_SL*Ask;
double tp = coef_BUY_TP*Ask ;
trade.Buy(Lot_size_BUY, _Symbol, Ask, sl, tp, NULL);
trade_ticket = trade.ResultOrder();
global_TP = tp;
global_SL = sl;
global_lotsize = Lot_size_BUY; // Update with your actual lot size
global_trading_time = TimeCurrent();
operacion_abierta = 2;}

if(operacion_abierta == 2
&& IsTradingAllowed()
&& stoch_sell_signal() // Current stoch is in sell
&& rsi_sell_signal()){ // Current rsi is in sell
double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);
double sl = coef_SELL_SL*Bid;
double tp = coef_SELL_TP*Bid;
trade.PositionClose(_Symbol);
trade.Sell(Lot_size_SELL, _Symbol, Bid, sl, tp, NULL);
trade_ticket = trade.ResultOrder();
global_TP = tp;
global_SL = sl;
global_lotsize = Lot_size_SELL; // Update with your actual lot size
global_trading_time = TimeCurrent();
operacion_abierta = 3;
}
if(trade_ticket == 0 && time_passed
&& operacion_abierta == 0
&& IsTradingAllowed()
&& stoch_sell_signal() // Current stoch is in sell
&& rsi_sell_signal()){ // Current rsi is in sell
double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);
double sl = coef_SELL_SL*Bid;
double tp = coef_SELL_TP*Bid;
global_TP = tp;
global_SL = sl;
global_lotsize = Lot_size_SELL; // Update with your actual lot size
global_trading_time = TimeCurrent();
trade.Sell(Lot_size_SELL, _Symbol, Bid, sl, tp, NULL);
trade_ticket = trade.ResultOrder();
operacion_abierta = 3;

}
if(operacion_abierta == 3
&& IsTradingAllowed()
&& stoch_buy_signal() // Current stoch is in sell
&& rsi_buy_signal()){ // Current rsi is in sell
double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
double sl = coef_BUY_SL*Ask;
double tp = coef_BUY_TP*Ask ;
trade.PositionClose(_Symbol);
global_TP = tp;
global_SL = sl;
global_lotsize = Lot_size_BUY; // Update with your actual lot size
global_trading_time = TimeCurrent();
trade.Buy(Lot_size_BUY, _Symbol, Ask, sl, tp, NULL);
trade_ticket = trade.ResultOrder();
operacion_abierta = 2;



}
// Displaying information in the chart
string info = StringFormat("Lot Size: %.2f\nTP: %.5f\nSL: %.5f\nTrading Time: %s",
global_lotsize, global_TP, global_SL, TimeToString(global_trading_time));
Comment(info);
}


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

Understanding the provided MQL5 code is a crucial step in building your own trading bot. It covers key aspects such as indicator signals, trade management, and environment setup. As you delve deeper into algorithmic trading with MT5, you can customize and expand upon this code to create more sophisticated EAs tailored to your trading strategy.

Remember to thoroughly test your strategies on historical data and consider the associated risks before deploying them in live trading environments.