451 行
18 KiB
MQL5
451 行
18 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| MACD Sample.mq5 |
| |||
//| Copyright 2000-2025, MetaQuotes Ltd. |
| |||
//| https://www.mql5.com |
| |||
//+------------------------------------------------------------------+
| |||
#property copyright "Copyright 2000-2025, MetaQuotes Ltd."
| |||
#property link "https://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"
| |||
| |||
#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;
| |||
}
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
|