//+------------------------------------------------------------------+ //| 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 #include #include #include //--- 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_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; } } } } //+------------------------------------------------------------------+