//+------------------------------------------------------------------+
//| AQuantPrice_EA.mq5                                               |
//| Daily Camarilla/CPR conditions + 30-min TPO value area filters   |
//| Layered limit entries, measured risk, dynamic take profit        |
//+------------------------------------------------------------------+
#property copyright "AQuantPrice"
#property version   "1.00"
#property strict

#include <Trade/Trade.mqh>

enum ENUM_STOP_MODE { STOP_CAM4 = 0, STOP_CPR = 1, STOP_TIGHTER = 2, STOP_WIDER = 3 };
enum ENUM_TP_TESTED { TP_R1_S1 = 0, TP_H3_L3 = 1, TP_NEAREST = 2 };
enum ENUM_RISK_BASE { RISK_EQUITY = 0, RISK_BALANCE = 1 };

//--- risk
input group "Risk"
input double          RiskPercent        = 2.0;         // Total risk per trade setup (%), shared by all layers
input ENUM_RISK_BASE  RiskBase           = RISK_EQUITY; // Risk is calculated on
input bool            UseMinLotIfSmall   = false;       // Use min lot if calculated lot is below minimum
input long            MagicNumber        = 46553;

//--- conditions
input group "Daily conditions (Pine logic)"
input int             MinBuyConditions   = 15;          // Buy conditions required (max 15)
input int             MinSellConditions  = 13;          // Sell conditions required (max 13)

//--- TPO
input group "30-min TPO / Value Area"
input double          ValueAreaPercent   = 70.0;        // Value area %
input double          TPOBinSize         = 0.0;         // TPO price bin in price units (0 = auto)
input int             TPOAutoBins        = 60;          // Bins per day when auto

//--- layers
input group "Entry layers (buy: VAH,POC,TC,PP,L3 | sell: VAL,POC,TC,PP,H3)"
input bool            UseValueEdge       = true;        // VAH (buy) / VAL (sell)
input bool            UsePOC             = true;        // Previous day POC
input bool            UseTC              = true;        // Top central pivot (trend aware)
input bool            UsePP              = true;        // Pivot point
input bool            UseCamarilla3      = true;        // L3 (buy) / H3 (sell)
input int             MinLayerGapPoints  = 20;          // Minimum distance between layers (points)

//--- stop and target
input group "Stop loss / Take profit"
input ENUM_STOP_MODE  StopMode           = STOP_TIGHTER; // Buy: L4 / BC / nearer / farther  (sell: H4 / BC ...)
input int             StopBufferPoints   = 0;           // Extra buffer beyond stop level (points)
input ENUM_TP_TESTED  TPWhenPPTested     = TP_H3_L3;    // Target once PP is tested (R1/S1, H3/L3, nearest)
input int             PPTestTolPoints    = 0;           // Tolerance for "PP tested" (points)

//--- misc
input group "Misc"
input bool            CancelIfBelowVAH   = false;       // Cancel unfilled buys if M30 closes below VAH (sell: above VAL)
input bool            CloseAtNewDay      = false;       // Close open positions at new daily bar
input bool            ShowPanel          = true;

struct Levels
  {
   double P, BC, TC, R1, S1, R2, S2, H3, L3, H4, L4;
  };

struct TPOProfile
  {
   double poc, vah, val;
   bool   ok;
  };

CTrade   trade;
Levels   g_lv;
TPOProfile g_tpo;
datetime g_dayStart  = 0;
bool     g_setupDone = false;
bool     g_ppTested  = false;
int      g_side      = 0;      // 1 buy, -1 sell, 0 none
datetime g_lastTry   = 0;
datetime g_lastM30   = 0;
int      g_buyCnt    = 0;
int      g_sellCnt   = 0;
string   g_status    = "";

//+------------------------------------------------------------------+
//| Levels                                                           |
//+------------------------------------------------------------------+
void CalcLevels(double H, double L, double C, Levels &lv)
  {
   double rng = H - L;
   lv.P  = (H + L + C) / 3.0;
   lv.BC = (H + L) / 2.0;
   lv.TC = 2.0 * lv.P - lv.BC;      // raw formula: TC < BC after a bearish close, so it follows trend
   lv.R1 = 2.0 * lv.P - L;
   lv.S1 = 2.0 * lv.P - H;
   lv.R2 = lv.P + rng;
   lv.S2 = lv.P - rng;
   lv.H3 = C + rng * 1.1 / 4.0;
   lv.L3 = C - rng * 1.1 / 4.0;
   lv.H4 = C + rng * 1.1 / 2.0;
   lv.L4 = C - rng * 1.1 / 2.0;
  }

