//+------------------------------------------------------------------+ //| Impulse 2.0.mqh | //| Copyright 2016, Vasiliy Sokolov, St-Petersburg, Russia | //| https://www.mql5.com/en/users/c-4 | //+------------------------------------------------------------------+ #property copyright "Copyright 2016, Vasiliy Sokolov." #property link "https://www.mql5.com/en/users/c-4" #include "Strategy\Strategy.mqh" #include "Strategy\Indicators.mqh" input int PeriodMA = 12; input double StopPercent = 0.05; //+------------------------------------------------------------------+ //| The CImpulse Strategy | //+------------------------------------------------------------------+ class CImpulse : public CStrategy { private: double m_percent; // Percent value for the level of a pending order protected: virtual void InitBuy(const MarketEvent &event); virtual void InitSell(const MarketEvent &event); virtual void SupportBuy(const MarketEvent &event,CPosition *pos); virtual void SupportSell(const MarketEvent &event,CPosition *pos); virtual void SupportPendingBuy(const MarketEvent &event,CPendingOrder *order); virtual void SupportPendingSell(const MarketEvent &event,CPendingOrder* order); virtual bool OnInit(void); public: double GetPercent(void); void SetPercent(double percent); CUnIndicator UnMA; }; //+------------------------------------------------------------------+ //| Initialize the moving average                                    | //+------------------------------------------------------------------+ bool CImpulse::OnInit(void) { UnMA.SetParameter(12); UnMA.SetParameter(0); UnMA.SetParameter(MODE_SMA); UnMA.SetParameter(PRICE_CLOSE); m_percent = StopPercent; if(UnMA.Create(Symbol(), Period(), IND_MA) != INVALID_HANDLE) return true; return false; } //+------------------------------------------------------------------+ //| Placing pending BuyStop orders                                   | //+------------------------------------------------------------------+ void CImpulse::InitBuy(const MarketEvent &event) { if(!IsTrackEvents(event))return; // Create pending only at the opening of a new bar if(PositionsTotal(POSITION_TYPE_BUY, ExpertSymbol(), ExpertMagic()) > 0) // There must be no open long positions present return; if(OrdersTotal(POSITION_TYPE_BUY, ExpertSymbol(), ExpertMagic()) > 0) // There must be no pending buy order present return; double target = WS.Ask() + WS.Ask()*(m_percent/100.0); // Calculate the level of the new pending order if(target < UnMA[0]) // The order trigger price must be above the Moving Average return; Trade.BuyStop(MM.GetLotFixed(), target, ExpertSymbol(), 0, 0, NULL); // Place the new BuyStop order } //+------------------------------------------------------------------+ //| Working with the pending BuyStop orders for opening a long       | //| position                                                         | //+------------------------------------------------------------------+ void CImpulse::SupportPendingBuy(const MarketEvent &event,CPendingOrder *order) { if(!IsTrackEvents(event))return; double target = WS.Ask() + WS.Ask()*(m_percent/100.0); // Calculate the level of the new pending order if(UnMA[0] > target) // If the new level is lower than the current Moving Average order.Delete(); // - lete it else // Otherwise, modify it with the new price order.Modify(target); } //+------------------------------------------------------------------+ //| Working with the pending SellStop orders for opening a short     | //| position                                                         | //+------------------------------------------------------------------+ void CImpulse::SupportPendingSell(const MarketEvent &event,CPendingOrder* order) { if(!IsTrackEvents(event))return; double target = WS.Ask() - WS.Ask()*(m_percent/100.0); // Calculate the level of the new pending order if(UnMA[0] < target) // If the new level is higher than the current Moving Average order.Delete(); // - lete it else // Otherwise, modify it with the new price order.Modify(target); } //+------------------------------------------------------------------+ //| Placing pending SellStop orders                                  | //+------------------------------------------------------------------+ void CImpulse::InitSell(const MarketEvent &event) { if(!IsTrackEvents(event))return; // Create pending only at the opening of a new bar if(PositionsTotal(POSITION_TYPE_SELL, ExpertSymbol(), ExpertMagic()) > 0) // There must be no open short positions present return; if(OrdersTotal(POSITION_TYPE_SELL, ExpertSymbol(), ExpertMagic()) > 0) // There must be no pending sell order present return; double target = WS.Bid() - WS.Bid()*(m_percent/100.0); // Calculate the level of the new pending order if(target > UnMA[0]) // The order trigger price must be below the Moving Average return; Trade.SellStop(MM.GetLotFixed(), target, ExpertSymbol(), 0, 0, NULL); // Place the new BuyStop order } //+------------------------------------------------------------------+ //| Managing a long position in accordance with the Moving Average   | //+------------------------------------------------------------------+ void CImpulse::SupportBuy(const MarketEvent &event,CPosition *pos) { int bar_open = WS.IndexByTime(pos.TimeOpen()); if(!IsTrackEvents(event))return; ENUM_ACCOUNT_MARGIN_MODE mode = (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE); if(mode != ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) { double target = WS.Bid() - WS.Bid()*(m_percent/100.0); if(target < UnMA[0]) pos.StopLossValue(target); else pos.StopLossValue(0.0); } if(WS.Bid() < UnMA[0]) pos.CloseAtMarket(); } //+------------------------------------------------------------------+ //| Managing a short position in accordance with the Moving Average  | //+------------------------------------------------------------------+ void CImpulse::SupportSell(const MarketEvent &event,CPosition *pos) { if(!IsTrackEvents(event))return; ENUM_ACCOUNT_MARGIN_MODE mode = (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE); if(mode != ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) { double target = WS.Ask() + WS.Ask()*(m_percent/100.0); if(target > UnMA[0]) pos.StopLossValue(target); else pos.StopLossValue(0.0); } if(WS.Ask() > UnMA[0]) pos.CloseAtMarket(); } //+------------------------------------------------------------------+ //| Returns the percent of the breakthrough level                    | //+------------------------------------------------------------------+ double CImpulse::GetPercent(void) { return m_percent; } //+------------------------------------------------------------------+ //| Sets percent of the breakthrough level                           | //+------------------------------------------------------------------+ void CImpulse::SetPercent(double percent) { m_percent = percent; } //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { CImpulse* impulse = new CImpulse(); impulse.ExpertMagic(140578); impulse.ExpertName("Impulse 2.0"); impulse.Timeframe(Period()); impulse.ExpertSymbol(Symbol()); Manager.AddStrategy(impulse); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { Manager.OnTick(); } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { Manager.OnChartEvent(id, lparam, dparam, sparam); ChartRedraw(0); }