//+------------------------------------------------------------------+ //| Expert.mqh | //| Copyright 2000-2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "ExpertBase.mqh" #include "ExpertTrade.mqh" #include "ExpertSignal.mqh" #include "ExpertMoney.mqh" #include "ExpertTrailing.mqh" //+------------------------------------------------------------------+ //| enumerations | //+------------------------------------------------------------------+ //--- flags of expected events enum ENUM_TRADE_EVENTS { TRADE_EVENT_NO_EVENT =0, // no expected events TRADE_EVENT_POSITION_OPEN =0x1, // flag of expecting the "opening of position" event TRADE_EVENT_POSITION_VOLUME_CHANGE=0x2, // flag of expecting of the "modification of position volume" event TRADE_EVENT_POSITION_MODIFY =0x4, // flag of expecting of the "modification of stop order of position" event TRADE_EVENT_POSITION_CLOSE =0x8, // flag of expecting of the "closing of position" event TRADE_EVENT_POSITION_STOP_TAKE =0x10, // flag of expecting of the "triggering of stop order of position" TRADE_EVENT_ORDER_PLACE =0x20, // flag of expecting of the "placing of pending order" event TRADE_EVENT_ORDER_MODIFY =0x40, // flag of expecting of the "modification of pending order" event TRADE_EVENT_ORDER_DELETE =0x80, // flag of expecting of the "deletion of pending order" event TRADE_EVENT_ORDER_TRIGGER =0x100 // flag of expecting of the "triggering of pending order" event }; //+------------------------------------------------------------------+ //| Macro definitions. | //+------------------------------------------------------------------+ //--- check the expectation of event #define IS_WAITING_POSITION_OPENED ((m_waiting_event&TRADE_EVENT_POSITION_OPEN)!=0) #define IS_WAITING_POSITION_VOLUME_CHANGED ((m_waiting_event&TRADE_EVENT_POSITION_VOLUME_CHANGE)!=0) #define IS_WAITING_POSITION_MODIFIED ((m_waiting_event&TRADE_EVENT_POSITION_MODIFY)!=0) #define IS_WAITING_POSITION_CLOSED ((m_waiting_event&TRADE_EVENT_POSITION_CLOSE)!=0) #define IS_WAITING_POSITION_STOP_TAKE ((m_waiting_event&TRADE_EVENT_POSITION_STOP_TAKE)!=0) #define IS_WAITING_ORDER_PLACED ((m_waiting_event&TRADE_EVENT_ORDER_PLACE)!=0) #define IS_WAITING_ORDER_MODIFIED ((m_waiting_event&TRADE_EVENT_ORDER_MODIFY)!=0) #define IS_WAITING_ORDER_DELETED ((m_waiting_event&TRADE_EVENT_ORDER_DELETE)!=0) #define IS_WAITING_ORDER_TRIGGERED ((m_waiting_event&TRADE_EVENT_ORDER_TRIGGER)!=0) //+------------------------------------------------------------------+ //| Class CExpert. | //| Purpose: Base class expert advisor. | //| Derives from class CExpertBase. | //+------------------------------------------------------------------+ class CExpert : public CExpertBase { protected: int m_period_flags; // timeframe flags (as visible flags) int m_max_orders; // max number of orders (include position) MqlDateTime m_last_tick_time; // time of last tick datetime m_expiration; // time expiration order //--- history info int m_pos_tot; // number of open positions int m_deal_tot; // number of deals in history int m_ord_tot; // number of pending orders int m_hist_ord_tot; // number of orders in history datetime m_beg_date; // start date of history //--- int m_waiting_event; // flags of expected trade events //--- trading objects CExpertTrade *m_trade; // trading object CExpertSignal *m_signal; // trading signals object CExpertMoney *m_money; // money manager object CExpertTrailing *m_trailing; // trailing stops object bool m_check_volume; // check and decrease trading volume before OrderSend //--- indicators CIndicators m_indicators; // indicator collection to fast recalculations //--- market objects CPositionInfo m_position; // position info object COrderInfo m_order; // order info object //--- flags of handlers bool m_on_tick_process; // OnTick will be processed (default true) bool m_on_trade_process; // OnTrade will be processed (default false) bool m_on_timer_process; // OnTimer will be processed (default false) bool m_on_chart_event_process; // OnChartEvent will be processed (default false) bool m_on_book_event_process; // OnBookEvent will be processed (default false) public: CExpert(void); ~CExpert(void); //--- initialization bool Init(string symbol,ENUM_TIMEFRAMES period,bool every_tick,ulong magic=0); void Magic(ulong value); void CheckVolumeBeforeTrade(const bool flag) { m_check_volume=flag; } //--- initialization trading objects virtual bool InitSignal(CExpertSignal *signal=NULL); virtual bool InitTrailing(CExpertTrailing *trailing=NULL); virtual bool InitMoney(CExpertMoney *money=NULL); virtual bool InitTrade(ulong magic,CExpertTrade *trade=NULL); //--- deinitialization virtual void Deinit(void); //--- methods of setting adjustable parameters void OnTickProcess(bool value) { m_on_tick_process=value; } void OnTradeProcess(bool value) { m_on_trade_process=value; } void OnTimerProcess(bool value) { m_on_timer_process=value; } void OnChartEventProcess(bool value) { m_on_chart_event_process=value; } void OnBookEventProcess(bool value) { m_on_book_event_process=value; } int MaxOrders(void) const { return(m_max_orders); } void MaxOrders(int value) { m_max_orders=value; } //--- methods of access to protected data CExpertSignal *Signal(void) const { return(m_signal); } //--- method of verification of settings virtual bool ValidationSettings(); //--- method of creating the indicator and timeseries virtual bool InitIndicators(CIndicators *indicators=NULL); //--- event handlers virtual void OnTick(void); virtual void OnTrade(void); virtual void OnTimer(void); virtual void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam); virtual void OnBookEvent(const string &symbol); protected: //--- initialization virtual bool InitParameters(void) { return(true); } //--- deinitialization virtual void DeinitTrade(void); virtual void DeinitSignal(void); virtual void DeinitTrailing(void); virtual void DeinitMoney(void); virtual void DeinitIndicators(void); //--- refreshing virtual bool Refresh(void); //--- position select depending on netting or hedging virtual bool SelectPosition(void); //--- processing (main method) virtual bool Processing(void); //--- trade open positions check virtual bool CheckOpen(void); virtual bool CheckOpenLong(void); virtual bool CheckOpenShort(void); //--- trade open positions processing virtual bool OpenLong(double price,double sl,double tp); virtual bool OpenShort(double price,double sl,double tp); //--- trade reverse positions check virtual bool CheckReverse(void); virtual bool CheckReverseLong(void); virtual bool CheckReverseShort(void); //--- trade reverse positions processing virtual bool ReverseLong(double price,double sl,double tp); virtual bool ReverseShort(double price,double sl,double tp); //--- trade close positions check virtual bool CheckClose(void); virtual bool CheckCloseLong(void); virtual bool CheckCloseShort(void); //--- trade close positions processing virtual bool CloseAll(double lot); virtual bool Close(void); virtual bool CloseLong(double price); virtual bool CloseShort(double price); //--- trailing stop check virtual bool CheckTrailingStop(void); virtual bool CheckTrailingStopLong(void); virtual bool CheckTrailingStopShort(void); //--- trailing stop processing virtual bool TrailingStopLong(double sl,double tp); virtual bool TrailingStopShort(double sl,double tp); //--- trailing order check virtual bool CheckTrailingOrderLong(void); virtual bool CheckTrailingOrderShort(void); //--- trailing order processing virtual bool TrailingOrderLong(double delta); virtual bool TrailingOrderShort(double delta); //--- delete order check virtual bool CheckDeleteOrderLong(void); virtual bool CheckDeleteOrderShort(void); //--- delete order processing virtual bool DeleteOrders(void); virtual bool DeleteOrdersLong(void); virtual bool DeleteOrdersShort(void); virtual bool DeleteOrder(void); virtual bool DeleteOrderLong(void); virtual bool DeleteOrderShort(void); //--- lot for trade double LotOpenLong(double price,double sl); double LotOpenShort(double price,double sl); double LotReverse(double sl); double LotCheck(double volume,double price,ENUM_ORDER_TYPE order_type); //--- methods of working with trade history void PrepareHistoryDate(void); void HistoryPoint(bool from_check_trade=false); bool CheckTradeState(void); //--- set/reset waiting events void WaitEvent(ENUM_TRADE_EVENTS event) { m_waiting_event|=event; } void NoWaitEvent(ENUM_TRADE_EVENTS event) { m_waiting_event&=~event; } //--- trade events virtual bool TradeEventPositionStopTake(void) { return(true); } virtual bool TradeEventOrderTriggered(void) { return(true); } virtual bool TradeEventPositionOpened(void) { return(true); } virtual bool TradeEventPositionVolumeChanged(void) { return(true); } virtual bool TradeEventPositionModified(void) { return(true); } virtual bool TradeEventPositionClosed(void) { return(true); } virtual bool TradeEventOrderPlaced(void) { return(true); } virtual bool TradeEventOrderModified(void) { return(true); } virtual bool TradeEventOrderDeleted(void) { return(true); } virtual bool TradeEventNotIdentified(void) { return(true); } //--- timeframe functions void TimeframeAdd(ENUM_TIMEFRAMES period); int TimeframesFlags(MqlDateTime &time); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CExpert::CExpert(void) : m_period_flags(0), m_expiration(0), m_pos_tot(0), m_deal_tot(0), m_ord_tot(0), m_hist_ord_tot(0), m_beg_date(0), m_trade(NULL), m_signal(NULL), m_money(NULL), m_trailing(NULL), m_check_volume(false), m_on_tick_process(true), m_on_trade_process(false), m_on_timer_process(false), m_on_chart_event_process(false), m_on_book_event_process(false), m_max_orders(1) { m_other_symbol =true; m_other_period =true; m_adjusted_point =10; m_period =WRONG_VALUE; m_last_tick_time.min=-1; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CExpert::~CExpert(void) { Deinit(); } //+------------------------------------------------------------------+ //| Initialization and checking for input parameters | //+------------------------------------------------------------------+ bool CExpert::Init(string symbol,ENUM_TIMEFRAMES period,bool every_tick,ulong magic) { //--- returns false if the EA is initialized on a symbol/timeframe different from the current one if(symbol!=::Symbol() || period!=::Period()) { PrintFormat(__FUNCTION__+": wrong symbol or timeframe (must be %s:%s)",symbol,EnumToString(period)); return(false); } //--- initialize common information if(m_symbol==NULL) { if((m_symbol=new CSymbolInfo)==NULL) return(false); } if(!m_symbol.Name(symbol)) return(false); m_period =period; m_every_tick=every_tick; m_magic =magic; SetMarginMode(); if(every_tick) TimeframeAdd(WRONG_VALUE); // add all periods else TimeframeAdd(period); // add specified period //--- tuning for 3 or 5 digits int digits_adjust=(m_symbol.Digits()==3 || m_symbol.Digits()==5) ? 10 : 1; m_adjusted_point=m_symbol.Point()*digits_adjust; //--- initializing objects expert if(!InitTrade(magic)) { Print(__FUNCTION__+": error initialization trade object"); return(false); } if(!InitSignal()) { Print(__FUNCTION__+": error initialization signal object"); return(false); } if(!InitTrailing()) { Print(__FUNCTION__+": error initialization trailing object"); return(false); } if(!InitMoney()) { Print(__FUNCTION__+": error initialization money object"); return(false); } if(!InitParameters()) { Print(__FUNCTION__+": error initialization parameters"); return(false); } //--- initialization for working with trade history PrepareHistoryDate(); HistoryPoint(); //--- primary initialization is successful, pass to the phase of tuning m_init_phase=INIT_PHASE_TUNING; //--- ok return(true); } //+------------------------------------------------------------------+ //| Sets magic number for object and its dependent objects | //+------------------------------------------------------------------+ void CExpert::Magic(ulong value) { if(m_trade!=NULL) m_trade.SetExpertMagicNumber(value); if(m_signal!=NULL) m_signal.Magic(value); if(m_money!=NULL) m_money.Magic(value); if(m_trailing!=NULL) m_trailing.Magic(value); //--- CExpertBase::Magic(value); } //+------------------------------------------------------------------+ //| Initialization trade object | //+------------------------------------------------------------------+ bool CExpert::InitTrade(ulong magic,CExpertTrade *trade=NULL) { //--- удаляем существующий объект if(m_trade!=NULL) delete m_trade; //--- if(trade==NULL) { if((m_trade=new CExpertTrade)==NULL) return(false); } else m_trade=trade; //--- tune trade object m_trade.SetSymbol(GetPointer(m_symbol)); m_trade.SetExpertMagicNumber(magic); m_trade.SetMarginMode(); //--- set default deviation for trading in adjusted points m_trade.SetDeviationInPoints((ulong)(3*m_adjusted_point/m_symbol.Point())); //--- ok return(true); } //+------------------------------------------------------------------+ //| Initialization signal object | //+------------------------------------------------------------------+ bool CExpert::InitSignal(CExpertSignal *signal) { if(m_signal!=NULL) delete m_signal; //--- if(signal==NULL) { if((m_signal=new CExpertSignal)==NULL) return(false); } else m_signal=signal; //--- initializing signal object if(!m_signal.Init(GetPointer(m_symbol),m_period,m_adjusted_point)) return(false); m_signal.EveryTick(m_every_tick); m_signal.Magic(m_magic); //--- ok return(true); } //+------------------------------------------------------------------+ //| Initialization trailing object | //+------------------------------------------------------------------+ bool CExpert::InitTrailing(CExpertTrailing *trailing) { if(m_trailing!=NULL) delete m_trailing; //--- if(trailing==NULL) { if((m_trailing=new CExpertTrailing)==NULL) return(false); } else m_trailing=trailing; //--- initializing trailing object if(!m_trailing.Init(GetPointer(m_symbol),m_period,m_adjusted_point)) return(false); m_trailing.EveryTick(m_every_tick); m_trailing.Magic(m_magic); //--- ok return(true); } //+------------------------------------------------------------------+ //| Initialization money object | //+------------------------------------------------------------------+ bool CExpert::InitMoney(CExpertMoney *money) { if(m_money!=NULL) delete m_money; //--- if(money==NULL) { if((m_money=new CExpertMoney)==NULL) return(false); } else m_money=money; //--- initializing money object if(!m_money.Init(GetPointer(m_symbol),m_period,m_adjusted_point)) return(false); m_money.EveryTick(m_every_tick); m_money.Magic(m_magic); //--- ok return(true); } //+------------------------------------------------------------------+ //| Validation settings | //+------------------------------------------------------------------+ bool CExpert::ValidationSettings(void) { if(!CExpertBase::ValidationSettings()) return(false); //--- Check signal parameters if(!m_signal.ValidationSettings()) { Print(__FUNCTION__+": error signal parameters"); return(false); } //--- Check trailing parameters if(!m_trailing.ValidationSettings()) { Print(__FUNCTION__+": error trailing parameters"); return(false); } //--- Check money parameters if(!m_money.ValidationSettings()) { Print(__FUNCTION__+": error money parameters"); return(false); } //--- ok return(true); } //+------------------------------------------------------------------+ //| Initialization indicators | //+------------------------------------------------------------------+ bool CExpert::InitIndicators(CIndicators *indicators) { //--- NULL always comes as the parameter, but here it's not significant for us CIndicators *indicators_ptr=GetPointer(m_indicators); //--- gather information about using of timeseries m_used_series|=m_signal.UsedSeries(); m_used_series|=m_trailing.UsedSeries(); m_used_series|=m_money.UsedSeries(); //--- create required timeseries if(!CExpertBase::InitIndicators(indicators_ptr)) return(false); m_signal.SetPriceSeries(m_open,m_high,m_low,m_close); m_signal.SetOtherSeries(m_spread,m_time,m_tick_volume,m_real_volume); if(!m_signal.InitIndicators(indicators_ptr)) { Print(__FUNCTION__+": error initialization indicators of signal object"); return(false); } m_trailing.SetPriceSeries(m_open,m_high,m_low,m_close); m_trailing.SetOtherSeries(m_spread,m_time,m_tick_volume,m_real_volume); if(!m_trailing.InitIndicators(indicators_ptr)) { Print(__FUNCTION__+": error initialization indicators of trailing object"); return(false); } m_money.SetPriceSeries(m_open,m_high,m_low,m_close); m_money.SetOtherSeries(m_spread,m_time,m_tick_volume,m_real_volume); if(!m_money.InitIndicators(indicators_ptr)) { Print(__FUNCTION__+": error initialization indicators of money object"); return(false); } //--- ok return(true); } //+------------------------------------------------------------------+ //| Deinitialization expert | //+------------------------------------------------------------------+ void CExpert::Deinit(void) { //--- delete trade class DeinitTrade(); //--- delete signal class DeinitSignal(); //--- delete trailing class DeinitTrailing(); //--- delete money class DeinitMoney(); //--- delete indicators collection DeinitIndicators(); } //+------------------------------------------------------------------+ //| Deinitialization trade object | //+------------------------------------------------------------------+ void CExpert::DeinitTrade(void) { if(m_trade!=NULL) { delete m_trade; m_trade=NULL; } } //+------------------------------------------------------------------+ //| Deinitialization signal object | //+------------------------------------------------------------------+ void CExpert::DeinitSignal(void) { if(m_signal!=NULL) { delete m_signal; m_signal=NULL; } } //+------------------------------------------------------------------+ //| Deinitialization trailing object | //+------------------------------------------------------------------+ void CExpert::DeinitTrailing(void) { if(m_trailing!=NULL) { delete m_trailing; m_trailing=NULL; } } //+------------------------------------------------------------------+ //| Deinitialization money object | //+------------------------------------------------------------------+ void CExpert::DeinitMoney(void) { if(m_money!=NULL) { delete m_money; m_money=NULL; } } //+------------------------------------------------------------------+ //| Deinitialization indicators | //+------------------------------------------------------------------+ void CExpert::DeinitIndicators(void) { m_indicators.Clear(); } //+------------------------------------------------------------------+ //| Refreshing data for processing | //+------------------------------------------------------------------+ bool CExpert::Refresh(void) { MqlDateTime time; //--- refresh rates if(!m_symbol.RefreshRates()) return(false); //--- check need processing TimeToStruct(m_symbol.Time(),time); if(m_period_flags!=WRONG_VALUE && m_period_flags!=0) if((m_period_flags&TimeframesFlags(time))==0) return(false); m_last_tick_time=time; //--- refresh indicators m_indicators.Refresh(); //--- ok return(true); } //+------------------------------------------------------------------+ //| Position select depending on netting or hedging | //+------------------------------------------------------------------+ bool CExpert::SelectPosition(void) { bool res=false; //--- if(IsHedging()) res=m_position.SelectByMagic(m_symbol.Name(),m_magic); else res=m_position.Select(m_symbol.Name()); //--- return(res); } //+------------------------------------------------------------------+ //| Main function | //+------------------------------------------------------------------+ bool CExpert::Processing(void) { //--- calculate signal direction once m_signal.SetDirection(); //--- check if open positions if(SelectPosition()) { //--- open position is available //--- check the possibility of reverse the position if(CheckReverse()) return(true); //--- check the possibility of closing the position/delete pending orders if(!CheckClose()) { //--- check the possibility of modifying the position if(CheckTrailingStop()) return(true); //--- return without operations return(false); } } //--- check if plased pending orders int total=OrdersTotal(); if(total!=0) { for(int i=total-1; i>=0; i--) { m_order.SelectByIndex(i); if(m_order.Symbol()!=m_symbol.Name()) continue; if(m_order.OrderType()==ORDER_TYPE_BUY_LIMIT || m_order.OrderType()==ORDER_TYPE_BUY_STOP) { //--- check the ability to delete a pending order to buy if(CheckDeleteOrderLong()) return(true); //--- check the possibility of modifying a pending order to buy if(CheckTrailingOrderLong()) return(true); } else { //--- check the ability to delete a pending order to sell if(CheckDeleteOrderShort()) return(true); //--- check the possibility of modifying a pending order to sell if(CheckTrailingOrderShort()) return(true); } //--- return without operations return(false); } } //--- check the possibility of opening a position/setting pending order if(CheckOpen()) return(true); //--- return without operations return(false); } //+------------------------------------------------------------------+ //| OnTick handler | //+------------------------------------------------------------------+ void CExpert::OnTick(void) { //--- check process flag if(!m_on_tick_process) return; //--- updated quotes and indicators if(!Refresh()) return; //--- expert processing Processing(); } //+------------------------------------------------------------------+ //| OnTrade handler | //+------------------------------------------------------------------+ void CExpert::OnTrade(void) { //--- check process flag if(!m_on_trade_process) return; CheckTradeState(); } //+------------------------------------------------------------------+ //| OnTimer handler | //+------------------------------------------------------------------+ void CExpert::OnTimer(void) { //--- check process flag if(!m_on_timer_process) return; } //+------------------------------------------------------------------+ //| OnChartEvent handler | //+------------------------------------------------------------------+ void CExpert::OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- check process flag if(!m_on_chart_event_process) return; } //+------------------------------------------------------------------+ //| OnBookEvent handler | //+------------------------------------------------------------------+ void CExpert::OnBookEvent(const string &symbol) { //--- check process flag if(!m_on_book_event_process) return; } //+------------------------------------------------------------------+ //| Check for position open or limit/stop order set | //+------------------------------------------------------------------+ bool CExpert::CheckOpen(void) { if(CheckOpenLong()) return(true); if(CheckOpenShort()) return(true); //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Check for long position open or limit/stop order set | //+------------------------------------------------------------------+ bool CExpert::CheckOpenLong(void) { double price=EMPTY_VALUE; double sl=0.0; double tp=0.0; datetime expiration=TimeCurrent(); //--- check signal for long enter operations if(m_signal.CheckOpenLong(price,sl,tp,expiration)) { if(!m_trade.SetOrderExpiration(expiration)) m_expiration=expiration; return(OpenLong(price,sl,tp)); } //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Check for short position open or limit/stop order set | //+------------------------------------------------------------------+ bool CExpert::CheckOpenShort(void) { double price=EMPTY_VALUE; double sl=0.0; double tp=0.0; datetime expiration=TimeCurrent(); //--- check signal for short enter operations if(m_signal.CheckOpenShort(price,sl,tp,expiration)) { if(!m_trade.SetOrderExpiration(expiration)) m_expiration=expiration; return(OpenShort(price,sl,tp)); } //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Long position open or limit/stop order set | //+------------------------------------------------------------------+ bool CExpert::OpenLong(double price,double sl,double tp) { if(price==EMPTY_VALUE) return(false); //--- get lot for open double lot=LotOpenLong(price,sl); //--- check lot for open lot=LotCheck(lot,price,ORDER_TYPE_BUY); if(lot==0.0) return(false); //--- return(m_trade.Buy(lot,price,sl,tp)); } //+------------------------------------------------------------------+ //| Short position open or limit/stop order set | //+------------------------------------------------------------------+ bool CExpert::OpenShort(double price,double sl,double tp) { if(price==EMPTY_VALUE) return(false); //--- get lot for open double lot=LotOpenShort(price,sl); //--- check lot for open lot=LotCheck(lot,price,ORDER_TYPE_SELL); if(lot==0.0) return(false); //--- return(m_trade.Sell(lot,price,sl,tp)); } //+------------------------------------------------------------------+ //| Check for position reverse | //+------------------------------------------------------------------+ bool CExpert::CheckReverse(void) { if(m_position.PositionType()==POSITION_TYPE_BUY) { //--- check the possibility of reverse the long position if(CheckReverseLong()) return(true); } else { //--- check the possibility of reverse the short position if(CheckReverseShort()) return(true); } //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Check for long position reverse | //+------------------------------------------------------------------+ bool CExpert::CheckReverseLong(void) { double price=EMPTY_VALUE; double sl=0.0; double tp=0.0; datetime expiration=TimeCurrent(); //--- check signal for long reverse operations if(m_signal.CheckReverseLong(price,sl,tp,expiration)) return(ReverseLong(price,sl,tp)); //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Check for short position reverse | //+------------------------------------------------------------------+ bool CExpert::CheckReverseShort(void) { double price=EMPTY_VALUE; double sl=0.0; double tp=0.0; datetime expiration=TimeCurrent(); //--- check signal for short reverse operations if(m_signal.CheckReverseShort(price,sl,tp,expiration)) return(ReverseShort(price,sl,tp)); //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Long position reverse | //+------------------------------------------------------------------+ bool CExpert::ReverseLong(double price,double sl,double tp) { if(price==EMPTY_VALUE) return(false); //--- get lot for reverse double lot=LotReverse(sl); //--- check lot if(lot==0.0) return(false); //--- bool result=true; if(IsHedging()) { //--- first close existing position lot-=m_position.Volume(); result=m_trade.PositionClose(m_position.Ticket()); } if(result) { lot=LotCheck(lot,price,ORDER_TYPE_SELL); if(lot==0.0) result=false; else result=m_trade.Sell(lot,price,sl,tp); } //--- return(result); } //+------------------------------------------------------------------+ //| Short position reverse | //+------------------------------------------------------------------+ bool CExpert::ReverseShort(double price,double sl,double tp) { if(price==EMPTY_VALUE) return(false); //--- get lot for reverse double lot=LotReverse(sl); //--- check lot if(lot==0.0) return(false); //--- bool result=true; if(IsHedging()) { //--- first close existing position lot-=m_position.Volume(); result=m_trade.PositionClose(m_position.Ticket()); } if(result) { lot=LotCheck(lot,price,ORDER_TYPE_BUY); if(lot==0.0) result=false; else result=m_trade.Buy(lot,price,sl,tp); } //--- return(result); } //+------------------------------------------------------------------+ //| Check for position close or limit/stop order delete | //+------------------------------------------------------------------+ bool CExpert::CheckClose(void) { double lot; //--- position must be selected before call if((lot=m_money.CheckClose(GetPointer(m_position)))!=0.0) return(CloseAll(lot)); //--- check for position type if(m_position.PositionType()==POSITION_TYPE_BUY) { //--- check the possibility of closing the long position / delete pending orders to buy if(CheckCloseLong()) { DeleteOrdersLong(); return(true); } } else { //--- check the possibility of closing the short position / delete pending orders to sell if(CheckCloseShort()) { DeleteOrdersShort(); return(true); } } //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Check for long position close or limit/stop order delete | //+------------------------------------------------------------------+ bool CExpert::CheckCloseLong(void) { double price=EMPTY_VALUE; //--- check for long close operations if(m_signal.CheckCloseLong(price)) return(CloseLong(price)); //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Check for short position close or limit/stop order delete | //+------------------------------------------------------------------+ bool CExpert::CheckCloseShort(void) { double price=EMPTY_VALUE; //--- check for short close operations if(m_signal.CheckCloseShort(price)) return(CloseShort(price)); //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Position close and orders delete | //+------------------------------------------------------------------+ bool CExpert::CloseAll(double lot) { bool result=false; //--- check for close operations if(IsHedging()) result=m_trade.PositionClose(m_position.Ticket()); else { if(m_position.PositionType()==POSITION_TYPE_BUY) result=m_trade.Sell(lot,0,0,0); else result=m_trade.Buy(lot,0,0,0); } result|=DeleteOrders(); //--- return(result); } //+------------------------------------------------------------------+ //| Position close | //+------------------------------------------------------------------+ bool CExpert::Close(void) { return(m_trade.PositionClose(m_symbol.Name())); } //+------------------------------------------------------------------+ //| Long position close | //+------------------------------------------------------------------+ bool CExpert::CloseLong(double price) { bool result=false; //--- if(price==EMPTY_VALUE) return(false); if(IsHedging()) result=m_trade.PositionClose(m_position.Ticket()); else result=m_trade.Sell(m_position.Volume(),price,0,0); //--- return(result); } //+------------------------------------------------------------------+ //| Short position close | //+------------------------------------------------------------------+ bool CExpert::CloseShort(double price) { bool result=false; //--- if(price==EMPTY_VALUE) return(false); if(IsHedging()) result=m_trade.PositionClose(m_position.Ticket()); else result=m_trade.Buy(m_position.Volume(),price,0,0); //--- return(result); } //+------------------------------------------------------------------+ //| Check for trailing stop/profit position | //+------------------------------------------------------------------+ bool CExpert::CheckTrailingStop(void) { //--- position must be selected before call if(m_position.PositionType()==POSITION_TYPE_BUY) { //--- check the possibility of modifying the long position if(CheckTrailingStopLong()) return(true); } else { //--- check the possibility of modifying the short position if(CheckTrailingStopShort()) return(true); } //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Check for trailing stop/profit long position | //+------------------------------------------------------------------+ bool CExpert::CheckTrailingStopLong(void) { double sl=EMPTY_VALUE; double tp=EMPTY_VALUE; //--- check for long trailing stop operations if(m_trailing.CheckTrailingStopLong(GetPointer(m_position),sl,tp)) { double position_sl=m_position.StopLoss(); double position_tp=m_position.TakeProfit(); if(sl==EMPTY_VALUE) sl=position_sl; else sl=m_symbol.NormalizePrice(sl); if(tp==EMPTY_VALUE) tp=position_tp; else tp=m_symbol.NormalizePrice(tp); if(sl==position_sl && tp==position_tp) return(false); //--- long trailing stop operations return(TrailingStopLong(sl,tp)); } //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Check for trailing stop/profit short position | //+------------------------------------------------------------------+ bool CExpert::CheckTrailingStopShort(void) { double sl=EMPTY_VALUE; double tp=EMPTY_VALUE; //--- check for short trailing stop operations if(m_trailing.CheckTrailingStopShort(GetPointer(m_position),sl,tp)) { double position_sl=m_position.StopLoss(); double position_tp=m_position.TakeProfit(); if(sl==EMPTY_VALUE) sl=position_sl; else sl=m_symbol.NormalizePrice(sl); if(tp==EMPTY_VALUE) tp=position_tp; else tp=m_symbol.NormalizePrice(tp); if(sl==position_sl && tp==position_tp) return(false); //--- short trailing stop operations return(TrailingStopShort(sl,tp)); } //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Trailing stop/profit long position | //+------------------------------------------------------------------+ bool CExpert::TrailingStopLong(double sl,double tp) { bool result; //--- if(IsHedging()) result=m_trade.PositionModify(m_position.Ticket(),sl,tp); else result=m_trade.PositionModify(m_symbol.Name(),sl,tp); //--- return(result); } //+------------------------------------------------------------------+ //| Trailing stop/profit short position | //+------------------------------------------------------------------+ bool CExpert::TrailingStopShort(double sl,double tp) { bool result; //--- if(IsHedging()) result=m_trade.PositionModify(m_position.Ticket(),sl,tp); else result=m_trade.PositionModify(m_symbol.Name(),sl,tp); //--- return(result); } //+------------------------------------------------------------------+ //| Check for trailing long limit/stop order | //+------------------------------------------------------------------+ bool CExpert::CheckTrailingOrderLong(void) { double price; //--- check the possibility of modifying the long order if(m_signal.CheckTrailingOrderLong(GetPointer(m_order),price)) return(TrailingOrderLong(m_order.PriceOpen()-price)); //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Check for trailing short limit/stop order | //+------------------------------------------------------------------+ bool CExpert::CheckTrailingOrderShort(void) { double price; //--- check the possibility of modifying the short order if(m_signal.CheckTrailingOrderShort(GetPointer(m_order),price)) return(TrailingOrderShort(m_order.PriceOpen()-price)); //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Trailing long limit/stop order | //+------------------------------------------------------------------+ bool CExpert::TrailingOrderLong(double delta) { ulong ticket=m_order.Ticket(); double price =m_symbol.NormalizePrice(m_order.PriceOpen()-delta); double sl =m_symbol.NormalizePrice(m_order.StopLoss()-delta); double tp =m_symbol.NormalizePrice(m_order.TakeProfit()-delta); //--- modifying the long order return(m_trade.OrderModify(ticket,price,sl,tp,m_order.TypeTime(),m_order.TimeExpiration())); } //+------------------------------------------------------------------+ //| Trailing short limit/stop order | //+------------------------------------------------------------------+ bool CExpert::TrailingOrderShort(double delta) { ulong ticket=m_order.Ticket(); double price =m_symbol.NormalizePrice(m_order.PriceOpen()-delta); double sl =m_symbol.NormalizePrice(m_order.StopLoss()-delta); double tp =m_symbol.NormalizePrice(m_order.TakeProfit()-delta); //--- modifying the short order return(m_trade.OrderModify(ticket,price,sl,tp,m_order.TypeTime(),m_order.TimeExpiration())); } //+------------------------------------------------------------------+ //| Check for delete long limit/stop order | //+------------------------------------------------------------------+ bool CExpert::CheckDeleteOrderLong(void) { double price; //--- check the possibility of deleting the long order if(m_expiration!=0 && TimeCurrent()>m_expiration) { m_expiration=0; return(DeleteOrderLong()); } if(m_signal.CheckCloseLong(price)) return(DeleteOrderLong()); //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Check for delete short limit/stop order | //+------------------------------------------------------------------+ bool CExpert::CheckDeleteOrderShort(void) { double price; //--- check the possibility of deleting the short order if(m_expiration!=0 && TimeCurrent()>m_expiration) { m_expiration=0; return(DeleteOrderShort()); } if(m_signal.CheckCloseShort(price)) return(DeleteOrderShort()); //--- return without operations return(false); } //+------------------------------------------------------------------+ //| Delete all limit/stop orders | //+------------------------------------------------------------------+ bool CExpert::DeleteOrders(void) { bool result=true; int total=OrdersTotal(); //--- for(int i=total-1;i>=0;i--) if(m_order.Select(OrderGetTicket(i))) { if(m_order.Symbol()!=m_symbol.Name()) continue; result&=DeleteOrder(); } //--- return(result); } //+------------------------------------------------------------------+ //| Delete all limit/stop long orders | //+------------------------------------------------------------------+ bool CExpert::DeleteOrdersLong(void) { bool result=true; int total=OrdersTotal(); //--- for(int i=total-1;i>=0;i--) if(m_order.Select(OrderGetTicket(i))) { if(m_order.Symbol()!=m_symbol.Name()) continue; if(m_order.OrderType()!=ORDER_TYPE_BUY_STOP && m_order.OrderType()!=ORDER_TYPE_BUY_LIMIT) continue; result&=DeleteOrder(); } //--- return(result); } //+------------------------------------------------------------------+ //| Delete all limit/stop orders | //+------------------------------------------------------------------+ bool CExpert::DeleteOrdersShort(void) { bool result=true; int total=OrdersTotal(); //--- for(int i=total-1;i>=0;i--) if(m_order.Select(OrderGetTicket(i))) { if(m_order.Symbol()!=m_symbol.Name()) continue; if(m_order.OrderType()!=ORDER_TYPE_SELL_STOP && m_order.OrderType()!=ORDER_TYPE_SELL_LIMIT) continue; result&=DeleteOrder(); } //--- return(result); } //+------------------------------------------------------------------+ //| Delete limit/stop order | //+------------------------------------------------------------------+ bool CExpert::DeleteOrder(void) { return(m_trade.OrderDelete(m_order.Ticket())); } //+------------------------------------------------------------------+ //| Delete long limit/stop order | //+------------------------------------------------------------------+ bool CExpert::DeleteOrderLong(void) { return(m_trade.OrderDelete(m_order.Ticket())); } //+------------------------------------------------------------------+ //| Delete short limit/stop order | //+------------------------------------------------------------------+ bool CExpert::DeleteOrderShort(void) { return(m_trade.OrderDelete(m_order.Ticket())); } //+------------------------------------------------------------------+ //| Method of getting the lot for open long position. | //+------------------------------------------------------------------+ double CExpert::LotOpenLong(double price,double sl) { return(m_money.CheckOpenLong(price,sl)); } //+------------------------------------------------------------------+ //| Method of getting the lot for open short position. | //+------------------------------------------------------------------+ double CExpert::LotOpenShort(double price,double sl) { return(m_money.CheckOpenShort(price,sl)); } //+------------------------------------------------------------------+ //| Method of getting the lot for reverse position. | //+------------------------------------------------------------------+ double CExpert::LotReverse(double sl) { return(m_money.CheckReverse(GetPointer(m_position),sl)); } //+------------------------------------------------------------------+ //| Check volume before OrderSend to avoid "not enough money" error | //+------------------------------------------------------------------+ double CExpert::LotCheck(double volume,double price,ENUM_ORDER_TYPE order_type) { if(m_check_volume) return(m_trade.CheckVolume(m_symbol.Name(),volume,price,order_type)); return(volume); } //+------------------------------------------------------------------+ //| Method of setting the start date for the history. | //+------------------------------------------------------------------+ void CExpert::PrepareHistoryDate(void) { MqlDateTime dts; //--- TimeCurrent(dts); //--- set up a date at the beginning of the month (but not less than one day) if(dts.day==1) { if(dts.mon==1) { dts.mon=12; dts.year--; } else dts.mon--; } dts.day =1; dts.hour=0; dts.min =0; dts.sec =0; //--- m_beg_date=StructToTime(dts); } //+------------------------------------------------------------------+ //| Method of establishing the checkpoint history. | //+------------------------------------------------------------------+ void CExpert::HistoryPoint(bool from_check_trade) { //--- check possible recursion if(!from_check_trade) CheckTradeState(); //--- select history point if(HistorySelect(m_beg_date,TimeCurrent())) { m_hist_ord_tot=HistoryOrdersTotal(); m_deal_tot =HistoryDealsTotal(); } else { m_hist_ord_tot=0; m_deal_tot =0; } m_ord_tot=OrdersTotal(); m_pos_tot=PositionsTotal(); } //+------------------------------------------------------------------+ //| Method of verification of trade events. | //+------------------------------------------------------------------+ bool CExpert::CheckTradeState(void) { bool res=false; //--- select current history point HistorySelect(m_beg_date,INT_MAX); int hist_ord_tot=HistoryOrdersTotal(); int ord_tot =OrdersTotal(); int deal_tot =HistoryDealsTotal(); int pos_tot =PositionsTotal(); //--- check for quantitative changes if(hist_ord_tot==m_hist_ord_tot && ord_tot==m_ord_tot && deal_tot==m_deal_tot && pos_tot==m_pos_tot) { //--- no quantitative changes if(IS_WAITING_POSITION_MODIFIED) { res=TradeEventPositionModified(); NoWaitEvent(TRADE_EVENT_POSITION_MODIFY); } if(IS_WAITING_ORDER_MODIFIED) { res=TradeEventOrderModified(); NoWaitEvent(TRADE_EVENT_ORDER_MODIFY); } return(true); } //--- check added a pending order if(hist_ord_tot==m_hist_ord_tot && ord_tot==m_ord_tot+1 && deal_tot==m_deal_tot && pos_tot==m_pos_tot) { //--- was added a pending order res=TradeEventOrderPlaced(); //--- establishment of the checkpoint history of the trade HistoryPoint(true); return(true); } //--- check make a deal "with the market" if(hist_ord_tot==m_hist_ord_tot+1 && ord_tot==m_ord_tot) { //--- was an attempt to make a deal "with the market" if(deal_tot==m_deal_tot+1) { //--- operation successfull //--- check position update/subtracting if(pos_tot==m_pos_tot) { //--- position update/subtracting if(IS_WAITING_POSITION_VOLUME_CHANGED) { res=TradeEventPositionVolumeChanged(); NoWaitEvent(TRADE_EVENT_POSITION_VOLUME_CHANGE); } //--- establishment of the checkpoint history of the trade HistoryPoint(true); return(res); } //--- check position open if(pos_tot==m_pos_tot+1) { //--- position open if(IS_WAITING_POSITION_OPENED) { res=TradeEventPositionOpened(); NoWaitEvent(TRADE_EVENT_POSITION_OPEN); } //--- establishment of the checkpoint history of the trade HistoryPoint(true); return(res); } //--- check position is closed (including the stoploss/takeprofit) if(pos_tot==m_pos_tot-1) { //--- position is closed (including the stoploss/takeprofit) if(IS_WAITING_POSITION_CLOSED) { res=TradeEventPositionClosed(); NoWaitEvent(TRADE_EVENT_POSITION_CLOSE); } else res=TradeEventPositionStopTake(); //--- establishment of the checkpoint history of the trade HistoryPoint(true); return(res); } } else { //--- operation failed //--- establishment of the checkpoint history of the trade HistoryPoint(true); return(false); } } //--- check delete pending order if(hist_ord_tot==m_hist_ord_tot+1 && ord_tot==m_ord_tot-1 && deal_tot==m_deal_tot && pos_tot==m_pos_tot) { //--- delete pending order res=TradeEventOrderDeleted(); //--- establishment of the checkpoint history of the trade HistoryPoint(true); return(res); } //--- check triggering of a pending order if(hist_ord_tot==m_hist_ord_tot+1 && ord_tot==m_ord_tot-1) { //--- triggering of a pending order if(deal_tot==m_deal_tot+1) { //--- operation successfull //--- check position update/subtracting if(pos_tot==m_pos_tot) { //--- position update/subtracting res=TradeEventOrderTriggered(); //--- establishment of the checkpoint history of the trade HistoryPoint(true); return(res); } //--- check position open if(pos_tot==m_pos_tot+1) { //--- position open res=TradeEventOrderTriggered(); //--- establishment of the checkpoint history of the trade HistoryPoint(true); return(res); } //--- check position is closed if(pos_tot==m_pos_tot-1) { //--- position is closed res=TradeEventOrderTriggered(); //--- establishment of the checkpoint history of the trade HistoryPoint(true); return(res); } } else { //--- operation failed //--- establishment of the checkpoint history of the trade HistoryPoint(true); return(false); } } //--- trade event non identifical res=TradeEventNotIdentified(); //--- establishment of the checkpoint history of the trade HistoryPoint(true); //--- return(res); } //+------------------------------------------------------------------+ //| Add timeframe for checked | //+------------------------------------------------------------------+ void CExpert::TimeframeAdd(ENUM_TIMEFRAMES period) { switch(period) { case PERIOD_M1: m_period_flags|=OBJ_PERIOD_M1; break; case PERIOD_M2: m_period_flags|=OBJ_PERIOD_M2; break; case PERIOD_M3: m_period_flags|=OBJ_PERIOD_M3; break; case PERIOD_M4: m_period_flags|=OBJ_PERIOD_M4; break; case PERIOD_M5: m_period_flags|=OBJ_PERIOD_M5; break; case PERIOD_M6: m_period_flags|=OBJ_PERIOD_M6; break; case PERIOD_M10: m_period_flags|=OBJ_PERIOD_M10; break; case PERIOD_M12: m_period_flags|=OBJ_PERIOD_M12; break; case PERIOD_M15: m_period_flags|=OBJ_PERIOD_M15; break; case PERIOD_M20: m_period_flags|=OBJ_PERIOD_M20; break; case PERIOD_M30: m_period_flags|=OBJ_PERIOD_M30; break; case PERIOD_H1: m_period_flags|=OBJ_PERIOD_H1; break; case PERIOD_H2: m_period_flags|=OBJ_PERIOD_H2; break; case PERIOD_H3: m_period_flags|=OBJ_PERIOD_H3; break; case PERIOD_H4: m_period_flags|=OBJ_PERIOD_H4; break; case PERIOD_H6: m_period_flags|=OBJ_PERIOD_H6; break; case PERIOD_H8: m_period_flags|=OBJ_PERIOD_H8; break; case PERIOD_H12: m_period_flags|=OBJ_PERIOD_H12; break; case PERIOD_D1: m_period_flags|=OBJ_PERIOD_D1; break; case PERIOD_W1: m_period_flags|=OBJ_PERIOD_W1; break; case PERIOD_MN1: m_period_flags|=OBJ_PERIOD_MN1; break; default: m_period_flags=WRONG_VALUE; break; } } //+------------------------------------------------------------------+ //| Forms timeframes flags | //+------------------------------------------------------------------+ int CExpert::TimeframesFlags(MqlDateTime &time) { //--- set flags for all timeframes int result=OBJ_ALL_PERIODS; //--- if first check, then setting flags all timeframes if(m_last_tick_time.min==-1) return(result); //--- check change time if(time.min==m_last_tick_time.min && time.hour==m_last_tick_time.hour && time.day==m_last_tick_time.day && time.mon==m_last_tick_time.mon) return(OBJ_NO_PERIODS); //--- new month? if(time.mon!=m_last_tick_time.mon) return(result); //--- reset the "new month" flag result^=OBJ_PERIOD_MN1; //--- new day? if(time.day!=m_last_tick_time.day) return(result); //--- reset the "new day" and "new week" flags result^=OBJ_PERIOD_D1+OBJ_PERIOD_W1; //--- temporary variables to speed up working with structures int curr,delta; //--- new hour? curr=time.hour; delta=curr-m_last_tick_time.hour; if(delta!=0) { if(curr%2>=delta) result^=OBJ_PERIOD_H2; if(curr%3>=delta) result^=OBJ_PERIOD_H3; if(curr%4>=delta) result^=OBJ_PERIOD_H4; if(curr%6>=delta) result^=OBJ_PERIOD_H6; if(curr%8>=delta) result^=OBJ_PERIOD_H8; if(curr%12>=delta) result^=OBJ_PERIOD_H12; return(result); } //--- reset all flags for hour timeframes result^=OBJ_PERIOD_H1+OBJ_PERIOD_H2+OBJ_PERIOD_H3+OBJ_PERIOD_H4+OBJ_PERIOD_H6+OBJ_PERIOD_H8+OBJ_PERIOD_H12; //--- new minute? curr=time.min; delta=curr-m_last_tick_time.min; if(delta!=0) { if(curr%2>=delta) result^=OBJ_PERIOD_M2; if(curr%3>=delta) result^=OBJ_PERIOD_M3; if(curr%4>=delta) result^=OBJ_PERIOD_M4; if(curr%5>=delta) result^=OBJ_PERIOD_M5; if(curr%6>=delta) result^=OBJ_PERIOD_M6; if(curr%10>=delta) result^=OBJ_PERIOD_M10; if(curr%12>=delta) result^=OBJ_PERIOD_M12; if(curr%15>=delta) result^=OBJ_PERIOD_M15; if(curr%20>=delta) result^=OBJ_PERIOD_M20; if(curr%30>=delta) result^=OBJ_PERIOD_M30; } //--- result return(result); } //+------------------------------------------------------------------+