//+------------------------------------------------------------------+
//| Buy conditions (15) - same as indicator / screener               |
//+------------------------------------------------------------------+
int CountBuy(double h1, double l1, double c1, double h2, double l2, double c2, double o)
  {
   double cam  = (h1 - l1) * 1.1 / 4.0;
   double cam2 = (h2 - l2) * 1.1 / 4.0;
   double P1 = (h1 + l1 + c1) / 3.0, P2 = (h2 + l2 + c2) / 3.0;
   double w1 = (h1 + l1 + 4.0 * c1) / 6.0, w2 = (h2 + l2 + 4.0 * c2) / 6.0;
   double m1 = (h1 + l1) / 2.0, m2 = (h2 + l2) / 2.0;
   double R1 = 2.0 * P1 - l1;
   bool c[15];
   c[0]  = c1 + cam > c2 + cam2;
   c[1]  = c1 - cam > c2 - cam2;
   c[2]  = c1 > c1 - cam;
   c[3]  = o > c1 - cam;
   c[4]  = MathAbs(P1) > MathAbs(P2);
   c[5]  = w1 > w2;
   c[6]  = m1 > m2;
   c[7]  = c1 > w1;
   c[8]  = c1 > m1;
   c[9]  = o > P1;
   c[10] = c1 - cam > c2 + cam2;
   c[11] = m1 > w2;
   c[12] = h1 > h2;
   c[13] = o < R1;
   c[14] = c1 + cam > o;
   int n = 0;
   for(int i = 0; i < 15; i++)
      if(c[i])
         n++;
   return n;
  }

//+------------------------------------------------------------------+
//| Sell conditions (13)                                             |
//+------------------------------------------------------------------+
int CountSell(double h1, double l1, double c1, double h2, double l2, double c2, double o)
  {
   double cam  = (h1 - l1) * 1.1 / 4.0;
   double cam2 = (h2 - l2) * 1.1 / 4.0;
   double P1 = (h1 + l1 + c1) / 3.0, P2 = (h2 + l2 + c2) / 3.0;
   double w1 = (h1 + l1 + 4.0 * c1) / 6.0, w2 = (h2 + l2 + 4.0 * c2) / 6.0;
   double m1 = (h1 + l1) / 2.0, m2 = (h2 + l2) / 2.0;
   double S1 = 2.0 * P1 - h1;
   bool s[13];
   s[0]  = MathAbs(P1) < MathAbs(P2);
   s[1]  = w1 < w2;
   s[2]  = m1 < m2;
   s[3]  = c1 < m1;
   s[4]  = o < P1;
   s[5]  = c1 + cam < c2 + cam2;
   s[6]  = c1 - cam < c2 + cam2;
   s[7]  = o < c1 + cam;
   s[8]  = c1 < c1 + cam;
   s[9]  = m2 > w1;
   s[10] = c2 - cam2 > c1 + cam;
   s[11] = o > S1;
   s[12] = c1 - cam < o;
   int n = 0;
   for(int i = 0; i < 13; i++)
      if(s[i])
         n++;
   return n;
  }

