459 lines
18 KiB
MQL5
459 lines
18 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| MACD Sample.mq5 |
|
|
//| Copyright 2009-2019, MetaQuotes Software Corp. |
|
|
//| http://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2009-2017, MetaQuotes Software Corp."
|
|
#property link "http://www.mql5.com"
|
|
#property version "5.50"
|
|
//#property description "It is important to make sure that the expert works with a normal"
|
|
//#property description "chart and the user did not make any mistakes setting input"
|
|
//#property description "variables (Lots, TakeProfit, TrailingStop) in our case,"
|
|
//#property description "we check TakeProfit on a chart of more than 2*trend_period bars"
|
|
//#property tester_file "1.txt"
|
|
//#property tester_indicator "Res\\ADX.ex5"
|
|
//#property tester_library "Res\\LastTick.ex5"
|
|
//#property tester_set "Res\\MACD_Sample_1.set"
|
|
//#property tester_set "Res\\MACD_Sample_2.set"
|
|
//---
|
|
//#resource "Res\\ADXW.ex5"
|
|
//#resource "Res\\euro.bmp"
|
|
//---
|
|
#define MACD_MAGIC 1234502
|
|
//---
|
|
#include <Trade\Trade.mqh>
|
|
#include <Trade\SymbolInfo.mqh>
|
|
#include <Trade\PositionInfo.mqh>
|
|
#include <Trade\AccountInfo.mqh>
|
|
//---
|
|
input double InpLots =0.1; // Lots
|
|
input int InpTakeProfit =50; // Take Profit (in pips)
|
|
input int InpTrailingStop =30; // Trailing Stop Level (in pips)
|
|
input int InpMACDOpenLevel =3; // MACD open level (in pips)
|
|
input int InpMACDCloseLevel=2; // MACD close level (in pips)
|
|
input int InpMATrendPeriod =26; // MA trend period
|
|
//---
|
|
int ExtTimeOut=10; // time out in seconds between trade operations
|
|
//+------------------------------------------------------------------+
|
|
//| MACD Sample expert class |
|
|
//+------------------------------------------------------------------+
|
|
class CSampleExpert
|
|
{
|
|
protected:
|
|
double m_adjusted_point; // point value adjusted for 3 or 5 points
|
|
CTrade m_trade; // trading object
|
|
CSymbolInfo m_symbol; // symbol info object
|
|
CPositionInfo m_position; // trade position object
|
|
CAccountInfo m_account; // account info wrapper
|
|
//--- indicators
|
|
int m_handle_macd; // MACD indicator handle
|
|
int m_handle_ema; // moving average indicator handle
|
|
//--- indicator buffers
|
|
double m_buff_MACD_main[]; // MACD indicator main buffer
|
|
double m_buff_MACD_signal[]; // MACD indicator signal buffer
|
|
double m_buff_EMA[]; // EMA indicator buffer
|
|
//--- indicator data for processing
|
|
double m_macd_current;
|
|
double m_macd_previous;
|
|
double m_signal_current;
|
|
double m_signal_previous;
|
|
double m_ema_current;
|
|
double m_ema_previous;
|
|
//---
|
|
double m_macd_open_level;
|
|
double m_macd_close_level;
|
|
double m_traling_stop;
|
|
double m_take_profit;
|
|
|
|
public:
|
|
CSampleExpert(void);
|
|
~CSampleExpert(void);
|
|
bool Init(void);
|
|
void Deinit(void);
|
|
bool Processing(void);
|
|
|
|
protected:
|
|
bool InitCheckParameters(const int digits_adjust);
|
|
bool InitIndicators(void);
|
|
bool LongClosed(void);
|
|
bool ShortClosed(void);
|
|
bool LongModified(void);
|
|
bool ShortModified(void);
|
|
bool LongOpened(void);
|
|
bool ShortOpened(void);
|
|
};
|
|
//--- global expert
|
|
CSampleExpert ExtExpert;
|
|
//+------------------------------------------------------------------+
|
|
//| Constructor |
|
|
//+------------------------------------------------------------------+
|
|
CSampleExpert::CSampleExpert(void) : m_adjusted_point(0),
|
|
m_handle_macd(INVALID_HANDLE),
|
|
m_handle_ema(INVALID_HANDLE),
|
|
m_macd_current(0),
|
|
m_macd_previous(0),
|
|
m_signal_current(0),
|
|
m_signal_previous(0),
|
|
m_ema_current(0),
|
|
m_ema_previous(0),
|
|
m_macd_open_level(0),
|
|
m_macd_close_level(0),
|
|
m_traling_stop(0),
|
|
m_take_profit(0)
|
|
{
|
|
ArraySetAsSeries(m_buff_MACD_main,true);
|
|
ArraySetAsSeries(m_buff_MACD_signal,true);
|
|
ArraySetAsSeries(m_buff_EMA,true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Destructor |
|
|
//+------------------------------------------------------------------+
|
|
CSampleExpert::~CSampleExpert(void)
|
|
{
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Initialization and checking for input parameters |
|
|
//+------------------------------------------------------------------+
|
|
bool CSampleExpert::Init(void)
|
|
{
|
|
//--- initialize common information
|
|
m_symbol.Name(Symbol()); // symbol
|
|
m_trade.SetExpertMagicNumber(MACD_MAGIC); // magic
|
|
m_trade.SetMarginMode();
|
|
m_trade.SetTypeFillingBySymbol(Symbol());
|
|
//--- tuning for 3 or 5 digits
|
|
int digits_adjust=1;
|
|
if(m_symbol.Digits()==3 || m_symbol.Digits()==5)
|
|
digits_adjust=10;
|
|
m_adjusted_point=m_symbol.Point()*digits_adjust;
|
|
//--- set default deviation for trading in adjusted points
|
|
m_macd_open_level =InpMACDOpenLevel*m_adjusted_point;
|
|
m_macd_close_level=InpMACDCloseLevel*m_adjusted_point;
|
|
m_traling_stop =InpTrailingStop*m_adjusted_point;
|
|
m_take_profit =InpTakeProfit*m_adjusted_point;
|
|
//--- set default deviation for trading in adjusted points
|
|
m_trade.SetDeviationInPoints(3*digits_adjust);
|
|
//---
|
|
if(!InitCheckParameters(digits_adjust))
|
|
return(false);
|
|
if(!InitIndicators())
|
|
return(false);
|
|
//--- succeed
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Checking for input parameters |
|
|
//+------------------------------------------------------------------+
|
|
bool CSampleExpert::InitCheckParameters(const int digits_adjust)
|
|
{
|
|
//--- initial data checks
|
|
if(InpTakeProfit*digits_adjust<m_symbol.StopsLevel())
|
|
{
|
|
printf("Take Profit must be greater than %d",m_symbol.StopsLevel());
|
|
return(false);
|
|
}
|
|
if(InpTrailingStop*digits_adjust<m_symbol.StopsLevel())
|
|
{
|
|
printf("Trailing Stop must be greater than %d",m_symbol.StopsLevel());
|
|
return(false);
|
|
}
|
|
//--- check for right lots amount
|
|
if(InpLots<m_symbol.LotsMin() || InpLots>m_symbol.LotsMax())
|
|
{
|
|
printf("Lots amount must be in the range from %f to %f",m_symbol.LotsMin(),m_symbol.LotsMax());
|
|
return(false);
|
|
}
|
|
if(MathAbs(InpLots/m_symbol.LotsStep()-MathRound(InpLots/m_symbol.LotsStep()))>1.0E-10)
|
|
{
|
|
printf("Lots amount is not corresponding with lot step %f",m_symbol.LotsStep());
|
|
return(false);
|
|
}
|
|
//--- warning
|
|
if(InpTakeProfit<=InpTrailingStop)
|
|
printf("Warning: Trailing Stop must be less than Take Profit");
|
|
//--- succeed
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Initialization of the indicators |
|
|
//+------------------------------------------------------------------+
|
|
bool CSampleExpert::InitIndicators(void)
|
|
{
|
|
//--- create MACD indicator
|
|
if(m_handle_macd==INVALID_HANDLE)
|
|
if((m_handle_macd=iMACD(NULL,0,12,26,9,PRICE_CLOSE))==INVALID_HANDLE)
|
|
{
|
|
printf("Error creating MACD indicator");
|
|
return(false);
|
|
}
|
|
//--- create EMA indicator and add it to collection
|
|
if(m_handle_ema==INVALID_HANDLE)
|
|
if((m_handle_ema=iMA(NULL,0,InpMATrendPeriod,0,MODE_EMA,PRICE_CLOSE))==INVALID_HANDLE)
|
|
{
|
|
printf("Error creating EMA indicator");
|
|
return(false);
|
|
}
|
|
//--- succeed
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Check for long position closing |
|
|
//+------------------------------------------------------------------+
|
|
bool CSampleExpert::LongClosed(void)
|
|
{
|
|
bool res=false;
|
|
//--- should it be closed?
|
|
if(m_macd_current>0)
|
|
if(m_macd_current<m_signal_current && m_macd_previous>m_signal_previous)
|
|
if(m_macd_current>m_macd_close_level)
|
|
{
|
|
//--- close position
|
|
if(m_trade.PositionClose(Symbol()))
|
|
printf("Long position by %s to be closed",Symbol());
|
|
else
|
|
printf("Error closing position by %s : '%s'",Symbol(),m_trade.ResultComment());
|
|
//--- processed and cannot be modified
|
|
res=true;
|
|
}
|
|
//--- result
|
|
return(res);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Check for short position closing |
|
|
//+------------------------------------------------------------------+
|
|
bool CSampleExpert::ShortClosed(void)
|
|
{
|
|
bool res=false;
|
|
//--- should it be closed?
|
|
if(m_macd_current<0)
|
|
if(m_macd_current>m_signal_current && m_macd_previous<m_signal_previous)
|
|
if(MathAbs(m_macd_current)>m_macd_close_level)
|
|
{
|
|
//--- close position
|
|
if(m_trade.PositionClose(Symbol()))
|
|
printf("Short position by %s to be closed",Symbol());
|
|
else
|
|
printf("Error closing position by %s : '%s'",Symbol(),m_trade.ResultComment());
|
|
//--- processed and cannot be modified
|
|
res=true;
|
|
}
|
|
//--- result
|
|
return(res);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Check for long position modifying |
|
|
//+------------------------------------------------------------------+
|
|
bool CSampleExpert::LongModified(void)
|
|
{
|
|
bool res=false;
|
|
//--- check for trailing stop
|
|
if(InpTrailingStop>0)
|
|
{
|
|
if(m_symbol.Bid()-m_position.PriceOpen()>m_adjusted_point*InpTrailingStop)
|
|
{
|
|
double sl=NormalizeDouble(m_symbol.Bid()-m_traling_stop,m_symbol.Digits());
|
|
double tp=m_position.TakeProfit();
|
|
if(m_position.StopLoss()<sl || m_position.StopLoss()==0.0)
|
|
{
|
|
//--- modify position
|
|
if(m_trade.PositionModify(Symbol(),sl,tp))
|
|
printf("Long position by %s to be modified",Symbol());
|
|
else
|
|
{
|
|
printf("Error modifying position by %s : '%s'",Symbol(),m_trade.ResultComment());
|
|
printf("Modify parameters : SL=%f,TP=%f",sl,tp);
|
|
}
|
|
//--- modified and must exit from expert
|
|
res=true;
|
|
}
|
|
}
|
|
}
|
|
//--- result
|
|
return(res);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Check for short position modifying |
|
|
//+------------------------------------------------------------------+
|
|
bool CSampleExpert::ShortModified(void)
|
|
{
|
|
bool res=false;
|
|
//--- check for trailing stop
|
|
if(InpTrailingStop>0)
|
|
{
|
|
if((m_position.PriceOpen()-m_symbol.Ask())>(m_adjusted_point*InpTrailingStop))
|
|
{
|
|
double sl=NormalizeDouble(m_symbol.Ask()+m_traling_stop,m_symbol.Digits());
|
|
double tp=m_position.TakeProfit();
|
|
if(m_position.StopLoss()>sl || m_position.StopLoss()==0.0)
|
|
{
|
|
//--- modify position
|
|
if(m_trade.PositionModify(Symbol(),sl,tp))
|
|
printf("Short position by %s to be modified",Symbol());
|
|
else
|
|
{
|
|
printf("Error modifying position by %s : '%s'",Symbol(),m_trade.ResultComment());
|
|
printf("Modify parameters : SL=%f,TP=%f",sl,tp);
|
|
}
|
|
//--- modified and must exit from expert
|
|
res=true;
|
|
}
|
|
}
|
|
}
|
|
//--- result
|
|
return(res);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Check for long position opening |
|
|
//+------------------------------------------------------------------+
|
|
bool CSampleExpert::LongOpened(void)
|
|
{
|
|
bool res=false;
|
|
//--- check for long position (BUY) possibility
|
|
if(m_macd_current<0)
|
|
if(m_macd_current>m_signal_current && m_macd_previous<m_signal_previous)
|
|
if(MathAbs(m_macd_current)>(m_macd_open_level) && m_ema_current>m_ema_previous)
|
|
{
|
|
double price=m_symbol.Ask();
|
|
double tp =m_symbol.Bid()+m_take_profit;
|
|
//--- check for free money
|
|
if(m_account.FreeMarginCheck(Symbol(),ORDER_TYPE_BUY,InpLots,price)<0.0)
|
|
printf("We have no money. Free Margin = %f",m_account.FreeMargin());
|
|
else
|
|
{
|
|
//--- open position
|
|
if(m_trade.PositionOpen(Symbol(),ORDER_TYPE_BUY,InpLots,price,0.0,tp))
|
|
printf("Position by %s to be opened",Symbol());
|
|
else
|
|
{
|
|
printf("Error opening BUY position by %s : '%s'",Symbol(),m_trade.ResultComment());
|
|
printf("Open parameters : price=%f,TP=%f",price,tp);
|
|
}
|
|
}
|
|
//--- in any case we must exit from expert
|
|
res=true;
|
|
}
|
|
//--- result
|
|
return(res);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Check for short position opening |
|
|
//+------------------------------------------------------------------+
|
|
bool CSampleExpert::ShortOpened(void)
|
|
{
|
|
bool res=false;
|
|
//--- check for short position (SELL) possibility
|
|
if(m_macd_current>0)
|
|
if(m_macd_current<m_signal_current && m_macd_previous>m_signal_previous)
|
|
if(m_macd_current>(m_macd_open_level) && m_ema_current<m_ema_previous)
|
|
{
|
|
double price=m_symbol.Bid();
|
|
double tp =m_symbol.Ask()-m_take_profit;
|
|
//--- check for free money
|
|
if(m_account.FreeMarginCheck(Symbol(),ORDER_TYPE_SELL,InpLots,price)<0.0)
|
|
printf("We have no money. Free Margin = %f",m_account.FreeMargin());
|
|
else
|
|
{
|
|
//--- open position
|
|
if(m_trade.PositionOpen(Symbol(),ORDER_TYPE_SELL,InpLots,price,0.0,tp))
|
|
printf("Position by %s to be opened",Symbol());
|
|
else
|
|
{
|
|
printf("Error opening SELL position by %s : '%s'",Symbol(),m_trade.ResultComment());
|
|
printf("Open parameters : price=%f,TP=%f",price,tp);
|
|
}
|
|
}
|
|
//--- in any case we must exit from expert
|
|
res=true;
|
|
}
|
|
//--- result
|
|
return(res);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| main function returns true if any position processed |
|
|
//+------------------------------------------------------------------+
|
|
bool CSampleExpert::Processing(void)
|
|
{
|
|
//--- refresh rates
|
|
if(!m_symbol.RefreshRates())
|
|
return(false);
|
|
//--- refresh indicators
|
|
if(BarsCalculated(m_handle_macd)<2 || BarsCalculated(m_handle_ema)<2)
|
|
return(false);
|
|
if(CopyBuffer(m_handle_macd,0,0,2,m_buff_MACD_main) !=2 ||
|
|
CopyBuffer(m_handle_macd,1,0,2,m_buff_MACD_signal)!=2 ||
|
|
CopyBuffer(m_handle_ema,0,0,2,m_buff_EMA) !=2)
|
|
return(false);
|
|
// m_indicators.Refresh();
|
|
//--- to simplify the coding and speed up access
|
|
//--- data are put into internal variables
|
|
m_macd_current =m_buff_MACD_main[0];
|
|
m_macd_previous =m_buff_MACD_main[1];
|
|
m_signal_current =m_buff_MACD_signal[0];
|
|
m_signal_previous=m_buff_MACD_signal[1];
|
|
m_ema_current =m_buff_EMA[0];
|
|
m_ema_previous =m_buff_EMA[1];
|
|
//--- it is important to enter the market correctly,
|
|
//--- but it is more important to exit it correctly...
|
|
//--- first check if position exists - try to select it
|
|
if(m_position.Select(Symbol()))
|
|
{
|
|
if(m_position.PositionType()==POSITION_TYPE_BUY)
|
|
{
|
|
//--- try to close or modify long position
|
|
if(LongClosed())
|
|
return(true);
|
|
if(LongModified())
|
|
return(true);
|
|
}
|
|
else
|
|
{
|
|
//--- try to close or modify short position
|
|
if(ShortClosed())
|
|
return(true);
|
|
if(ShortModified())
|
|
return(true);
|
|
}
|
|
}
|
|
//--- no opened position identified
|
|
else
|
|
{
|
|
//--- check for long position (BUY) possibility
|
|
if(LongOpened())
|
|
return(true);
|
|
//--- check for short position (SELL) possibility
|
|
if(ShortOpened())
|
|
return(true);
|
|
}
|
|
//--- exit without position processing
|
|
return(false);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit(void)
|
|
{
|
|
//--- create all necessary objects
|
|
if(!ExtExpert.Init())
|
|
return(INIT_FAILED);
|
|
//--- secceed
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert new tick handling function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick(void)
|
|
{
|
|
static datetime limit_time=0; // last trade processing time + timeout
|
|
//--- don't process if timeout
|
|
if(TimeCurrent()>=limit_time)
|
|
{
|
|
//--- check for data
|
|
if(Bars(Symbol(),Period())>2*InpMATrendPeriod)
|
|
{
|
|
//--- change limit time by timeout in seconds if processed
|
|
if(ExtExpert.Processing())
|
|
limit_time=TimeCurrent()+ExtTimeOut;
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|