//+------------------------------------------------------------------+
//|                                                      Sandbox.mq4 |
//|                                                  Igor Ryabchikov |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Igor Ryabchikov"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
#include <Arrays/ArrayObj.mqh>
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

input int    MagicNumber            = 1987891;
input double StopLossPips           = 0;
input int    HiLoPeriodOpen         = 50;
input int    HiLoPeriodAdd          = 10;


#include <MoneyManager.mqh>
#include <ProfitStrategyManagerATR.mqh>
#include <TradeStatsChartObjects.mqh>
#include <Spacer.mqh>

ScreenUtils* su;
TradeStatsChartObjectsManager* tsManager;
TradeStats tradeStats;
double minimumTrailStep;
DirectionAdvice directionAdvice[2] = {DirectionAdvice_None, DirectionAdvice_None};
double stopLoss[2] = {0.0, 0.0};
datetime barTime, lastOrderTime;
      

int OnInit() {
      su = new ScreenUtils(true, true);
      tsManager = new TradeStatsChartObjectsManager();
      tradeStats.SetMagic( MagicNumber);     
      barTime = Time[0];
//      dayBarTime = iTime(_Symbol, PERIOD_D1, 0);
      return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){
   if(CheckPointer(su) == POINTER_DYNAMIC){
      logger.Info("deleting screenUtils");
      delete (su);   
   }
   if(CheckPointer(tsManager) == POINTER_DYNAMIC){
      logger.Info("deleting tradeStatsChartObjectManager");
      delete (tsManager);   
   }
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick() {

   tradeStats.UpdatePosition();
//   tsManager.PrintTradeStatsLabel(tradeStats);
   tsManager.MarkLevels(tradeStats);
   profitStrategyManager.UpdateAndProcess(tradeStats, directionAdvice);
   
   if(Time[0] > barTime)
      OnBar();
   
}


 
void OnBar() {
   barTime = Time[0];

   double breakeven[2] = {0.0, 0.0};
   if(tradeStats.GetCount(OP_BUY) > 0)
      breakeven[OP_BUY] = Utils::CalculateBreakEven(_Symbol, tradeStats.GetTotalProfit(OP_BUY), tradeStats.GetTotalLots(OP_BUY), OP_BUY, true);
   if(tradeStats.GetCount(OP_SELL) > 0)
      breakeven[OP_SELL] = Utils::CalculateBreakEven(_Symbol, tradeStats.GetTotalProfit(OP_SELL), tradeStats.GetTotalLots(OP_SELL), OP_SELL, true);
   
   directionAdvice[OP_BUY] = DirectionAdvice_None;
   directionAdvice[OP_SELL] = DirectionAdvice_None;

   int extremum = iHighest(_Symbol, _Period, MODE_HIGH, HiLoPeriodAdd);
   if(extremum == 2) { // sell
      extremum = iHighest(_Symbol, _Period, MODE_HIGH, HiLoPeriodOpen);
      if(extremum == 2)
         directionAdvice[OP_SELL] = DirectionAdvice_Open;
      else
         directionAdvice[OP_SELL] = DirectionAdvice_Add;
   } else {
      extremum = iLowest(_Symbol, _Period, MODE_LOW, HiLoPeriodAdd);
      
      if(extremum == 2){ // buy
         extremum = iLowest(_Symbol, _Period, MODE_LOW, HiLoPeriodOpen);
         if(extremum == 2)
            directionAdvice[OP_BUY] = DirectionAdvice_Open;
         else
            directionAdvice[OP_BUY] = DirectionAdvice_Add;
      }
   }
   TradeAction();
}

bool TradeAction() {
   bool result = false;
   for(int type = OP_BUY; type <= OP_SELL; type++) {
      double lots = moneyManager.CalculateLot(type, tradeStats);
//      if(tradeStats.GetTotalLots(Utils::GetOppositeType(type)) > tradeStats.GetTotalLots(type))
//         lots = Utils::NormalizeLots(tradeStats.GetTotalLots() / tradeStats.GetCount(), symbolInfo.symbol);
      
      if(lastOrderTime < Time[0]
         && directionAdvice[type] == DirectionAdvice_Open  
         && profitStrategyManager.IsAllowedToOpen(type) 
        && tradeStats.GetCount(type) == 0
         ) {//Open is a strong signal promising long run
         if(SendOrder(type, lots, StopLossPips) > 0){
            lastOrderTime = Time[0];
            result = true;
         }         
      }
      if(lastOrderTime < Time[0] && (directionAdvice[type] == DirectionAdvice_Add || directionAdvice[type] == DirectionAdvice_Open)//Adding will be subject to spacing requirements only if we have buy already open
         && profitStrategyManager.IsAllowedToOpen(type)
         && tradeStats.GetCount(type) > 0 && Spacer::IsAllowedToOpen(tradeStats, type)) {
         if(SendOrder(type, lots, StopLossPips) > 0){
            lastOrderTime = Time[0];
            result = true;
         }
      }

      if(directionAdvice[type] == DirectionAdvice_Close && tradeStats.GetCount(type) > 0) {
         if(tradeUtils.CloseAllOfType(MagicNumber, type))
            result = true;
      }
   }
   return (result);
}
  
int SendOrder(int _type, double _lots, double _stopLossPips) {
   double openPrice = Utils::GetOpenPriceForDirection(_Symbol, _type);
   return tradeUtils.OpenOrderStopsInPips(_type, MagicNumber, _lots, _stopLossPips, 0.0, "Stupido " + Utils::TypeToStr(_type) + " order");
}