//+------------------------------------------------------------------+
//| 30-minute TPO profile: POC and value area (VAL / VAH)            |
//+------------------------------------------------------------------+
bool BuildTPO(datetime t0, datetime t1, TPOProfile &p)
  {
   p.ok = false;
   MqlRates r[];
   int got = CopyRates(_Symbol, PERIOD_M30, t0, t1 - 1, r);
   if(got < 4)
      return false;

   double lo = r[0].low, hi = r[0].high;
   for(int i = 1; i < got; i++)
     {
      if(r[i].low < lo)  lo = r[i].low;
      if(r[i].high > hi) hi = r[i].high;
     }
   if(hi <= lo)
      return false;

   double bin = TPOBinSize > 0 ? TPOBinSize : (hi - lo) / MathMax(10, TPOAutoBins);
   if(bin < _Point)
      bin = _Point;

   int n = (int)MathFloor((hi - lo) / bin) + 1;
   long cnt[];
   ArrayResize(cnt, n);
   ArrayInitialize(cnt, 0);

   for(int i = 0; i < got; i++)
     {
      int a = (int)MathFloor((r[i].low - lo) / bin);
      int b = (int)MathFloor((r[i].high - lo) / bin);
      a = MathMax(0, MathMin(n - 1, a));
      b = MathMax(0, MathMin(n - 1, b));
      for(int k = a; k <= b; k++)
         cnt[k]++;               // one TPO (letter) per 30-min bar per price bin
     }

   long total = 0;
   int poc = 0;
   double midP = (lo + hi) / 2.0;
   for(int i = 0; i < n; i++)
     {
      total += cnt[i];
      double bi = lo + (i + 0.5) * bin, bp = lo + (poc + 0.5) * bin;
      if(cnt[i] > cnt[poc] || (cnt[i] == cnt[poc] && MathAbs(bi - midP) < MathAbs(bp - midP)))
         poc = i;
     }

   int up = poc, dn = poc;
   long sum = cnt[poc];
   double target = total * ValueAreaPercent / 100.0;
   while(sum < target)
     {
      long upSum = 0, dnSum = 0;
      int upN = 0, dnN = 0;
      for(int k = 1; k <= 2; k++)
        {
         if(up + k < n) { upSum += cnt[up + k]; upN++; }
         if(dn - k >= 0) { dnSum += cnt[dn - k]; dnN++; }
        }
      if(upN == 0 && dnN == 0)
         break;
      if(dnN == 0 || (upN > 0 && upSum >= dnSum))
        { up += upN; sum += upSum; }
      else
        { dn -= dnN; sum += dnSum; }
     }

   p.poc = lo + (poc + 0.5) * bin;
   p.vah = lo + (up + 1) * bin;
   p.val = lo + dn * bin;
   p.ok  = true;
   return true;
  }

//+------------------------------------------------------------------+
//| Helpers                                                          |
//+------------------------------------------------------------------+
double Nrm(double v) { return NormalizeDouble(v, _Digits); }

void AddLayer(double &p[], string &nm[], double price, string name)
  {
   int s = ArraySize(p);
   ArrayResize(p, s + 1);
   ArrayResize(nm, s + 1);
   p[s] = price;
   nm[s] = name;
  }

void SortLayers(double &p[], string &nm[], bool descending)
  {
   int n = ArraySize(p);
   for(int i = 0; i < n - 1; i++)
      for(int j = 0; j < n - 1 - i; j++)
        {
         bool swap = descending ? (p[j] < p[j + 1]) : (p[j] > p[j + 1]);
         if(swap)
           {
            double t = p[j]; p[j] = p[j + 1]; p[j + 1] = t;
            string s = nm[j]; nm[j] = nm[j + 1]; nm[j + 1] = s;
           }
        }
  }

double LotsForRisk(bool buy, double entry, double sl, double riskMoney)
  {
   double profit = 0;
   ENUM_ORDER_TYPE t = buy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
   if(!OrderCalcProfit(t, _Symbol, 1.0, entry, sl, profit))
      return 0;
   double lossPerLot = MathAbs(profit);
   if(lossPerLot <= 0)
      return 0;
   double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   double vmin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double vmax = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double lots = MathFloor(riskMoney / lossPerLot / step) * step;
   if(lots < vmin)
     {
      if(!UseMinLotIfSmall)
         return 0;
      lots = vmin;
     }
   return MathMin(lots, vmax);
  }

double ComputeTP(bool buy, double entry)
  {
   double minD = MathMax(MinLayerGapPoints, 10) * _Point;
   if(buy)
     {
      if(g_ppTested)
        {
         double cand = 0;
         if(TPWhenPPTested == TP_R1_S1)       cand = g_lv.R1;
         else if(TPWhenPPTested == TP_H3_L3)  cand = g_lv.H3;
         else
           {
            double a = g_lv.R1, b = g_lv.H3;
            bool av = a > entry + minD, bv = b > entry + minD;
            if(av && bv)  cand = MathMin(a, b);
            else if(av)   cand = a;
            else if(bv)   cand = b;
           }
         if(cand > entry + minD)
            return Nrm(cand);
        }
      return (g_lv.R2 > entry + minD) ? Nrm(g_lv.R2) : 0;
     }
   else
     {
      if(g_ppTested)
        {
         double cand = 0;
         if(TPWhenPPTested == TP_R1_S1)       cand = g_lv.S1;
         else if(TPWhenPPTested == TP_H3_L3)  cand = g_lv.L3;
         else
           {
            double a = g_lv.S1, b = g_lv.L3;
            bool av = a < entry - minD, bv = b < entry - minD;
            if(av && bv)  cand = MathMax(a, b);
            else if(av)   cand = a;
            else if(bv)   cand = b;
           }
         if(cand > 0 && cand < entry - minD)
            return Nrm(cand);
        }
      return (g_lv.S2 < entry - minD) ? Nrm(g_lv.S2) : 0;
     }
  }

