The Easiest Way to Place BUY and SELL Orders with your MetaTrader EA
There comes a point in every Expert Advisors life where the decision has to be made:
Will I just be a signal, or will become an autotrading EA?
If you’ve been following my series, then you’ll know that in the previous article, I showed you how to convert an RSI Indicator into an RSI Signal.
In this episode, I’m going to show you how to convert this signal into an actual trade.
Read on to learn more.
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.
About This Episode
In this episode, I’m going to show you a really easy way to make your EA autotrade.
What You’ll Need to Complete This Episode
- A working MT5 terminal
- A working RSI algorithm generating BUY, SELL, and HOLD signals. Check out this article for an example.
Working GitHub Code
Get the working GitHub code for this series below:
Introducing the CTrade Class from MQL5
The CTrade class, part of MQL5, is a super simple way to access all the trade functions in MT5.
The CTrade class has access to most, if not all, of the trading functions you might want to use in a trading bot. It’s also much simpler than trying to build a trade from ground up.
Add the CTrade Class to Your EA
We will start by adding the CTrade class to your EA. To do this, add the line below to your EA, right above your input
parameters:
// CTrade Class
#include <Trade\Trade.mqh>
Next, below your inputs, create a global variable called trade that uses the CTrade class. To do this, add the following code:
// Declare Global Variables
CTrade trade; // Trade Object
Creating A Simple Trade
Now we’re going to move on to creating a simple trade that your EA can execute whenever a trade signal is received.
Some Basic Risk Management
Before actually creating a trade, I’m going to define some simple risk management parameters we can use to get started. Later on in this article, I’ll show you how to parameterize them so that they can be fine-tuned by you.
Here they are:
- Stop Loss, or SL, will be 10 pips
- Take Profit, or TP, will be 20 pips
- Volume will 0.1
Create an OnSignal()
Function
Next, we’re going to create a new function called OnSignal()
. This function is responsible for dealing with the signals that are detected from your algorithm functions — i.e. RSIAlgorithm()
if you are following this series.
This function is going to perform the following actions:
- BUY — BUY an asset when a BUY Signal is received
- SELL — SELL an asset when a SELL Signal is received
- Do nothing otherwise
Here’s the initial framework for your function. It doesn’t really do much, but will allow us to get going:
//+------------------------------------------------------------------+
// OnSignal Function |
//+------------------------------------------------------------------+
bool OnSignal(string signal){
if(signal == "BUY"){
return(true);
}else if(signal == "SELL"){
return(true);
}else{
return(false);
}
}
Update OnSignal so that it can Place Trades
With the OnSignal()
function framework in place, let’s add in the ability to make BUY and SELL trades on your behalf.
For now, we’ll set all trades to happen at the current market price. In a future episode, I’ll show you how to adjust these trades to use STOP trades.
To update the function, we need to take into account a few things:
- The current price of the asset
- The Point Size of the asset (as different FOREX pairs can have different amounts)
- Setting the SL and TP for the different types of trade
Update your OnSignal()
function so that it looks like this. Note how the Pip Size is 10 x the Point Size:
//+------------------------------------------------------------------+
// 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;
if(signal == "BUY"){
// Make the Take Profit 20 pips above the current price
double takeProfit = ask + (pipSize * 20);
// Make the Stop Loss 10 pips below the current price
double stopLoss = ask - (pipSize * 10);
// Open a Buy Order
trade.Buy(0.1, _Symbol, ask, stopLoss, takeProfit, "RSI Tutorial EA");
return(true);
}else if(signal == "SELL"){
// Make the Take Profit 20 pips below the current price
double takeProfit = ask - (pipSize * 20);
// Make the Stop Loss 10 pips above the current price
double stopLoss = ask + (pipSize * 10);
// Open a Sell Order
trade.Sell(0.1, _Symbol, ask, stopLoss, takeProfit, "RSI Tutorial EA");
return(true);
}else{
return(false);
}
}
Update Your OnTick Function
Now let's add this function to your previously built OnTick()
function.
Update OnTick()
so that it looks like this:
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
double rsi = GetRSI();
string signal = RSIAlgorithm(rsi);
if(signal == "BUY"){
Print("BUY Signal Detected");
bool result = OnSignal(signal);
}else if(signal == "SELL"){
Print("SELL Signal Detected");
bool result = OnSignal(signal);
}
}
Compile + Run 💻
Compile you code and see it run.
You may need to wait for the RSI to hit one of the triggers, but once it does, it should work beautifully!
Parameterizing Your Trading
So far, your EA has been using hard-coded amounts for:
- Stop Loss
- Take Profit
- Volume
However, many times, traders like to adjust these values to suit various different assets and trading styles. So let’s parameterize these values so you can do the same.
Add Three Input Variables
If you’ve been following this series, you will currently have three inputs — liveRSIPrice
, rsiHigh
, rsiLow
. Now we will add three new ones:
takeProfitPips
— which allows you to adjust the number of pips for the Take Profit (or TP)stopLossPips
— which allows you to adjust the number of pips for the Stop Loss (or SL)volume
— which allows you to adjust the amount (or lot size) of each currency you will purchase
To do this, add the following three lines to your code, under your existing input
parameters:
input int takeProfitPips = 20; // Take Profit in Pips
input int stopLossPips = 10; // Stop Loss in Pips
input double lotSize = 0.1; // Lot Size
Integrate Parameters into OnSignal()
Now we need to integrate these parameters into the OnSignal()
function.
Update it so that it looks like this:
//+------------------------------------------------------------------+
// 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;
if(signal == "BUY"){
// Make the Take Profit above the current price
double takeProfit = ask + (pipSize * takeProfitPips);
// Make the Stop Loss below the current price
double stopLoss = ask - (pipSize * stopLossPips);
// 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 - (pipSize * takeProfitPips);
// Make the Stop Loss above the current price
double stopLoss = ask + (pipSize * stopLossPips);
// Open a Sell Order
trade.Sell(lotSize, _Symbol, ask, stopLoss, takeProfit, "RSI Tutorial EA");
return(true);
}else{
return(false);
}
}
Compile + Run 💻
Compile you code and see it run.
You may need to wait for the RSI to hit one of the triggers, but once it does, it should work beautifully!
Make Your Code DRY
Before we finish up, we’re going to make a couple of changes to make our code conform to the DRY principle.
What is the DRY Programming Principle
The DRY programming principle refers to a programming approach of “Don’t Repeate Yourself”. In essence, it means that any time you have repetitive code where you have repeated yourself, there is an opportunity to refactor your code.
There are several advantages to this:
- Reduces errors, as every repetition of your code offers a chance for something to go wrong
- Makes it easier to read your code
- Speeds up your development time
What Updates Can We Make to Our EA to Make it DRY?
If you check through the EA code so far, there are two updates we can make to improve our code:
OnSignal()
— this function has repeated the Take Profit and Stop Loss parameters in each of the signalsOnTick()
— this function uses the linebool result = OnSignal(signal)
line twice
I’m going to combine these changes into one update.
Update both of these functions so they look like this:
//+------------------------------------------------------------------+
// 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);
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
double rsi = GetRSI();
string signal = RSIAlgorithm(rsi);
bool success = OnSignal(signal);
}
Compile + Run 💻
Chuck a quick compile to make sure it’s still running!
Wrapping Up
By now you’ve got a really solid expert advisor up and running. It can even make trades on your behalf!
However, you might notice that we’ve got a critical problem due to the nature of the RSI. Your bot will place lots of trades whenever it hits the triggers you’ve put in.
This can be pretty catastrophic if you make a ton of losses.
In the next episode, I’ll show you how to manage your trades through Order Management.
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 Episode
//+------------------------------------------------------------------+
//| 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
// 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);
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
double rsi = GetRSI();
string signal = RSIAlgorithm(rsi);
bool success = OnSignal(signal);
}