The Simplest Way to Manage Your Expert Advisor Trades on MetaTrader
So, you’ve developed a fantastic trading algorithm.
You’ve invested time into building it into an Expert Advisor. You’re excited, pumped! It’s go time!
Then you realize something.
How can you make sure your trading bot only trades a certain number of trades?
For instance, if you’re trading the RSI, you might not want to enter every. single. candle. while the RSI stays below your RSI low value.
In this article, I’ll show you how you can get your EA to automanage your trades.
About This Series
In this series, I cover everything you need to build your own advanced Expert Advisor from scratch. I cover:
- How to get started
- Using built in technical indicators from MetaTrader
- Making your EA autotrade
- Adding some simple-yet-powerful risk management techniques to your EA
- Backtesting and Optimizing your soon-to-be-awesome algorithm
- Adding some advanced features
All of the code that I use is available on my public GitHub repo, and each episode contains working code snippets you can immediately use in your own trading bot.
If you’d like some more general help, join our Discord server here, and if you prefer content in a video format, you can check out my YouTube channel here.
Get the Code on GitHub
Get working code on my GitHub, linked below:
About This Episode
In this episode, I’ll show you a simple way to manage your Expert Advisor trades.
What You’ll Need to Complete This Episode
- A working MT5 terminal
- A working algorithm which is autotrading. If you’d like to learn how to build one using the RSI, check out this article.
Why You Need Trade Management in Your Expert Advisor
When you set your Expert Advisor to autotrade, you are handing over your trading decisions to your trading bot. While this can be a great thing, and many traders use it to eliminate things like emotions and downtime while sleeping, it also means that you need a way to manage your trades.
For instance, in previous episodes, I’ve been demonstrating how to build an autotrading EA that uses the RSI technical indicator. Without order management, I could end up with a situation where my trading bot keeps opening up trades every time the RSI goes above or below the RSIHigh
and RSILow
values I’ve set.
To demonstrate, have a look at this screenshot of all my trades:
While this is an extreme example where I was using the Current Close
value, it does a demonstrate a critical requirement for my trading bot EA:
I need a way to restrict how many trades my Expert Advisor enters simultaneously
Without it I am at risk of:
- Stacking my losses
- Generating margin calls (especially if my lot size was greater than 0.1)
- Losing track of my risk management
So let’s start adding in some order management
Adding Trade Management to Your Trading Bot
For the simplest of order management approaches, there are two items we must manage:
- Orders — these are trades we have proposed but not yet converted into positions. This is more relevant if you are using Stop trades, such as a Buy Stop or Sell Stop.
- Positions — these are trades where we have converted a BUY or SELL order into an actual position. I.e. we have $$$ on the line!
The Trade Management Function
In the interests of keeping all our code nice and neat, we will be collecting all our order management into one function: TradeManagement()
. This function will be responsible for:
- Managing the concurrent number of trades we have (this episode)
- Managing current open positions (in a later episode)
- Tracking the number trades made in a single session (in a later episode)
To manage the concurrent number of trades, we need to make sure that the sum of orders and positions is less than or equal to the number of trades we desire.
Getting Your EA to Manage the Number of Concurrent Trades You Enter
To get started, we’re going to assume that your EA should not allow any more than one trade to be active at any given time.
Add the code below to your EA, above the OnTick()
function if you are following the series:
//+------------------------------------------------------------------+
//| TradeManagement Function |
//+------------------------------------------------------------------+
bool TradeManagement(){
// Get the total number of orders
int totalOrders = OrdersTotal();
// Get the total number of positions
int totalPositions = PositionsTotal();
// If there are no orders or positions, return true
if(totalOrders == 0 && totalPositions == 0){
return(true);
}else{
int totalTrades = totalOrders + totalPositions;
if (totalTrades < 1){
return (true);
}else{
return (false);
}
}
}
This function:
- Gets the number of existing orders and positions
- Sums them together
- Returns
true
if the number of trades is below the threshold of 1 - Returns
false
otherwise
Update OnTick()
Next, we need to incorporate these updates into the OnTick()
function. For code efficiencies sake, we’re going to make a design decision here that the first check that OnTick()
will make is to see if it can do any more trades.
Update your OnTick()
so that it looks like this:
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
bool tradeManagement = TradeManagement();
if(tradeManagement == true){
double rsi = GetRSI();
string signal = RSIAlgorithm(rsi);
bool success = OnSignal(signal);
}
}
Compile + Run 💻
Compile your code and add it to your MT5.
Congratulations, you’ve just added some simple Trade Management to Your EA!
Make Trade Management More Dynamic
Of course, you might prefer to a have different number of trades open. Depending on what you’re trying to do with your trading, maybe you want 2 or even 3 trades open at a time.
To do this, we’ll be adding a new input
parameter to your trading bot.
Start by adding this line to the bottom of all your current input
parameters:
input int concurrentTrades = 1; // Maximum number of concurrent trades
Then, update your TradeManagement()
function to include this input parameter, as follows:
//+------------------------------------------------------------------+
//| TradeManagement Function |
//+------------------------------------------------------------------+
bool TradeManagement(){
// Get the total number of orders
int totalOrders = OrdersTotal();
// Get the total number of positions
int totalPositions = PositionsTotal();
// If there are no orders or positions, return true
if(totalOrders == 0 && totalPositions == 0){
return(true);
}else{
int totalTrades = totalOrders + totalPositions;
if (totalTrades < concurrentTrades){
return (true);
}else{
return (false);
}
}
}
Compile + Run 💻
Compile your code and test it out.
Wrapping Up
By now you’ve got a fully featured EA which will happily trade away whenever the markets for your chose asset are open.
Pretty cool!
However, you might be wondering:
How could I test this algorithm to see if it actually works?
In the next episode, I’ll show you how to use the built in MT5 backtester to learn how to do that.
List of Articles in this Series
- Build Your Own AutoTrading MetaTrader 5 Expert Advsior
- The Easiest Way to Add the RSI Indicator to Your MetaTrader 5 EA
- The Easiest RSI Algorithm for Your MetaTrader Expert Advisor
- The Easiest Way to Place BUY and Sell Orders with your MetaTrader EA
- The Simplest Way to Manage Your Expert Advisor Trades on MetaTrader
- Four Simple Steps to Backtest and Optimize Your EA on MetaTrader 5
Connect With Me
My name is James, and you’ll often see me online using the AppnologyJames handle. Although my background and training is in Cyber Security, I’ve spend the last few years building trading algorithms for clients, along with a powerful market analysis platform called TradeOxy.
I love hearing from my readers and viewers, so feel free to reach out and connect with me:
- On YouTube
- Through TradeOxy
- On my Discord Channel
- On LinkedIn
Full Code for this Article
//+------------------------------------------------------------------+
//| RSI_EA_from_TradeOxy.mq5 |
//| AppnologyJames, TradeOxy.com |
//| https://www.tradeoxy.com |
//+------------------------------------------------------------------+
// CTrade Class
#include <Trade\Trade.mqh>
input bool liveRSIPrice = false; // Use live RSI price?
input int rsiHigh = 70; // RSI High threshold
input int rsiLow = 30; // RSI Low threshold
input int takeProfitPips = 20; // Take Profit in Pips
input int stopLossPips = 10; // Stop Loss in Pips
input double lotSize = 0.1; // Lot Size
input int concurrentTrades = 1; // Maximum number of concurrent trades
// Declare Global Variables
CTrade trade; // Trade Object
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Print the name of the Expert Advisor and a Welcome message
Print("RSI Trading Bot Expert Advisor from TradeOxy.com");
// Return value of initialization
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Deinitialization code
Print("Expert advisor deinitialized. Reason: ", reason);
}
//+------------------------------------------------------------------+
//| GetRSI |
//+------------------------------------------------------------------+
double GetRSI()
{
// Initialize a buffer
double rsiBuffer[];
// Make it into an array
ArraySetAsSeries(rsiBuffer, true);
// Get the RSI Handle
int rsiHandle = iRSI(_Symbol, _Period, 14, PRICE_CLOSE);
// If the handle is invalid, return 0
if (rsiHandle == INVALID_HANDLE)
{
return(0);
}
// Copy the RSI values to the buffer
int rsiCount = CopyBuffer(rsiHandle, 0, 0, 2, rsiBuffer);
// If the copy failed, return 0
if (rsiCount == 0)
{
return(0);
}
// Get the actual RSI value
if(liveRSIPrice == true)
{
double rsi = rsiBuffer[0];
return(rsi);
}else{
double rsi = rsiBuffer[1];
return(rsi);
}
}
//+------------------------------------------------------------------+
//| RSIAlgorithm Function |
//+------------------------------------------------------------------+
string RSIAlgorithm(double rsiValue){
// See if the value is below the 30 threshold
if(rsiValue < rsiLow){
return("BUY");
// See if the value is above the 70 threshold
}else if (rsiValue > rsiHigh){
return("SELL");
// Otherwise return HOLD
}else{
return("HOLD");
}
}
//+------------------------------------------------------------------+
// OnSignal Function |
//+------------------------------------------------------------------+
bool OnSignal(string signal){
// Get the current ask price
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
// Get the pip size for the current symbol
double pointSize = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
// Multiply the point size by 10 to get pips
double pipSize = pointSize * 10;
// Get the Take Profit, which is the pipSize * takeProfitPips
double takeProfitSize = pipSize * takeProfitPips;
// Get the Stop Loss, which is the pipSize * stopLossPips
double stopLossSize = pipSize * stopLossPips;
if(signal == "BUY"){
// Make the Take Profit above the current price
double takeProfit = ask + takeProfitSize;
// Make the Stop Loss below the current price
double stopLoss = ask - stopLossSize;
// Open a Buy Order
trade.Buy(lotSize, _Symbol, ask, stopLoss, takeProfit, "RSI Tutorial EA");
return(true);
}else if(signal == "SELL"){
// Make the Take Profit below the current price
double takeProfit = ask - takeProfitSize;
// Make the Stop Loss above the current price
double stopLoss = ask + stopLossSize;
// Open a Sell Order
trade.Sell(lotSize, _Symbol, ask, stopLoss, takeProfit, "RSI Tutorial EA");
return(true);
}else if (signal == "HOLD"){
return(true);
}else{
return(false);
}
}
//+------------------------------------------------------------------+
//| TradeManagement Function |
//+------------------------------------------------------------------+
bool TradeManagement(){
// Get the total number of orders
int totalOrders = OrdersTotal();
// Get the total number of positions
int totalPositions = PositionsTotal();
// If there are no orders or positions, return true
if(totalOrders == 0 && totalPositions == 0){
return(true);
}else{
int totalTrades = totalOrders + totalPositions;
if (totalTrades < concurrentTrades){
return (true);
}else{
return (false);
}
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
bool tradeManagement = TradeManagement();
if(tradeManagement == true){
double rsi = GetRSI();
string signal = RSIAlgorithm(rsi);
bool success = OnSignal(signal);
}
}