double ComputeSL(bool buy)
  {
   double buf = StopBufferPoints * _Point;
   if(buy)
     {
      double a = g_lv.L4, b = g_lv.BC, sl;
      switch(StopMode)
        {
         case STOP_CAM4:    sl = a; break;
         case STOP_CPR:     sl = b; break;
         case STOP_TIGHTER: sl = MathMax(a, b); break;
         default:           sl = MathMin(a, b); break;
        }
      return Nrm(sl - buf);
     }
   double a = g_lv.H4, b = g_lv.BC, sl;
   switch(StopMode)
     {
      case STOP_CAM4:    sl = a; break;
      case STOP_CPR:     sl = b; break;
      case STOP_TIGHTER: sl = MathMin(a, b); break;
      default:           sl = MathMax(a, b); break;
     }
   return Nrm(sl + buf);
  }

//+------------------------------------------------------------------+
//| Order management                                                 |
//+------------------------------------------------------------------+
bool HasMyExposure()
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong t = PositionGetTicket(i);
      if(t == 0) continue;
      if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && PositionGetString(POSITION_SYMBOL) == _Symbol)
         return true;
     }
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      ulong t = OrderGetTicket(i);
      if(t == 0) continue;
      if(OrderGetInteger(ORDER_MAGIC) == MagicNumber && OrderGetString(ORDER_SYMBOL) == _Symbol)
         return true;
     }
   return false;
  }

void DeleteMyPendings()
  {
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      ulong t = OrderGetTicket(i);
      if(t == 0) continue;
      if(OrderGetInteger(ORDER_MAGIC) == MagicNumber && OrderGetString(ORDER_SYMBOL) == _Symbol)
         trade.OrderDelete(t);
     }
  }

void CloseMyPositions()
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong t = PositionGetTicket(i);
      if(t == 0) continue;
      if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && PositionGetString(POSITION_SYMBOL) == _Symbol)
         trade.PositionClose(t);
     }
  }

void UpdateTPs()
  {
   if(g_side == 0) return;
   bool buy = (g_side == 1);
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong t = PositionGetTicket(i);
      if(t == 0) continue;
      if(PositionGetInteger(POSITION_MAGIC) != MagicNumber || PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
      double tp = ComputeTP(buy, PositionGetDouble(POSITION_PRICE_OPEN));
      if(tp > 0 && MathAbs(tp - PositionGetDouble(POSITION_TP)) > _Point)
         trade.PositionModify(t, PositionGetDouble(POSITION_SL), tp);
     }
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      ulong t = OrderGetTicket(i);
      if(t == 0) continue;
      if(OrderGetInteger(ORDER_MAGIC) != MagicNumber || OrderGetString(ORDER_SYMBOL) != _Symbol) continue;
      double tp = ComputeTP(buy, OrderGetDouble(ORDER_PRICE_OPEN));
      if(tp > 0 && MathAbs(tp - OrderGetDouble(ORDER_TP)) > _Point)
         trade.OrderModify(t, OrderGetDouble(ORDER_PRICE_OPEN), OrderGetDouble(ORDER_SL), tp, ORDER_TIME_GTC, 0);
     }
  }

