This script is designed to automatically trade on the Forex market using the MetaTrader platform. It uses the Relative Strength Index (RSI), a popular technical indicator, to identify potential buying and selling opportunities. Here's a breakdown of how it works:
1. Initial Setup:
-
Settings: The script starts by defining various settings that you, the user, can adjust. These settings control how the script behaves, including:
- RSI parameters: The period used to calculate the RSI, and the levels that indicate when the market is potentially overbought (likely to fall) or oversold (likely to rise).
- Trade Management: Whether to use features like Take Profit (automatically close a trade when it reaches a certain profit level), Stop Loss (automatically close a trade when it reaches a certain loss level), and Trailing Stop (automatically adjust the Stop Loss as the trade becomes more profitable).
- Money Management: Whether to automatically calculate the trade size based on the account balance and risk percentage.
- Other parameters: Other parameters such as allowed slippage of trades and magic number.
-
Identification: The script also assigns a unique "magic number" to its trades to distinguish them from trades placed manually or by other automated systems.
2. Trading Logic - The Main Cycle:
-
Checking for Open Trades: The script first checks if it already has any open trades on the current currency pair.
-
If No Open Trades:
- Checking the RSI: It calculates the RSI based on the closing prices of recent candles (historical price data).
- Looking for Signals:
- If the RSI is below the "oversold" level, it considers this a potential "buy" signal, anticipating the price will rise.
- If the RSI is above the "overbought" level, it considers this a potential "sell" signal, anticipating the price will fall.
- Opening a Trade: If a buy or sell signal is identified, the script opens a trade. The trade size (number of lots) is determined either by a fixed amount or by the money management settings. The script also considers a moving average (MMSet) to confirm the direction of the trend before placing the trade.
- Setting Stop Loss and Take Profit: If enabled in the settings, the script sets a Stop Loss and/or Take Profit order for the new trade.
-
If Open Trades Exist:
- Checking for Exit Signals: The script checks if the RSI is giving an exit signal for any existing trades. For example, if it has a buy trade open, it will see if the RSI has reached the "overbought" level and is starting to turn down, which might indicate it's time to close the trade.
- Closing Trades: If an exit signal is detected, the script closes the corresponding trade.
- Trailing Stop Management: If the trailing stop feature is enabled, the script adjusts the Stop Loss of existing trades to lock in profits as the price moves in a favorable direction. There are two trailing stop modes, one that trails immediately and the other that waits for the price to move a certain distance before activating the trailing stop.
3. Trailing Stop Functionality:
- The Trailing Stop function automatically adjusts the stop-loss level of an open trade as the price moves in a favorable direction. This helps to protect profits and limit potential losses.
- There are two types of trailing stops:
- Immediate Trailing Stop: The stop-loss is immediately adjusted as the price moves, ensuring that the trade is always protected by a stop-loss.
- Standard Trailing Stop: The stop-loss is only adjusted after the price has moved a certain distance in a favorable direction. This allows the trade to have some room to fluctuate without being prematurely stopped out.
4. Money Management (Optional):
- If enabled, the script automatically calculates the appropriate trade size based on the account balance, the specified risk percentage, and the characteristics of the currency pair.
- It can also be configured to use different lot sizes for micro, mini, or standard accounts.
5. Error Handling:
- The script includes basic error handling to identify and report any problems that occur during the trading process, such as failed order placements or modifications.
In summary, this script automates Forex trading based on the RSI indicator. It continuously monitors the market, looks for buy and sell signals, opens and closes trades, and manages risk through Stop Loss, Take Profit, and Trailing Stop features. The user can customize various settings to tailor the script's behavior to their preferences and risk tolerance.
//=============================================================================
// RSI_EA.mq4
// Originally by: Robert Hill
//
//=============================================================================
#property copyright "Robert Hill"
#include <stdlib.mqh>
#include <stderror.mqh>
#define LONG 1
#define SHORT -1
#define FLAT 0
extern bool AllowNewTrades = true;
extern int MagicCode = 5;
//+---------------------------------------------------+
//|Indicator inputs |
//+---------------------------------------------------+
extern int RSI_Period = 9;
extern int RSI_LowerLevel = 30;
extern int RSI_UpperLevel = 70;
extern bool ExitAtSignal = true;
extern int MMSet = 45; // Periodo da media Base
//---- Trade Management
extern bool UseTakeProfit = false;
extern double TakeProfit = 80;
extern double StopLoss = 50;
extern string ts ="---TrailingStop Settings---";
extern string ts0 = "---TrailingStopLoss---";
extern string ts1 = " 1. Trail immediately";
extern string ts2 = " 2. Standard at input";
extern bool UseTrailingStop = true;
extern int TrailingStopType = 2;
extern double TrailingStop = 25;
//+---------------------------------------------------+
//|Money Management |
//+---------------------------------------------------+
extern bool UseMoneyManagement = true; // Change to false if you want to shutdown money management controls.
extern bool BrokerIsIBFX = false;
extern string m1="Set mini and micro to false for standard account";
extern bool AccountIsMini = true;
extern bool AccountIsMicro = false;
extern double TradeSizePercent = 2; // Change to whatever percent of equity you wish to risk.
extern double Lots = 1;
double MaxLots = 100.0;
extern int Slippage = 3;
extern int SignalCandle = 1;
double lotMM;
string ExpertName="RSI_EA_";
int MagicNumber; // Magic number of the trades. must be unique to identify
string nameEA; // identifies the expert
int TradesInThisSymbol;
bool YesStop;
double myPoint;
int totalTries = 5;
int retryDelay = 1000;
int OrderErr;
//=============================================================================
// expert initialization function
//=============================================================================
int init()
{
MagicNumber = MagicCode*1000 + func_Symbol2Val(Symbol())*100 + func_TimeFrame_Const2Val(Period());
nameEA = ExpertName + Symbol() + "_" + func_TimeFrame_Val2String(func_TimeFrame_Const2Val(Period()));
myPoint = SetPoint();
return(0);
}
//=============================================================================
// expert deinitialization function
//=============================================================================
int deinit()
{
return(0);
}
//=============================================================================
//
// CheckSignals()
//
// Function to tell whether or not there is a trade to place.
//
// RETURN VALUE:
//
// 1: If the rules are met to place a long trade
//
// 2: If the rules are met to place a short trade
//
// 0: If the rules are not met
//
//=============================================================================
int CheckSignals()
{
double myRSI, myRSIp;
myRSI = iRSI(Symbol(),0,RSI_Period,PRICE_CLOSE,SignalCandle);
if (myRSI < RSI_LowerLevel) return(LONG);
if (myRSI > RSI_UpperLevel) return(SHORT); // down
return (FLAT); // has not changed
}
//=============================================================================
//
// CheckExitSignals()
//
//
//=============================================================================
bool CheckExitSignals(int cmd)
{
double myRSI, myRSIp;
if (ExitAtSignal == false) return(false);
myRSI = iRSI(Symbol(),0,RSI_Period,PRICE_CLOSE,SignalCandle);
myRSIp = iRSI(Symbol(),0,RSI_Period,PRICE_CLOSE,SignalCandle+1);
if (cmd == OP_BUY)
{
// Check overbought and turning down
if (myRSI > RSI_UpperLevel && myRSI < myRSIp) return(true);
}
if (cmd == OP_SELL)
{
// Check oversold and turning up
if ( myRSI < RSI_LowerLevel && myRSI > myRSIp) return(true);
}
return (false); // has not changed
}
//=============================================================================
// expert start function
//=============================================================================
int start()
{
int total, PlaceTrade;
total = CheckOpenTrades();
if (total == 0)
{
if (AllowNewTrades == true)
{
PlaceTrade = CheckSignals();
if (PlaceTrade != FLAT) OpenTrade(PlaceTrade);
}
}
else
{
RefreshRates();
HandleOpenPositions();
}
return(0);
}
void OpenTrade( int signal)
{
int res, err;
double TPprice,STprice;
int ticket;
double MMB0 = iMA(NULL,0,MMSet,0,2,0,1);
RefreshRates();
lotMM = GetLots();
if ((Close[0]>MMB0)&& signal == LONG)
{
res = OrderSend(Symbol(), OP_BUY, lotMM, Ask, Slippage, 0, 0, nameEA, MagicNumber, 0, Green);
if (res > 0)
{
ticket = res;
if (OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
{
Print("BUY order opened : ", OrderOpenPrice());
TPprice = 0;
if (TakeProfit > 0) TPprice=TakeLong(OrderOpenPrice(), TakeProfit);
STprice = 0;
if (StopLoss > 0)
{
STprice=StopLong(OrderOpenPrice(), StopLoss);
STprice = ValidStopLoss(OP_BUY,Bid, STprice);
}
// Normalize stoploss / takeprofit to the proper # of digits.
if (Digits > 0)
{
STprice = NormalizeDouble( STprice, Digits);
TPprice = NormalizeDouble( TPprice, Digits);
}
ModifyOrder(ticket, OrderOpenPrice(), STprice, TPprice, LightGreen);
}
}
}
if ((Close[0]<MMB0)&& signal == SHORT)
{
res = OrderSend(Symbol(), OP_SELL, lotMM, Bid, Slippage, 0, 0, nameEA, MagicNumber, 0, Red);
if (res > 0)
{
ticket = res;
if (OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
{
Print("SELL order opened : ", OrderOpenPrice());
if (StopLoss != 0 || TakeProfit != 0)
{
TPprice = 0;
if (TakeProfit > 0) TPprice=TakeShort(OrderOpenPrice(),TakeProfit);
STprice = 0;
if (StopLoss > 0)
{
STprice=StopShort(OrderOpenPrice() ,StopLoss);
STprice = ValidStopLoss(OP_SELL,Ask, STprice);
}
// Normalize stoploss / takeprofit to the proper # of digits.
if (Digits > 0)
{
STprice = NormalizeDouble( STprice, Digits);
TPprice = NormalizeDouble( TPprice, Digits);
}
ModifyOrder(ticket, OrderOpenPrice(), STprice, TPprice, LightGreen);
}
}
}
}
if(res<0)
{
err = GetLastError();
Print("OrderSend failed with error(" + err + ") " + ErrorDescription(err));
}
}
void HandleOpenPositions()
{
int cnt, err, total;
bool CloseTrade, result = false;
total = OrdersTotal();
for (cnt=0; cnt < total; cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if (OrderSymbol() != Symbol()) continue;
if (OrderMagicNumber() != MagicNumber) continue;
result = false;
// Should it be closed because of a reverse signal?
CloseTrade = CheckExitSignals(OrderType());
// We have a long position open
if (OrderType() == OP_BUY)
{
if (CloseTrade == true)
{
result = OrderClose(OrderTicket(), OrderLots(), Bid, 3, Violet);
if (!result)
{
err = GetLastError();
Print("OrderClose BUY failed with error(" + err + ") " + ErrorDescription(err));
Alert("Exit of BUY FAILED.");
}
}
}
// We have a short position open
if (OrderType() == OP_SELL)
{
if (CloseTrade == true)
{
result = OrderClose(OrderTicket(), OrderLots(), Ask, 3, Violet);
if (!result)
{
err = GetLastError();
Print("OrderClose SELL failed with error(" + err + ") " + ErrorDescription(err));
Alert("Exit of SELL FAILED.");
}
}
}
if (!result && UseTrailingStop) // Handle mods to trailing stop
HandleTrailingStop(OrderType(), OrderTicket(), OrderOpenPrice(), OrderStopLoss(), OrderTakeProfit());
}
return(0);
}
//=============================================================================
//
// HandleTrailingStop()
//
// Type 1 moves the stoploss without delay.
//
// Type 2 waits for price to move the amount of the trailStop
// before moving stop loss then moves like type 1
//
// PARAMETERS:
//
// type: OP_BUY or OP_SELL
// ticket: the ticket number
// open_price: the order's open price
// cur_sl: the order's current StopLoss value
// cur_tp: the order's current TakeProfit value
//
// RETURN VALUE:
// zero for now
//
// Calling example
// HandleTrailingStop(OP_BUY,OrderTicket(),OrderOpenPrice(),OrderStopLoss(),OrderTakeProfit());
//
//=============================================================================
void HandleTrailingStop(int type, int ticket, double open_price, double cur_sl, double cur_tp)
{
double pt, TS = 0;
if (type == OP_BUY)
{
switch (TrailingStopType)
{
case 1:
pt = myPoint * StopLoss;
if (Bid - cur_sl > pt)
ModifyOrder(ticket, open_price, Bid - pt, cur_tp, Aqua);
break;
case 2:
pt = myPoint * TrailingStop;
if (Bid - open_price > pt && (cur_sl < Bid - pt || cur_sl == 0))
ModifyOrder(ticket, open_price, Bid - pt, cur_tp, Aqua);
break;
}
}
if (type == OP_SELL)
{
switch (TrailingStopType)
{
case 1:
pt = myPoint * StopLoss;
if (cur_sl - Ask > pt)
ModifyOrder(ticket, open_price, Ask+pt, cur_tp, Aqua);
break;
case 2:
pt = myPoint * TrailingStop;
if (open_price - Ask > pt && (cur_sl > Ask + pt || cur_sl == 0))
ModifyOrder(ticket, open_price, Ask+pt, cur_tp, Aqua);
break;
}
}
}
int ModifyOrder(int ord_ticket,double op, double oSL, double oTP, color mColor)
{
int CloseCnt, err;
double myStop, myTake;
CloseCnt=0;
while (CloseCnt < 3)
{
if (OrderModify(ord_ticket,op,oSL,oTP,0,mColor))
{
CloseCnt = 3;
}
else
{
err=GetLastError();
Print(CloseCnt," Error modifying order : (", err , ") " + ErrorDescription(err));
if (err>0) CloseCnt++;
}
}
}
//=============================================================================
//
// CheckOpenTrades()
//
// RETURN VALUE:
//
// The number of trades this EA has currently open
//
//=============================================================================
int CheckOpenTrades()
{
int cnt;
int NumTrades; // Number of buy and sell trades in this symbol
NumTrades = 0;
for (cnt=OrdersTotal()-1; cnt>=0; cnt--)
{
OrderSelect (cnt, SELECT_BY_POS, MODE_TRADES);
if (OrderSymbol() != Symbol())
continue;
if (OrderMagicNumber() != MagicNumber)
continue;
if (OrderType() == OP_BUY)
NumTrades++;
if (OrderType() == OP_SELL)
NumTrades++;
}
return (NumTrades);
}
//+------------------------------------------------------------------+
//| Get number of lots for this trade |
//+------------------------------------------------------------------+
double GetLots()
{
double lot;
double myMaxLot = MarketInfo(Symbol(), MODE_MAXLOT);
if(UseMoneyManagement == false) return(Lots);
if (BrokerIsIBFX == true)
{
lot = Calc_IBFX_Money_Management();
return(lot);
}
lot=NormalizeDouble((AccountEquity()*TradeSizePercent/10000)/10,2);
// Use at least 1 micro lot
if (AccountIsMicro == true)
{
lot = MathFloor(lot*100)/100;
if (lot < 0.01) lot = 0.01;
if (lot > myMaxLot) lot = myMaxLot;
return(lot);
}
// Use at least 1 mini lot
if(AccountIsMini == true)
{
lot = MathFloor(lot*10)/10;
if (lot < 0.1) lot = 0.1;
if (lot > myMaxLot) lot = myMaxLot;
return(lot);
}
if (lot >= 1.0) lot = MathFloor(lot); else lot = 1.0;
if (lot > MaxLots) lot = MaxLots;
return(lot);
}
double Calc_IBFX_Money_Management()
{
// variables used for money management
double lot;
double myMaxLot = MarketInfo(Symbol(), MODE_MAXLOT);
lot=NormalizeDouble((AccountEquity()*TradeSizePercent/10000)/10,2);
// Use at least 1 micro lot
if (AccountIsMicro == true)
{
lot = lot * 10;
lot = MathFloor(lot*100)/100;
if (lot < 0.1) lot = 0.1;
if (lot > myMaxLot) lot = myMaxLot;
return(lot);
}
// Use at least 1 mini lot
if(AccountIsMini == true)
{
lot = lot * 10;
lot = MathFloor(lot*10)/10;
if (lot < 1) lot = 1;
if (lot > myMaxLot) lot = myMaxLot;
return(lot);
}
// Standard Account
lot = MathFloor(lot);
if (lot < 1) lot = 1;
if (lot > myMaxLot) lot = myMaxLot;
return(lot);
}
double SetPoint()
{
double mPoint;
if (Digits < 4)
mPoint = 0.01;
else
mPoint = 0.0001;
return(mPoint);
}
double StopLong(double price,int stop)
{
if(stop==0)
return(0);
else
return(price-(stop*myPoint));
}
double StopShort(double price,int stop)
{
if(stop==0)
return(0);
else
return(price+(stop*myPoint));
}
double TakeLong(double price,int take)
{
if(take==0)
return(0);
else
return(price+(take*myPoint));
}
double TakeShort(double price,int take)
{
if(take==0)
return(0);
else
return(price-(take*myPoint));
}
double ValidStopLoss(int type, double price, double SL)
{
double minstop;
if (SL < 0.1) return(SL);
minstop = MarketInfo(Symbol(),MODE_STOPLEVEL);
if (type == OP_BUY)
{
if((price - SL) < minstop*myPoint) SL = price - minstop*myPoint;
}
if (type == OP_SELL)
{
if((SL-price) < minstop*myPoint) SL = price + minstop*myPoint;
}
return(SL);
}
//+------------------------------------------------------------------+
//| Time frame interval appropriation function |
//+------------------------------------------------------------------+
int func_TimeFrame_Const2Val(int Constant ) {
switch(Constant) {
case 1: // M1
return(1);
case 5: // M5
return(2);
case 15:
return(3);
case 30:
return(4);
case 60:
return(5);
case 240:
return(6);
case 1440:
return(7);
case 10080:
return(8);
case 43200:
return(9);
}
}
//+------------------------------------------------------------------+
//| Time frame string appropriation function |
//+------------------------------------------------------------------+
string func_TimeFrame_Val2String(int Value ) {
switch(Value) {
case 1: // M1
return("M1");
case 2: // M1
return("M5");
case 3:
return("M15");
case 4:
return("M30");
case 5:
return("H1");
case 6:
return("H4");
case 7:
return("D1");
case 8:
return("W1");
case 9:
return("MN1");
default:
return("undefined " + Value);
}
}
int func_Symbol2Val(string symbol) {
string mySymbol = StringSubstr(symbol,0,6);
if(mySymbol=="AUDCAD") return(1);
if(mySymbol=="AUDJPY") return(2);
if(mySymbol=="AUDNZD") return(3);
if(mySymbol=="AUDUSD") return(4);
if(mySymbol=="CHFJPY") return(5);
if(mySymbol=="EURAUD") return(6);
if(mySymbol=="EURCAD") return(7);
if(mySymbol=="EURCHF") return(8);
if(mySymbol=="EURGBP") return(9);
if(mySymbol=="EURJPY") return(10);
if(mySymbol=="EURUSD") return(11);
if(mySymbol=="GBPCHF") return(12);
if(mySymbol=="GBPJPY") return(13);
if(mySymbol=="GBPUSD") return(14);
if(mySymbol=="NZDUSD") return(15);
if(mySymbol=="USDCAD") return(16);
if(mySymbol=="USDCHF") return(17);
if(mySymbol=="USDJPY") return(18);
return(19);
}
Comments