/*
   ExpertBase.mqh

   Copyright 2013-2020, Orchard Forex
   https://www.orchardforex.com

*/


#include "CommonBase.mqh"
#include "Trade/Trade.mqh"
#include "../Extensions/AllGridExtensions.mqh"

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CExpertBase : public CCommonBase
  {

protected:

   int               mMagicNumber;
   string            mTradeComment;

   double            mVolume;

   int               GridNumber;
   int               mGridGap;
   int               mSlippage;
   double            mDefaultLotSize;
   double            mMaxLotSize;
   double            mMinLotSize;
   double            mMaxRiskPerTrade;
   double            mProfitPercent;
   double            mTargetProfit;


   double               lastBuyOrderPrice;
   double               lastSellOrderPrice;
   double               openedBuyPositionPrice;
   double               openedSellPositionPrice;
   double               pendingOrderPrice;

   ENUM_TRADING_SESSION    mUseTradingSession;
   ENUM_RISK_DEFAULT_SIZE mRiskDefaultSize;
   ENUM_RISK_BASE    mRiskBase;

   enum ENUM_OFX_SIGNAL_TYPE
     {
      OFX_ENTRY_SIGNAL,
      OFX_EXIT_SIGNAL
     };

   ENUM_OFX_SIGNAL_TYPE signalType;

   enum ENUM_OFX_SIGNAL_DIRECTION
     {
      OFX_SIGNAL_NONE            =  0,
      OFX_SIGNAL_BUY             =  1,
      OFX_SIGNAL_SELL            =  2,
      OFX_SIGNAL_BOTH            =  3,
      OFX_SIGNAL_ALL             = 4
     };

   ENUM_OFX_SIGNAL_DIRECTION entrySignal;
   ENUM_OFX_SIGNAL_DIRECTION exitSignal;

   datetime          mLastBarTime;
   datetime          mBarTime;

   bool              mResetGrid;

   ////Changed
   // Arrays to hold the signal objects
   CSignalGrid       *mEntrySignals[];
   CSignalGrid       *mExitSignals[];
   ////CSignalBase      *mEntrySignal;
   ////CSignalBase      *mExitSignal;

   double            mTakeProfitValue;
   double            mStopLossValue;
   GridTPSL          *mTakeProfitObj;
   GridTPSL          *mStopLossObj;

   CTradeCustom      Trade;

private:

protected:

   virtual bool      LoopMain(bool newBar, bool firstTime);
   virtual void      GetPendingOrderPrice(ENUM_OFX_SIGNAL_DIRECTION tradeType);

protected:

   int               Init(int magicNumber, string tradeComment);

public:

   //
   // Constructors
   //
                     CExpertBase()                    : CCommonBase()
     {               Init(0, "");   }
                     CExpertBase(string symbol, int timeframe, int magicNumber, string tradeComment)
      :              CCommonBase(symbol, timeframe)
     {               Init(magicNumber, tradeComment); }
                     CExpertBase(string symbol, ENUM_TIMEFRAMES timeframe, int magicNumber, string tradeComment)
      :              CCommonBase(symbol, timeframe)
     {               Init(magicNumber, tradeComment); }
                     CExpertBase(int magicNumber, string tradeComment)
      :              CCommonBase()
     {               Init(magicNumber, tradeComment); }

   //
   // Destructors
   //
                    ~CExpertBase();

public:  // Default properties

   //
   // Assign the default values to the expert
   //
   virtual void      SetVolume(double volume)      {  mVolume        =  volume;  }

   virtual void      SetTakeProfitValue(int takeProfitPoints)
     {  mTakeProfitValue  =  PointsToDouble(takeProfitPoints);   }
   virtual void      SetTakeProfitObj(CTPSLBase *takeProfitObj)
     {  mTakeProfitObj =  takeProfitObj; }

   virtual void      SetStopLossValue(int stopLossPoints)
     {  mStopLossValue =  PointsToDouble(stopLossPoints);  }
   virtual void      SetStopLossObj(CTPSLBase *stopLossObj)
     {  mStopLossObj   =  stopLossObj;   }

   virtual void      SetTradeComment(string comment)  {  mTradeComment  =  comment; }
   virtual void      SetMagic(int magicNumber)
     {
      mMagicNumber   =  magicNumber;
      Trade.SetExpertMagicNumber(magicNumber);
     }

   virtual void      SetGridNumber(int gNumber) {GridNumber = gNumber;}
   virtual void      SetGridGap(int gGap) {mGridGap = gGap;}
   virtual void      SetResetGrid() {mResetGrid = true;}
   virtual void      SetSlippage(int slippage) {mSlippage = slippage;}
   virtual void      SetDefaultLotSize(double defaultLotSize) {mDefaultLotSize = defaultLotSize;}
   virtual void      SetMaxLotSize(double maxLotSize) {mMaxLotSize = maxLotSize;}
   virtual void      SetMinLotSize(double minLotSize) {mMinLotSize = minLotSize;}
   virtual void      SetMaxRiskPerTrade(double maxRiskPerTrade) {mMaxRiskPerTrade = maxRiskPerTrade;}
   virtual void      SetProfitPercent(double profitPercent) {mProfitPercent = profitPercent;}


   virtual void      SetUseTradingSession(ENUM_TRADING_SESSION useTradingSession) {mUseTradingSession = useTradingSession;}
   virtual void      SetRiskDefaultSize(ENUM_RISK_DEFAULT_SIZE riskDefaultSize) { mRiskDefaultSize = riskDefaultSize;}
   virtual void      SetRiskBase(ENUM_RISK_BASE riskBase) {mRiskBase=riskBase;}

public:  // Setup

   ////Changed
   virtual void      AddEntrySignal(CSignalGrid *signal) {  AddSignal(signal, mEntrySignals);   }
   virtual void      AddExitSignal(CSignalGrid *signal)  {  AddSignal(signal, mExitSignals); }
   virtual void      AddSignal(CSignalGrid *signal, CSignalGrid* &signals[]);
   virtual void      LotSize(double SL);
   virtual void      TradeWatcher();
   virtual bool      IsTradingTime();
   virtual bool      CheckTradingSession();

   ////virtual void  AddEntrySignal(CSignalBase *signal) {  mEntrySignal=signal; }
   ////virtual void  AddExitSignal(CSignalBase *signal)  {  mExitSignal=signal;  }

public:  // Event handlers

   virtual int       OnInit();
   virtual void      OnTick();
   virtual void      OnTimer()         {  return;  }
   virtual double    OnTester()        {  return(0.0);   }
   virtual void      OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {};

#ifdef __MQL5__
   virtual void      OnTrade()         {  return;  }
   virtual void      OnTradeTransaction(const MqlTradeTransaction& trans,
                                        const MqlTradeRequest& request,
                                        const MqlTradeResult& result)
     {  return;  }
   virtual int       OnTesterInit()    {  return(INIT_SUCCEEDED); }
   virtual void      OnTesterPass()    {  return;  }
   virtual void      OnTesterDeinit()  {  return;  }
   virtual void      OnBookEvent()     {  return;  }
#endif

public:  // Functions

   virtual void      GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &request);
   ////New
   virtual ENUM_OFX_SIGNAL_DIRECTION   GetCurrentSignal(CSignalGrid* &signals[],
         ENUM_OFX_SIGNAL_TYPE signalType);

   virtual double                      getLastBuyOrderPrice() {return lastBuyOrderPrice;}
   virtual double                      getLastSellOrderPrice() {return lastSellOrderPrice;}
   virtual double                      getOpenedBuyPositionPrice() {return openedBuyPositionPrice;}
   virtual double                      getOpenedSellPositionPrice() {return openedSellPositionPrice;}

  };

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CExpertBase::~CExpertBase()
  {

  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int   CExpertBase::OnInit()
  {

   int   i  =  0;
   for(i=ArraySize(mEntrySignals)-1; i>=0; i--)
     {
      if(mEntrySignals[i].InitResult()!=INIT_SUCCEEDED)
         return(mEntrySignals[i].InitResult());
     }
   for(i=ArraySize(mExitSignals)-1; i>=0; i--)
     {
      if(mExitSignals[i].InitResult()!=INIT_SUCCEEDED)
         return(mExitSignals[i].InitResult());
     }
   if(mTakeProfitObj!=NULL)
     {
      if(mTakeProfitObj.InitResult()!=INIT_SUCCEEDED)
         return(mTakeProfitObj.InitResult());
     }
   if(mStopLossObj!=NULL)
     {
      if(mStopLossObj.InitResult()!=INIT_SUCCEEDED)
         return(mStopLossObj.InitResult());
     }

   return(INIT_SUCCEEDED);

  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int   CExpertBase::Init(int magicNumber, string tradeComment)
  {

   if(mInitResult!=INIT_SUCCEEDED)
      return(mInitResult);

   mTradeComment     =  tradeComment;
   SetMagic(magicNumber);

   mTakeProfitValue  =  0.0;
   mStopLossValue    =  0.0;

   mLastBarTime      =  0;

////New
   ArrayResize(mEntrySignals, 0);   // Just make sure these are initialised
   ArrayResize(mExitSignals, 0);

   return(INIT_SUCCEEDED);

  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void  CExpertBase::OnTick(void)
  {

   if(!TradeAllowed())
      return;

   mBarTime =  iTime(mSymbol, mTimeframe, 0);

   bool  firstTime   = (mLastBarTime==0);
   bool  newBar      = (mBarTime!=mLastBarTime);

   TradeWatcher();
   if(LoopMain(newBar, firstTime))
     {
      mLastBarTime   =  mBarTime;
     }

   return;

  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool     CExpertBase::LoopMain(bool newBar,bool firstTime)
  {

//
// To start I will only trade on a new bar
//    and not on the first bar after start
//
   /*if(!newBar)
      return(true);
   if(firstTime)
      return(true);*/

//
// Update the signals
//
////Changed
   /*   ENUM_OFX_SIGNAL_DIRECTION  entrySignal =  GetCurrentSignal(mEntrySignals, OFX_ENTRY_SIGNAL);
      ENUM_OFX_SIGNAL_DIRECTION  exitSignal  =  GetCurrentSignal(mExitSignals, OFX_EXIT_SIGNAL);****/


   Print("entrySignal  ", entrySignal, ", exitSignal ", exitSignal);

//
// Should a trade be opened
//
   MqlTradeRequest   request = {};  // Just initialising

   double sellPrice, buyPrice, SLPoints=0;
   int GripPips = mGridGap;

   double TakeProfitPoint = GripPips*_Point;
   long offset = SymbolInfoInteger(mSymbol, SYMBOL_TRADE_STOPS_LEVEL);
   Print("Take profit point ", TakeProfitPoint);
   Print("Offset levelt ", offset, " Spread ", SymbolInfoInteger(mSymbol, SYMBOL_SPREAD));
   LotSize(GripPips);
   double AskPrice = SymbolInfoDouble(mSymbol,SYMBOL_ASK);
   double BidPrice = SymbolInfoDouble(mSymbol,SYMBOL_BID);
   bool retry = true;


//GetMarketPrices(ORDER_TYPE_BUY, request);


//GetMarketPrices(ORDER_TYPE_SELL_STOP, request);
   sellPrice = BidPrice - TakeProfitPoint;
   buyPrice = AskPrice + TakeProfitPoint;
   if(entrySignal==OFX_SIGNAL_BOTH)
     {
      request.price = NormalizeDouble(sellPrice, mDigits);

      if(Trade.SellStop(mVolume, request.price, mSymbol))
        {
         request.price = NormalizeDouble(AskPrice, mDigits);

         Trade.Buy(mVolume, mSymbol,request.price);
         return(true);
        }
      else
        {
         Print("Get last error code ", GetLastError());
         return(true);
        }
     }

   else
      if(entrySignal==OFX_SIGNAL_BUY)
        {
         //If there's a pending order, get the last order's price else get the position price
         Print("Trying to open a buy");

         //GetMarketPrices(ORDER_TYPE_BUY_STOP, request);
         Print("openedBuyPositionPrice ", openedBuyPositionPrice, " lastBuyOrderPrice ", lastBuyOrderPrice);
         buyPrice = (lastBuyOrderPrice == 0.0) ? openedBuyPositionPrice : lastBuyOrderPrice;
         request.price = NormalizeDouble(buyPrice+TakeProfitPoint, mDigits);

         if(!Trade.BuyStop(mVolume, request.price, mSymbol))
           {
            while(retry)
              {
               if(Trade.Buy(mVolume, mSymbol, NormalizeDouble(AskPrice, mDigits)))
                 {
                  retry = false;
                 }
              }
           }
         return(true);
        }
      else
         if(entrySignal==OFX_SIGNAL_SELL)
           {
            Print("Trying to open a sell");

            //GetMarketPrices(ORDER_TYPE_SELL_STOP, request);
            Print("openedSellPositionPrice ", openedSellPositionPrice, " lastSellOrderPrice ", lastSellOrderPrice);
            sellPrice = (lastSellOrderPrice == 0.0) ? openedSellPositionPrice : lastSellOrderPrice;
            Print("sellPrice ", sellPrice);
            request.price = NormalizeDouble(sellPrice-TakeProfitPoint, mDigits);
            Print("request.price ", request.price);

            if(!Trade.SellStop(mVolume, NormalizeDouble(request.price,mDigits), mSymbol))
              {
               while(retry)
                 {
                  if(Trade.Sell(mVolume, mSymbol, NormalizeDouble(BidPrice, mDigits)))
                    {
                     retry = false;
                    }
                 }
              }
            return(true);

           }

   if(exitSignal==OFX_SIGNAL_ALL)
     {
      Trade.OrderCloseAll();
      Trade.PositionCloseAll();
     }

   return(true);

  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void  CExpertBase::GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &request)
  {

   double   sl = (mStopLossObj==NULL) ? mStopLossValue : mStopLossObj.GetStopLoss();
   double   tp = (mTakeProfitObj==NULL) ? mTakeProfitValue : mTakeProfitObj.GetTakeProfit();
   double   sellPrice, buyPrice;

   Trade.SetExpertMagicNumber(mMagicNumber);
   if(orderType==ORDER_TYPE_BUY)
     {
      request.price  =  SymbolInfoDouble(mSymbol, SYMBOL_ASK);
      request.tp  = (tp==0.0) ? 0.0 : NormalizeDouble(request.price+tp, mDigits);
      request.sl  = (sl==0.0) ? 0.0 : NormalizeDouble(request.price-sl, mDigits);
     }

   if(orderType==ORDER_TYPE_SELL)
     {
      request.price  =  SymbolInfoDouble(mSymbol, SYMBOL_BID);
      request.tp  = (tp==0.0) ? 0.0 : NormalizeDouble(request.price-tp, mDigits);
      request.sl  = (sl==0.0) ? 0.0 : NormalizeDouble(request.price+sl, mDigits);
     }

   if(orderType==ORDER_TYPE_SELL_STOP)
     {
      sellPrice = getLastSellOrderPrice()?getLastSellOrderPrice():getOpenedSellPositionPrice();
      sellPrice = (sellPrice==0.0)?SymbolInfoDouble(mSymbol, SYMBOL_BID):sellPrice;

      request.price = sellPrice-(mGridGap*_Point);

      request.tp  = (tp==0.0) ? 0.0 : NormalizeDouble(request.price-tp, mDigits);
      request.sl  = (sl==0.0) ? 0.0 : NormalizeDouble(request.price+sl, mDigits);
     }

   if(orderType==ORDER_TYPE_BUY_STOP)
     {
      buyPrice = getLastBuyOrderPrice()?getLastBuyOrderPrice():getOpenedBuyPositionPrice();
      buyPrice = (buyPrice==0.0)?SymbolInfoDouble(mSymbol, SYMBOL_ASK):buyPrice;
      request.price = buyPrice+(mGridGap*_Point);
      request.tp  = (tp==0.0) ? 0.0 : NormalizeDouble(request.price-tp, mDigits);
      request.sl  = (sl==0.0) ? 0.0 : NormalizeDouble(request.price+sl, mDigits);
     }

   return;

  }

////New
void  CExpertBase::AddSignal(CSignalGrid *signal, CSignalGrid* &signals[])
  {

   int      index =  ArraySize(signals);
   ArrayResize(signals, index+1);
   signals[index] =  signal;

  }

////New
/*ENUM_OFX_SIGNAL_DIRECTION  CExpertBase::GetCurrentSignal(CSignalGrid* &signals[],
      ENUM_OFX_SIGNAL_TYPE signalType)
  {

   ENUM_OFX_SIGNAL_DIRECTION  result   =  OFX_SIGNAL_NONE;
   ENUM_OFX_SIGNAL_DIRECTION  r2       =  OFX_SIGNAL_NONE;  // Just working value
   int   index =  ArraySize(signals);

   if(index<=0)
     {

      return(result);

     }
   else
     {

      signals[0].UpdateSignal();
      result   =  signals[0].GetSignal(signalType);

      // I have chosen to update all signals in case there is some
      //    behavour that needs it. The penalty is some performance
      // If performance is an issue just add an exit inside the loop
      //    as the commented line
      for(int i = 1; i<index; i++)
        {

         if(result==OFX_SIGNAL_NONE)
            return(result);

         signals[i].UpdateSignal();
         r2       =  signals[i].GetSignal(signalType);

         // The logic here
         // If the current result is both then just update to the r2
         //    because this allows for any value
         // If r2 is both then this just leave the current result as is
         // Last test, meaning result is already none or buy or sell
         //    If r2 is different then we cannot combine them
         //    so the result must be none
         //
         // or like this
         //
         // result      r2       gives
         // Both     +  Any   =  Any
         // Any      +  Both  =  Any
         // !Both    +  !Same =  None
         if(result==OFX_SIGNAL_BOTH)
           {
            result   =  r2;
           }
         else
            if(r2==OFX_SIGNAL_BOTH)    {  }
            else
               if(result!=r2)
                 {
                  result   =  OFX_SIGNAL_NONE;
                 }

        }

     }

   return(result);

  }*/


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CExpertBase::CheckTradingSession()
  {
   string candles_times;
   int    time_to_string;
   ushort a;
   string result[];
//--- Get the separator code
   a = StringGetCharacter(":",0);
   candles_times = TimeToString(iTime(Symbol(),_Period,0), TIME_MINUTES);
   time_to_string = StringSplit(candles_times, a, result);

//Implement this later
   /*
   if(InpUseTradingSession)
     {
      if(InpTradingSession == LONDON_SESSION && londonSession[0] <= result[0] && londonSession[1] >= result[0])
        {
         londonSession
        }
      return;
     }*/
   return true;
  }



//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CExpertBase::IsTradingTime(void)
  {
   bool result = false;

   if(mUseTradingSession)
      result = true;

   return result;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CExpertBase::LotSize(double SL=0)
  {

//Lot Size Calculator

//If the position size is dynamic
   if(mRiskDefaultSize==RISK_DEFAULT_AUTO)
     {
      //If the stop loss is not zero then calculate the lot size
      Print("Stop loss ", SL);
      if(SL!=0)
        {
         double RiskBaseAmount=0;
         //TickValue is the value of the individual price increment for 1 lot of the instrument, expressed in the account currenty
         double TickValue=SymbolInfoDouble(mSymbol,SYMBOL_TRADE_TICK_VALUE);
         Print("Tick value ", TickValue);
         //Define the base for the risk calculation depending on the parameter chosen
         if(mRiskBase==RISK_BASE_BALANCE)
            RiskBaseAmount=AccountInfoDouble(ACCOUNT_BALANCE);
         if(mRiskBase==RISK_BASE_EQUITY)
            RiskBaseAmount=AccountInfoDouble(ACCOUNT_EQUITY);
         if(mRiskBase==RISK_BASE_FREEMARGIN)
            RiskBaseAmount=AccountInfoDouble(ACCOUNT_FREEMARGIN);

         //Calculate the Position Size
         mVolume=((RiskBaseAmount*mMaxRiskPerTrade/100)/(SL*TickValue));
         Print("Volume ", mVolume);
        }
      //If the stop loss is zero then the lot size is the default one
      if(SL==0)
        {
         mVolume=mDefaultLotSize;
        }
     }
//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size
   mVolume=MathFloor(mVolume/SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_STEP);

//Limit the lot size in case it is greater than the maximum allowed by the user
   if(mVolume>mMaxLotSize)
      mVolume=mMaxLotSize;
//Limit the lot size in case it is greater than the maximum allowed by the broker
   if(mVolume>SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_MAX))
      mVolume=SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_MAX);
   Print("Lot ", mVolume, " Max lot ", SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_MAX));
//If the lot size is too small then set it to 0 and don't trade
   if(mVolume<mMinLotSize || mVolume < SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_MIN))
     {
      mVolume=0;
      Print("Lot size too small : ", mVolume);
     }


  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CExpertBase::TradeWatcher(void)
  {


// Check the account balance equity for profit
   int pCountBuy = 0,
       pCountSell = 0,
       oCountBuy = 0,
       oCountSell = 0,
       totalBuy = 0,
       totalSell = 0,
       realTotalBuy = 0,
       realTotalSell = 0;
   int realOCountBuy, realOCountSell;

   lastBuyOrderPrice = 0.0;
   lastSellOrderPrice = 0.0;
   openedBuyPositionPrice = 0.0;
   openedSellPositionPrice = 0.0;

   ulong ticket;
   entrySignal = OFX_SIGNAL_NONE;
   exitSignal = OFX_SIGNAL_NONE;

//If there're many positions and account balance is negative

   Print("There is ", PositionsTotal(), " opened positions");
   if(PositionsTotal() > 0)
     {
      //Count the opened positions by type
      int   cntP      =  PositionsTotal();
      Print("cntP ", cntP-1);
      for(int i = cntP-1; i>=0; i--)
        {
         Print(" i ", i);
         ticket = PositionGetTicket(i);
         if(PositionSelectByTicket(ticket))
           {
            if(PositionGetString(POSITION_SYMBOL)==mSymbol && PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY
               && PositionGetInteger(POSITION_MAGIC)==mMagicNumber)
              {
               if(pCountBuy == 0)
                 {
                  openedBuyPositionPrice = PositionGetDouble(POSITION_PRICE_OPEN);
                 }

               pCountBuy += 1;
              }

            Print("POSITION_SYMBOL ", PositionGetString(POSITION_SYMBOL), " = ", mSymbol, " POSITION_TYPE ",PositionGetInteger(POSITION_TYPE), " = ", POSITION_TYPE_SELL, " Magic ", PositionGetInteger(POSITION_MAGIC), " = ",mMagicNumber);
            if(PositionGetString(POSITION_SYMBOL)==mSymbol && PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL
               && PositionGetInteger(POSITION_MAGIC)==mMagicNumber)
              {
               if(pCountSell == 0)
                 {
                  openedSellPositionPrice = PositionGetDouble(POSITION_PRICE_OPEN);
                 }

               pCountSell += 1;
              }
           }
         else
           {
            Print(GetLastError());
           }
        }
     }
//Count the orders by type

   int   cntO      =  OrdersTotal();

   Print("Total pending orders ", cntO);
   for(int i = cntO-1; i>=0; i--)
     {
      ticket = OrderGetTicket(i);
      if(OrderSelect(ticket))
        {
         if(OrderGetString(ORDER_SYMBOL)==mSymbol && OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_BUY_STOP
            && OrderGetInteger(ORDER_MAGIC)==mMagicNumber)
           {
            oCountBuy += 1;
            lastBuyOrderPrice = OrderGetDouble(ORDER_PRICE_OPEN);
           }

         Print("ORDER_SYMBOL ", OrderGetString(ORDER_SYMBOL), " Real symbol ", mSymbol, " ORDER_TYPE ", OrderGetInteger(ORDER_TYPE), " Real type ", ORDER_TYPE_SELL_STOP, " Magic ", OrderGetInteger(ORDER_MAGIC), " Real magic ", mMagicNumber);
         if(OrderGetString(ORDER_SYMBOL)==mSymbol && OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_SELL_STOP
            && OrderGetInteger(ORDER_MAGIC)==mMagicNumber)
           {
            oCountSell += 1;
            lastSellOrderPrice = OrderGetDouble(ORDER_PRICE_OPEN);
           }
        }
      else
        {
         Print(GetLastError());
        }
     }

   double floatingProfitPercent = ((AccountInfoDouble(ACCOUNT_EQUITY) - AccountInfoDouble(ACCOUNT_BALANCE))*100)/AccountInfoDouble(ACCOUNT_BALANCE);
//mTargetProfit = AccountInfoDouble(ACCOUNT_BALANCE)*mProfitPercent/100;
// Check if profit is at least the mMaxRiskPerTrade

   Print(" Profit Percent ",mProfitPercent, " Floating profit percent ", floatingProfitPercent, " Account equity ", AccountInfoDouble(ACCOUNT_EQUITY), " Account balance ", AccountInfoDouble(ACCOUNT_BALANCE));

//The number of buy pending order should be twice the opened sell positions; and vice versa
   realOCountBuy = pCountSell+1;
   realOCountSell = pCountBuy*2;
   totalBuy = pCountBuy+oCountBuy;
   totalSell = pCountSell+oCountSell;
   realTotalBuy = pCountSell+1;
   realTotalSell = pCountBuy+1;

   Print("Sell order (", oCountSell, ") Real (", realOCountSell, ")");
   Print("Buy order (", oCountBuy, ") Real (", realOCountBuy, ")", " Opened sell ", pCountSell);


   Print("oCountSell ", oCountSell, " < ", " realOCountSell ", realOCountSell, " && ", " pCountBuy ", pCountBuy," > 0");

   if(OrdersTotal() == 0 && PositionsTotal() == 0)
     {
      entrySignal = OFX_SIGNAL_BOTH;
     }

   else
     {
      //If there's only one pending order left, close it.
      if(OrdersTotal() >= 1 && PositionsTotal() == 0)
        {
         exitSignal =  OFX_SIGNAL_ALL;
         Print("Exit if no opened position");
        }


      else
        {
         //If there's only one pending order left, close it.
         if(OrdersTotal() >= 1 && PositionsTotal() == 0)
           {
            exitSignal =  OFX_SIGNAL_ALL;
            Print("Exit if no opened position");
           }
         else
           {
            //When there are multiple positions, check is the account is making enough profit
            Print("floatingProfitPercent ", floatingProfitPercent, " mMaxRiskPerTrade ", mMaxRiskPerTrade);
            if(floatingProfitPercent > mProfitPercent)
              {
               exitSignal = OFX_SIGNAL_ALL;
               Print("Exit on profit target");
              }
            else
              {
               Print("realTotalSell ", realTotalSell, " <= ", " totalSell ", totalSell," && ", " pCountBuy ",pCountBuy," > 0");
               if(realTotalSell > totalSell && pCountBuy > 0)
                 {
                  signalType = OFX_ENTRY_SIGNAL;
                  entrySignal = OFX_SIGNAL_SELL;
                  Print("Sell order (", oCountSell, ") is less than it should be (", realOCountSell, ")");
                 }
               else
                 {
                  if(realTotalBuy > totalBuy && pCountSell > 0)
                    {
                     signalType = OFX_ENTRY_SIGNAL;
                     entrySignal = OFX_SIGNAL_BUY;
                     //mEntrySignals[0].SetSignal(OFX_ENTRY_SIGNAL, OFX_SIGNAL_BUY);
                     Print("Buy order (", oCountBuy, ") is less than it should be (", realOCountBuy, ")");
                    }
                 }
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+

/*void CExpertBase::GetPendingOrderPrice(ENUM_OFX_SIGNAL_DIRECTION tradeType){
if(tradeType == OFX_SIGNAL_BUY)
  {
  if(getLastBuyOrderPrice == 0.0)
    {
     pendingOrderPrice = openedBuyPositionPrice;
    } else
        {
         if(condition)
           {

           }
        }
   //buyPrice = (lastBuyOrderPrice == 0.0) ? openedBuyPositionPrice : lastBuyOrderPrice;
  }
}
*/
//+------------------------------------------------------------------+