//+------------------------------------------------------------------+
//| Build and place the layered limit orders                         |
//+------------------------------------------------------------------+
int PlaceLayers(bool buy)
  {
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double stopLvl = (double)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * _Point;
   double gap = MinLayerGapPoints * _Point;

   double raw[]; string rawN[];
   if(buy)
     {
      if(UseValueEdge)   AddLayer(raw, rawN, g_tpo.vah, "VAH");
      if(UsePOC)         AddLayer(raw, rawN, g_tpo.poc, "POC");
      if(UseTC)          AddLayer(raw, rawN, g_lv.TC,   "TC");
      if(UsePP)          AddLayer(raw, rawN, g_lv.P,    "PP");
      if(UseCamarilla3)  AddLayer(raw, rawN, g_lv.L3,   "L3");
     }
   else
     {
      if(UseValueEdge)   AddLayer(raw, rawN, g_tpo.val, "VAL");
      if(UsePOC)         AddLayer(raw, rawN, g_tpo.poc, "POC");
      if(UseTC)          AddLayer(raw, rawN, g_lv.TC,   "TC");
      if(UsePP)          AddLayer(raw, rawN, g_lv.P,    "PP");
      if(UseCamarilla3)  AddLayer(raw, rawN, g_lv.H3,   "H3");
     }
   SortLayers(raw, rawN, buy);   // buy: highest first, sell: lowest first

   double sl = ComputeSL(buy);
   double lp[]; string ln[];
   for(int i = 0; i < ArraySize(raw); i++)
     {
      double pr = Nrm(raw[i]);
      bool valid = buy ? (pr < ask - stopLvl && pr > sl + gap)
                       : (pr > bid + stopLvl && pr < sl - gap);
      if(!valid) continue;
      int s = ArraySize(lp);
      if(s > 0 && MathAbs(lp[s - 1] - pr) < gap) continue;   // too close to previous layer
      AddLayer(lp, ln, pr, rawN[i]);
     }

   int n = ArraySize(lp);
   if(n == 0)
     {
      g_status = "No valid layer below/above market";
      return 0;
     }

   double base = (RiskBase == RISK_EQUITY) ? AccountInfoDouble(ACCOUNT_EQUITY) : AccountInfoDouble(ACCOUNT_BALANCE);
   double perLayerRisk = base * RiskPercent / 100.0 / n;
   int placed = 0;
   for(int i = 0; i < n; i++)
     {
      double lots = LotsForRisk(buy, lp[i], sl, perLayerRisk);
      if(lots <= 0)
        {
         PrintFormat("Layer %s skipped: lot below minimum for the risk", ln[i]);
         continue;
        }
      double tp = ComputeTP(buy, lp[i]);
      string cmt = "AQ " + (buy ? "B-" : "S-") + ln[i];
      bool ok = buy ? trade.BuyLimit(lots, lp[i], _Symbol, sl, tp, ORDER_TIME_GTC, 0, cmt)
                    : trade.SellLimit(lots, lp[i], _Symbol, sl, tp, ORDER_TIME_GTC, 0, cmt);
      if(ok) placed++;
      else PrintFormat("Order %s failed: %d %s", cmt, trade.ResultRetcode(), trade.ResultRetcodeDescription());
     }
   return placed;
  }

//+------------------------------------------------------------------+
//| Daily setup                                                      |
//+------------------------------------------------------------------+
void TrySetup()
  {
   if(TimeCurrent() - g_lastTry < 15) return;
   g_lastTry = TimeCurrent();

   if(HasMyExposure()) { g_setupDone = true; g_status = "Exposure already open"; return; }

   double h1 = iHigh(_Symbol, PERIOD_D1, 1), l1 = iLow(_Symbol, PERIOD_D1, 1), c1 = iClose(_Symbol, PERIOD_D1, 1);
   double h2 = iHigh(_Symbol, PERIOD_D1, 2), l2 = iLow(_Symbol, PERIOD_D1, 2), c2 = iClose(_Symbol, PERIOD_D1, 2);
   double o  = iOpen(_Symbol, PERIOD_D1, 0);
   datetime t0 = iTime(_Symbol, PERIOD_D1, 1), t1 = iTime(_Symbol, PERIOD_D1, 0);
   if(h1 <= 0 || h2 <= 0 || o <= 0 || t0 == 0) { g_status = "Waiting for D1 history"; return; }

   if(!BuildTPO(t0, t1, g_tpo)) { g_status = "Waiting for M30 history"; return; }

   CalcLevels(h1, l1, c1, g_lv);
   g_buyCnt  = CountBuy(h1, l1, c1, h2, l2, c2, o);
   g_sellCnt = CountSell(h1, l1, c1, h2, l2, c2, o);

   bool buyOK  = g_buyCnt  >= MinBuyConditions  && o > g_tpo.vah && c1 > g_tpo.poc;
   bool sellOK = g_sellCnt >= MinSellConditions && o < g_tpo.val && c1 < g_tpo.poc;

   g_setupDone = true;
   g_ppTested = false;
   PrintFormat("Setup %s | buy %d/15 sell %d/13 | open %.5f VAH %.5f POC %.5f VAL %.5f prevClose %.5f",
               TimeToString(t1), g_buyCnt, g_sellCnt, o, g_tpo.vah, g_tpo.poc, g_tpo.val, c1);

   if(buyOK && !sellOK)
     {
      g_side = 1;
      int n = PlaceLayers(true);
      g_status = StringFormat("BUY setup: %d layers placed", n);
     }
   else if(sellOK && !buyOK)
     {
      g_side = -1;
      int n = PlaceLayers(false);
      g_status = StringFormat("SELL setup: %d layers placed", n);
     }
   else
      g_status = "No trade: filters not all true";
  }

