9003b29674
Indicator Collection
579 lines
20 KiB
Plaintext
579 lines
20 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| MACD Sample.mq5 |
|
|
//| Copyright 2009-2013, MetaQuotes Software Corp. |
|
|
//| http://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2014 Semet Gaetan"
|
|
#property link "http://www.xeberon.net/gaetan"
|
|
#property version "1.0"
|
|
#property description "Gaetan Semet Expert Advisor"
|
|
#property description "This expert advisor triggers position on MACD and"
|
|
#property description "crossing Moving Averages. After a bid is placed"
|
|
#property description "it is qualified as 'gaining' or loosing'. If loosing,"
|
|
#property description "the stop will triggered to stop losses. If gaining,"
|
|
#property description "a trailing stop will be placed that allow a retracement"
|
|
#property description "of N percents. Only a small number of retracement is"
|
|
#property description "allowed, after a stop loss will be placed."
|
|
|
|
|
|
|
|
//---
|
|
#include <Trade\Trade.mqh>
|
|
#include <Trade\SymbolInfo.mqh>
|
|
#include <Trade\PositionInfo.mqh>
|
|
#include <Trade\AccountInfo.mqh>
|
|
|
|
//---
|
|
input double InpLots = 0.1; // Size of lots for each position
|
|
input int InpAllowedRetracementPercent = 50; // Allowed retracement for gaining position (in percent)
|
|
input int IntMaxNumberOfRetracement = 2; // Maximum number of allowed retracement before placing a close stop loss.
|
|
input int InpMACDOpenLevel = 3; // MACD open level (in pips)
|
|
input int InpMACDCloseLevel = 2; // MACD close level (in pips)
|
|
input int InpMA20TrendPeriod = 20; // Long MA trend period
|
|
input int InpMA6TrendPeriod = 6; // Short MA trend period
|
|
|
|
//---
|
|
int ExtTimeOut=10; // time out in seconds between trade operations
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| CMacdExpert class |
|
|
//+------------------------------------------------------------------+
|
|
class CMacdExpert
|
|
{
|
|
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_ema20; // long moving average indicator handle
|
|
int m_handle_ema6; // short 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:
|
|
CMacdExpert(void);
|
|
~CMacdExpert(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
|
|
CMacdExpert ExtExpert;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Constructor |
|
|
//+------------------------------------------------------------------+
|
|
CMacdExpert::CMacdExpert(void) : m_adjusted_point(0),
|
|
m_handle_macd(INVALID_HANDLE),
|
|
m_handle_ema20(INVALID_HANDLE),
|
|
m_handle_ema6(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 |
|
|
//+------------------------------------------------------------------+
|
|
CMacdExpert::~CMacdExpert(void)
|
|
{
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Initialization and checking for input parameters |
|
|
//+------------------------------------------------------------------+
|
|
bool CMacdExpert::Init(void)
|
|
{
|
|
//--- initialize common information
|
|
m_symbol.Name(Symbol()); // symbol
|
|
m_trade.SetExpertMagicNumber(0xcafebabe); // magic
|
|
|
|
//--- 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);
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Checking for input parameters |
|
|
//+------------------------------------------------------------------+
|
|
bool CMacdExpert::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");
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Initialization of the indicators |
|
|
//+------------------------------------------------------------------+
|
|
bool CMacdExpert::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 20 indicator and add it to collection
|
|
if (m_handle_ema20 == INVALID_HANDLE)
|
|
{
|
|
if ((m_handle_ema20 = iMA(NULL, 0, InpMA20TrendPeriod, 0, MODE_EMA, PRICE_CLOSE)) == INVALID_HANDLE)
|
|
{
|
|
printf("Error creating EMA indicator");
|
|
return(false);
|
|
}
|
|
}
|
|
|
|
//--- create EMA 6 indicator and add it to collection
|
|
if (m_handle_ema6== INVALID_HANDLE)
|
|
{
|
|
if ((m_handle_ema6 = iMA(NULL, 0, InpMA6TrendPeriod, 0, MODE_EMA, PRICE_CLOSE)) == INVALID_HANDLE)
|
|
{
|
|
printf("Error creating EMA indicator");
|
|
return(false);
|
|
}
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check for long position closing |
|
|
//+------------------------------------------------------------------+
|
|
bool CMacdExpert::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;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(res);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check for short position closing |
|
|
//+------------------------------------------------------------------+
|
|
bool CMacdExpert::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;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(res);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check for long position modifying |
|
|
//+------------------------------------------------------------------+
|
|
bool CMacdExpert::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;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(res);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check for short position modifying |
|
|
//+------------------------------------------------------------------+
|
|
bool CMacdExpert::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 CMacdExpert::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;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(res);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check for short position opening |
|
|
//+------------------------------------------------------------------+
|
|
bool CMacdExpert::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 CMacdExpert::Processing(void)
|
|
{
|
|
//--- refresh rates
|
|
if (!m_symbol.RefreshRates())
|
|
{
|
|
return(false);
|
|
}
|
|
|
|
//--- refresh indicators
|
|
if (BarsCalculated(m_handle_macd) < 2 || BarsCalculated(m_handle_ema20) < 2 || BarsCalculated(m_handle_ema6) < 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_ema6, 0, 0, 2, m_buff_EMA) != 2 ||
|
|
CopyBuffer(m_handle_ema20, 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);
|
|
}
|
|
|
|
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 * InpMA20TrendPeriod)
|
|
{
|
|
//--- change limit time by timeout in seconds if processed
|
|
if (ExtExpert.Processing())
|
|
{
|
|
limit_time = TimeCurrent() + ExtTimeOut;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+ |