void ManageDay()
  {
   if(g_side == 0) return;

   // PP tested -> switch target (buy: low touched PP, sell: high touched PP)
   if(!g_ppTested)
     {
      double tol = PPTestTolPoints * _Point;
      bool tested = (g_side == 1) ? (iLow(_Symbol, PERIOD_D1, 0) <= g_lv.P + tol)
                                  : (iHigh(_Symbol, PERIOD_D1, 0) >= g_lv.P - tol);
      if(tested)
        {
         g_ppTested = true;
         UpdateTPs();
        }
     }

   // optional: cancel unfilled layers once value is lost
   if(CancelIfBelowVAH)
     {
      datetime m = iTime(_Symbol, PERIOD_M30, 0);
      if(m != g_lastM30)
        {
         g_lastM30 = m;
         double cl = iClose(_Symbol, PERIOD_M30, 1);
         if((g_side == 1 && cl < g_tpo.vah) || (g_side == -1 && cl > g_tpo.val))
            DeleteMyPendings();
        }
     }
  }

void RecoverState()
  {
   for(int i = PositionsTotal() - 1; i >= 0 && g_side == 0; i--)
     {
      ulong t = PositionGetTicket(i);
      if(t == 0) continue;
      if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && PositionGetString(POSITION_SYMBOL) == _Symbol)
         g_side = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? 1 : -1;
     }
   for(int i = OrdersTotal() - 1; i >= 0 && g_side == 0; i--)
     {
      ulong t = OrderGetTicket(i);
      if(t == 0) continue;
      if(OrderGetInteger(ORDER_MAGIC) == MagicNumber && OrderGetString(ORDER_SYMBOL) == _Symbol)
         g_side = (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_LIMIT) ? 1 : -1;
     }
   if(g_side != 0)
     {
      double h1 = iHigh(_Symbol, PERIOD_D1, 1), l1 = iLow(_Symbol, PERIOD_D1, 1), c1 = iClose(_Symbol, PERIOD_D1, 1);
      CalcLevels(h1, l1, c1, g_lv);
      BuildTPO(iTime(_Symbol, PERIOD_D1, 1), iTime(_Symbol, PERIOD_D1, 0), g_tpo);
      g_dayStart = iTime(_Symbol, PERIOD_D1, 0);
      g_setupDone = true;
      g_status = "Recovered existing setup";
     }
  }

void DrawPanel()
  {
   if(!ShowPanel) return;
   string s = "AQuantPrice EA\n";
   s += StringFormat("Buy conditions %d/15 (need %d) | Sell %d/13 (need %d)\n", g_buyCnt, MinBuyConditions, g_sellCnt, MinSellConditions);
   if(g_tpo.ok)
      s += StringFormat("VAH %.*f  POC %.*f  VAL %.*f\n", _Digits, g_tpo.vah, _Digits, g_tpo.poc, _Digits, g_tpo.val);
   s += StringFormat("PP %.*f  TC %.*f  BC %.*f\n", _Digits, g_lv.P, _Digits, g_lv.TC, _Digits, g_lv.BC);
   s += StringFormat("L3 %.*f  L4 %.*f  H3 %.*f  H4 %.*f\n", _Digits, g_lv.L3, _Digits, g_lv.L4, _Digits, g_lv.H3, _Digits, g_lv.H4);
   s += "PP tested: " + (g_ppTested ? "yes" : "no") + "\n";
   s += "Status: " + g_status;
   Comment(s);
  }

//+------------------------------------------------------------------+
int OnInit()
  {
   trade.SetExpertMagicNumber(MagicNumber);
   trade.SetDeviationInPoints(30);
   trade.SetTypeFillingBySymbol(_Symbol);
   ZeroMemory(g_lv);
   ZeroMemory(g_tpo);
   RecoverState();
   return INIT_SUCCEEDED;
  }

void OnDeinit(const int reason) { Comment(""); }

void OnTick()
  {
   datetime d0 = iTime(_Symbol, PERIOD_D1, 0);
   if(d0 == 0) return;

   if(d0 != g_dayStart)
     {
      g_dayStart  = d0;
      g_setupDone = false;
      g_ppTested  = false;
      g_side      = 0;
      g_lastTry   = 0;
      DeleteMyPendings();
      if(CloseAtNewDay) CloseMyPositions();
     }

   if(!g_setupDone) TrySetup();
   else             ManageDay();

   DrawPanel();
  }
//+------------------------------------------------------------------+
