Cisd logic troubleshooting. CRT - C1 LTF PROJECTION - CISD PLOT

 
Hey guys hope everyone is having a great trading year so far. 

Just needed to ask for help debugging a cisd(change in state of delivery) code am working on. For the most part it is delivering the cisd upon sweep but it does miss lots of post sweep series of defending candles. Do you have any idea on how to overcome this. The core logic is detection crt ranges on either of the 2 HTFs which then project c1 levels on the current ltf and then a cisd scan starts once a block is broken. The code is somehow producing good cisd but mostly it fails to capture post sweep blocks which can be very valid. Also sometimes once a sweep is detected, and there happens to be an old broken block within c1 which took place before the sweep, it gets marked and that is not structurally correct. We only need to mark post sweep bar breaks. The candle breaking the blocks either pre sweep or post sweep should be after the sweep ltf time itself. I'd really appreciate any help in solving those. issues 

CISD Detection – Structural Refactor Needed

The current CISD engine produces valid signals but suffers from structural inconsistencies around sweep anchoring, block detection, and breakout prioritization.

Main problems:

     

  • Daily and weekly and monthly cisd are not properly drawing despite the crt and Ltf projections printing on the charts.

  • Post-sweep defending blocks are sometimes ignored in favor of older pre-sweep blocks, causing delayed or structurally incorrect CISD signals.

  • Pre-sweep blocks can override post-sweep structure even when the post-sweep breakout occurs first.

  • Block detection occasionally splits contiguous defending clusters or anchors mid-block instead of using the true oldest candle.

  • Breakout logic is not fully standardized (mix of open/close/high/low checks), leading to inconsistent trigger behavior.

Goal:

Rework the CISD engine so that the sweep is the strict structural anchor, blocks are clean contiguous defending sequences, and the first valid breakout after the sweep triggers CISD — with no implicit priority conflicts and a clearly defined breakout rule.

In the photo usually if i have a cisd for htf2 it tends to skip the most obvioous and nearest block near the sweep and marks the oldest block if there is any. That is why i introduced the reuse logic from htf1 cisd calculation. So the fl

// === CRT CISD GLOBALS ===
// CRT Alert Tracking
datetime lastBearishCRTAlertTime_HTF1 = 0;
datetime lastBullishCRTAlertTime_HTF1 = 0;
datetime lastBearishCRTAlertTime_HTF2 = 0;
datetime lastBullishCRTAlertTime_HTF2 = 0;

// Bar Time Tracking
static datetime lastHtf1BarTime = 0;
static datetime lastHtf2BarTime = 0;

// HTF1 CRT storage
double crtHighs_HTF1[], crtLows_HTF1[];
datetime crtTimes_HTF1[];
int crtCount_HTF1 = 0;

// HTF2 CRT storage
double crtHighs_HTF2[], crtLows_HTF2[];
datetime crtTimes_HTF2[];
int crtCount_HTF2 = 0;

// === CISD STATUS LOCKS ===
datetime lastBearishCISDTime_HTF1 = 0;
datetime lastBullishCISDTime_HTF1 = 0;
datetime lastBearishCISDTime_HTF2 = 0;
datetime lastBullishCISDTime_HTF2 = 0;
datetime lastCISDCheckTime = 0;
// === CISD BLOCK FREEZE (per sweep) ===
datetime lastBlockSelectionSweep_HTF1 = 0;
datetime lastBlockSelectionSweep_HTF2 = 0;
// === CISD CACHE FOR HTF2 REUSE ===
datetime lastCISD_SweepTime_HTF1 = 0;
double   lastCISD_KeyLevel_HTF1  = 0;
datetime lastCISD_StartTime_HTF1 = 0;
bool     lastCISD_Valid_HTF1     = false;
datetime lastCISD_SweepTime_HTF2 = 0;
double   lastCISD_KeyLevel_HTF2  = 0;
datetime lastCISD_StartTime_HTF2 = 0;
bool     lastCISD_Valid_HTF2     = false;

// === CISD LOCK STATE (PREVENT GREEDY REBUILD) ===
bool lastCISD_Locked_HTF1 = false;
bool lastCISD_Locked_HTF2 = false;
// === CISD DIRECTION CACHE ===
bool lastCISD_IsBullish_HTF1 = false;
bool lastCISD_IsBullish_HTF2 = false;
// Guards to ensure each sweep event is processed only once
static datetime lastProcessedSweep_HTF1 = 0;   // last HTF1 sweep we cached
static datetime lastProcessedSweep_HTF2 = 0;   // last HTF2 sweep we reused
datetime lastCISD_Start_HTF1 = 0;
datetime lastCISD_End_HTF1 = 0;
double   lastCISD_Level_HTF1 = 0;
//+------------------------------------------------------------------+
//| CRT Detection - Dispatcher (all or only recent)                 |
//+------------------------------------------------------------------+
void DetectAndDrawHTFCRT(ENUM_TIMEFRAMES htf, int candleCount, string prefix)
{
    if(ShowOnlyRecentCRT)
        DetectAndDrawRecentCRT(htf, candleCount, prefix);
    else
        DetectAndDrawAllCRT(htf, candleCount, prefix);
}


//+------------------------------------------------------------------+
//| Optimized All CRT – with caching (no mass deletion)             |
//+------------------------------------------------------------------+
void DetectAndDrawAllCRT(ENUM_TIMEFRAMES htf,int candleCount,string prefix){
 int spacing=(int)(HTF_CandleSpacing*PeriodSeconds(_Period));
 datetime baseTime=iTime(_Symbol,_Period,0)+HTF_RightOffsetBars*PeriodSeconds(_Period);
 int offset=(prefix=="HTF2_CRT_")?(HTF1_CandleCount*spacing+10*PeriodSeconds(_Period)):0;
 // Remove DeleteAllCRTObjects(prefix); – we now handle individually
 int maxLookback=MathMin(30,candleCount-1);
 double oArr[],hArr[],lArr[],cArr[];
 datetime timeArr[];
 ArrayResize(oArr,maxLookback+2);ArrayResize(hArr,maxLookback+2);
 ArrayResize(lArr,maxLookback+2);ArrayResize(cArr,maxLookback+2);
 ArrayResize(timeArr,maxLookback+2);
 for(int i=0;i<=maxLookback+1;i++){
  if(htf==PERIOD_3M){
   GetQuarterlyOHLC(i,oArr[i],hArr[i],lArr[i],cArr[i]);
   timeArr[i]=GetQuarterlyTime(i);
  }else{
   oArr[i]=iOpen(_Symbol,htf,i);hArr[i]=iHigh(_Symbol,htf,i);
   lArr[i]=iLow(_Symbol,htf,i);cArr[i]=iClose(_Symbol,htf,i);
   timeArr[i]=iTime(_Symbol,htf,i);
  }
 }
 double bidPrice=SymbolInfoDouble(_Symbol,SYMBOL_BID);
 bool mostRecentBearishAlerted=false,mostRecentBullishAlerted=false;

 for(int i=1;i<=maxLookback;i++){
  int s1=i,s2=i-1;
  double h1=hArr[s1],l1=lArr[s1],c1=cArr[s1],o1=oArr[s1];
  double h2=hArr[s2],l2=lArr[s2],c2=cArr[s2],o2=oArr[s2];
  if(h1<=0||l1<=0)continue;
  datetime sweepTime=timeArr[s2],baseTimeC=timeArr[s1];
  bool isClosed=(htf==PERIOD_3M)? true : (TimeCurrent()>=sweepTime+PeriodSeconds(htf));
  double baseRange=MathMax(h1-l1,0.00001),penetrationPct=0.0;
  bool allowEarly=false;

  if(!isClosed&&i==1){
   double progress=(double)(TimeCurrent()-sweepTime)/PeriodSeconds(htf);
   if(progress>=CRT_CompletionThreshold){
    if(h2>h1&&bidPrice<h1)penetrationPct=(h1-bidPrice)/baseRange;
    else if(l2<l1&&bidPrice>l1)penetrationPct=(bidPrice-l1)/baseRange;
    if(penetrationPct>=MinPenetrationPercentage)
     if((h2>h1&&bidPrice<h1&&bidPrice<MathMax(o2,c2))||
        (l2<l1&&bidPrice>l1&&bidPrice>MathMin(o2,c2)))allowEarly=true;
   }
  }

  bool meetsPenetration=isClosed||(penetrationPct>=MinPenetrationPercentage);
  if(!isClosed&&i!=1)continue;

  datetime t1=baseTime+offset+(candleCount-1-s1)*spacing;
  datetime t2=baseTime+offset+(candleCount-1-s2)*spacing;
  bool isOutside=(h2>=h1&&l2<=l1),resolveBearish=false,resolveBullish=false;
  if(isOutside){if(c2<o2)resolveBearish=true;else if(c2>o2)resolveBullish=true;}

  bool isBearishCRT=(h2>h1)&&(isClosed||allowEarly)&&
   (StrictCRTClose?(c2<c1):(c2<h1||(allowEarly&&bidPrice<h1)))&&
   (!isOutside||resolveBearish);

  bool isBullishCRT=(l2<l1)&&(isClosed||allowEarly)&&
   (StrictCRTClose?(c2>c1):(c2>l1||(allowEarly&&bidPrice>l1)))&&
   (!isOutside||resolveBullish);

  // -------- BEARISH --------
  if(isBearishCRT&&meetsPenetration){
   bool traded=false,broken=false;
   for(int j=s2-1;j>=0;j--){if(lArr[j]<h1)traded=true;if(cArr[j]>h1)broken=true;if(traded&&broken)break;}
   color col=BearishCRTColor;ENUM_LINE_STYLE sty=CRTLineStyle;
   if(isOutside){col=clrDarkSlateGray;sty=STYLE_DASHDOT;}
   else if(broken){col=clrDimGray;sty=STYLE_DOT;}
   else if(traded){col=clrGray;sty=STYLE_DASH;}
   else if(!isClosed){col=clrOrange;sty=STYLE_DASH;}
   string name=prefix+"CRT_BEAR_"+IntegerToString(i);
   
   // --- Caching guard: if line exists with same level, skip redraw ---
   bool needRedraw = true;
   if(ObjectFind(0,name) >= 0)
   {
       double existingLevel = ObjectGetDouble(0, name, OBJPROP_PRICE, 0);
       if(MathAbs(existingLevel - h1) <= _Point)
           needRedraw = false;
       else
           ObjectDelete(0,name);
   }
   if(needRedraw)
   {
       DrawCRTLineEx(name,t1,h1,t2,h1,col,sty,baseTimeC,sweepTime);
   }
   
   if(i==1&&!mostRecentBearishAlerted){
    SendCRTAlert(true,isClosed,htf,h1,sweepTime,prefix,penetrationPct,TimeframeToString(htf));
    mostRecentBearishAlerted=true;
   }
   if(ShowLTFCRTProjections)
    ProjectCRTToLTF(prefix+"LTF_BEAR_"+IntegerToString(i),h1,true,baseTimeC,sweepTime,htf);
   DetectAndMarkCISD_LTF(htf,sweepTime,h1,true,15,prefix+"CISD_");
  }

  // -------- BULLISH --------
  if(isBullishCRT&&meetsPenetration){
   bool traded=false,broken=false;
   for(int j=s2-1;j>=0;j--){if(hArr[j]>l1)traded=true;if(cArr[j]<l1)broken=true;if(traded&&broken)break;}
   color col=BullishCRTColor;ENUM_LINE_STYLE sty=CRTLineStyle;
   if(isOutside){col=clrDarkSlateGray;sty=STYLE_DASHDOT;}
   else if(broken){col=clrDimGray;sty=STYLE_DOT;}
   else if(traded){col=clrGray;sty=STYLE_DASH;}
   else if(!isClosed){col=clrBlue;sty=STYLE_DASH;}
   string name=prefix+"CRT_BULL_"+IntegerToString(i);
   
   // --- Caching guard ---
   bool needRedraw = true;
   if(ObjectFind(0,name) >= 0)
   {
       double existingLevel = ObjectGetDouble(0, name, OBJPROP_PRICE, 0);
       if(MathAbs(existingLevel - l1) <= _Point)
           needRedraw = false;
       else
           ObjectDelete(0,name);
   }
   if(needRedraw)
   {
       DrawCRTLineEx(name,t1,l1,t2,l1,col,sty,baseTimeC,sweepTime);
   }
   
   if(i==1&&!mostRecentBullishAlerted){
    SendCRTAlert(false,isClosed,htf,l1,sweepTime,prefix,penetrationPct,TimeframeToString(htf));
    mostRecentBullishAlerted=true;
   }
   if(ShowLTFCRTProjections)
    ProjectCRTToLTF(prefix+"LTF_BULL_"+IntegerToString(i),l1,false,baseTimeC,sweepTime,htf);
   DetectAndMarkCISD_LTF(htf,sweepTime,l1,false,15,prefix+"CISD_");
  }
 }
}

void ProjectCRTToLTF(string name, double lvl, bool bear, datetime bt, datetime swt, ENUM_TIMEFRAMES htf)
{
   string lineName = name + "_LINE", lblName = name + "_C1";
   bool needRedraw = true;
   if(ObjectFind(0, lineName) >= 0)
   {
      double ex = ObjectGetDouble(0, lineName, OBJPROP_PRICE, 0);
      if(MathAbs(ex - lvl) <= _Point) needRedraw = false;
      else ObjectDelete(0, lineName);
   }
   if(needRedraw)
   {
      int sb = iBarShift(_Symbol, htf, swt, true);
      datetime end = swt + (sb >= 0 ? PeriodSeconds(htf) - 1 : 0);
      datetime L = bt - PeriodSeconds(_Period) * 2, R = MathMin(end, TimeCurrent());
      ObjectCreate(0, lineName, OBJ_TREND, 0, L, lvl, R, lvl);
      ObjectSetInteger(0, lineName, OBJPROP_COLOR, bear ? LTF_BearishCRTColor : LTF_BullishCRTColor);
      ObjectSetInteger(0, lineName, OBJPROP_STYLE, LTF_CRTLineStyle);
      ObjectSetInteger(0, lineName, OBJPROP_WIDTH, LTF_CRTLineWidth);
      ObjectSetInteger(0, lineName, OBJPROP_RAY, false);
      ObjectSetInteger(0, lineName, OBJPROP_BACK, true);
      string tfStr = TimeframeToString(htf);
      ObjectSetString(0, lineName, OBJPROP_TOOLTIP, StringFormat("%s CRT [%s→%s]\nLevel:%.5f\nBase:%s\nSweep:%s",
                        bear?"BEARISH":"BULLISH", tfStr, TimeframeToString(_Period), lvl,
                        TimeToString(bt, TIME_DATE|TIME_MINUTES), TimeToString(swt, TIME_DATE|TIME_MINUTES)));
   }
   if(ShowLTFCRTLabels)
   {
      bool needLbl = true;
      if(ObjectFind(0, lblName) >= 0)
      {
         if(!needRedraw) needLbl = false;
         else ObjectDelete(0, lblName);
      }
      if(needLbl)
      {
         int sb = iBarShift(_Symbol, htf, swt, true);
         datetime end = swt + (sb >= 0 ? PeriodSeconds(htf) - 1 : 0);
         datetime L = bt - PeriodSeconds(_Period) * 2, R = MathMin(end, TimeCurrent());
         datetime mid = L + (R - L) / 2;
         double tick = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
         if(tick <= 0) tick = _Point;
         double off = MathMax(tick * 5, MathMin(tick * 100, tick * 20));
         double prc = lvl + (bear ? off : -off);
         ObjectCreate(0, lblName, OBJ_TEXT, 0, mid, prc);
         ObjectSetString(0, lblName, OBJPROP_TEXT, "C1");
         int fsz = (StringFind(name, "HTF2_") >= 0) ? 11 : 8;
         ObjectSetInteger(0, lblName, OBJPROP_COLOR, bear ? clrRed : clrGreen);
         ObjectSetInteger(0, lblName, OBJPROP_FONTSIZE, fsz);
         ObjectSetInteger(0, lblName, OBJPROP_BACK, true);
         ObjectSetInteger(0, lblName, OBJPROP_ANCHOR, bear ? ANCHOR_LEFT_LOWER : ANCHOR_LEFT_UPPER);
         string tfStr = TimeframeToString(htf);
         ObjectSetString(0, lblName, OBJPROP_TOOLTIP, StringFormat("C1 Base [%s]\nTime:%s\nLevel:%.5f\n%s",
                           tfStr, TimeToString(bt, TIME_DATE|TIME_MINUTES), lvl, bear?"Bearish":"Bullish"));
      }
   }
}
//+------------------------------------------------------------------+
//| Check for LTF Price Touch of CRT Level                          |
//+------------------------------------------------------------------+
void CheckLTFCRTTouch()
{
    static datetime lastTouchAlert = 0;
    if(!ShowLTFCRTAlerts || TimeCurrent() - lastTouchAlert < 300) return;
    
    double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    int total = ObjectsTotal(0);
    
    for(int i = 0; i < total; i++) {
        string name = ObjectName(0, i);
        if(StringFind(name, "LTF_") < 0 || StringFind(name, "_LINE") < 0) continue;
        
        double level = ObjectGetDouble(0, name, OBJPROP_PRICE, 0);
        double touchDistance = MathAbs(currentPrice - level) / _Point;
        
        if(touchDistance <= 50) { // 5 pips
            string tooltip = ObjectGetString(0, name, OBJPROP_TOOLTIP);
            Print("⚡ LTF CRT TOUCH: ", tooltip, " | Current: ", currentPrice, " | Distance: ", touchDistance/10, " pips");
            lastTouchAlert = TimeCurrent();
            break;
        }
    }
}

//+------------------------------------------------------------------+
//| IMPROVED CISD Detection - SWEEP-ANCHORED BLOCK + FORWARD SCAN   |
//| Added HTF2 reuse with exact line copy (left start)             |
//+------------------------------------------------------------------+
void DetectAndMarkCISD_LTF(ENUM_TIMEFRAMES htf,datetime swT,double swP,bool isBear,int maxL=20,string pfx="CISD_"){
if(!ShowCISD_LTF) return;
datetime cut=swT+3*PeriodSeconds(htf); string htfStr=TimeframeToString(htf); int dgt=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
int swBar=iBarShift(_Symbol,_Period,swT,true); if(swBar<0) return;
datetime barOpen=iTime(_Symbol,_Period,swBar); if(barOpen<swT && swBar<iBars(_Symbol,_Period)-1) swBar++;
bool isH1=(StringFind(pfx,"HTF1_")!=-1), isH2=(StringFind(pfx,"HTF2_")!=-1);
// ------------------- HTF2 REUSE (exact copy) -------------------
if(isH2 && ReuseHTF1CISDforHTF2 && lastCISD_Valid_HTF1){
bool h2NeedBull=!isBear;
if(lastCISD_IsBullish_HTF1 == h2NeedBull){
datetime h2Start=swT, h2End=swT+PeriodSeconds(htf)-1;
if(lastCISD_SweepTime_HTF1>=h2Start && lastCISD_SweepTime_HTF1<=h2End){
string ln=pfx+htfStr+"_"+(isBear?"BEAR_":"BULL_")+"REUSE";
if(ObjectFind(0,ln)>=0){
double existingLevel=ObjectGetDouble(0,ln,OBJPROP_PRICE,0);
if(MathAbs(existingLevel-lastCISD_Level_HTF1)<=_Point){ lastCISD_SweepTime_HTF2=swT; lastCISD_Locked_HTF2=true; return; }
else ObjectDelete(0,ln); }
ObjectCreate(0,ln,OBJ_TREND,0,lastCISD_Start_HTF1,lastCISD_Level_HTF1,lastCISD_End_HTF1,lastCISD_Level_HTF1);
color clr=isBear?CISD_BearishColor:CISD_BullishColor;
ObjectSetInteger(0,ln,OBJPROP_COLOR,clr); ObjectSetInteger(0,ln,OBJPROP_WIDTH,CISD_LineWidth);
ObjectSetInteger(0,ln,OBJPROP_STYLE,CISD_LineStyle); ObjectSetInteger(0,ln,OBJPROP_RAY,false);
ObjectSetInteger(0,ln,OBJPROP_BACK,true); ObjectSetInteger(0,ln,OBJPROP_SELECTABLE,false);
string dir=isBear?"BEARISH":"BULLISH";
string tip=StringFormat("%s CISD [%s→%s] (reused from HTF1)\nC1 %s: %.*f @ %s\nLevel: %.*f",dir,htfStr,TimeframeToString(_Period),isBear?"HIGH":"LOW",dgt,swP,TimeToString(swT-PeriodSeconds(htf),TIME_MINUTES),dgt,lastCISD_Level_HTF1);
ObjectSetString(0,ln,OBJPROP_TOOLTIP,tip);
lastCISD_SweepTime_HTF2=swT; lastCISD_Locked_HTF2=true; return; } } }
// ------------------- LOCK CHECK -------------------
double keyLvl=0; datetime startTm=0; bool locked=false;
if(isH1 && lastCISD_Locked_HTF1 && lastCISD_SweepTime_HTF1==swT){ locked=true; keyLvl=lastCISD_KeyLevel_HTF1; startTm=lastCISD_StartTime_HTF1; }
if(isH2 && lastCISD_Locked_HTF2 && lastCISD_SweepTime_HTF2==swT){ locked=true; keyLvl=lastCISD_KeyLevel_HTF2; startTm=lastCISD_StartTime_HTF2; }
// ------------------- BUILD BLOCK -------------------
if(!locked){
double swO=iOpen(_Symbol,_Period,swBar), swC=iClose(_Symbol,_Period,swBar);
bool def=(isBear)?(swC>swO):(swC<swO);
int blkStart=-1, blkEnd=-1;
if(def){ // defending sweep
blkStart=swBar; blkEnd=swBar;
for(int b=swBar+1; b<iBars(_Symbol,_Period) && b<=swBar+maxL; b++){
double o=iOpen(_Symbol,_Period,b), c=iClose(_Symbol,_Period,b);
bool isDef2=(isBear)?(c>o):(c<o);
if(!isDef2) break;
if(b == blkStart + 1) blkStart = b; else break; } }
else{ // NON-DEFENDING SWEEP
int b = swBar-1;
if(b>=0){
double o=iOpen(_Symbol,_Period,b), c=iClose(_Symbol,_Period,b);
bool isDef=(isBear)?(c>o):(c<o);
if(isDef){ blkStart=b; blkEnd=b;
for(int k=b-1; k>=0 && k>=b-maxL; k--){
double ko=iOpen(_Symbol,_Period,k), kc=iClose(_Symbol,_Period,k);
bool isDef2=(isBear)?(kc>ko):(kc<ko);
if(!isDef2) break;
if(k == blkStart - 1) blkStart = k; else break; } } }
if(blkStart < 0){
for(int b=swBar+1; b<iBars(_Symbol,_Period) && b<=swBar+maxL; b++){
double o=iOpen(_Symbol,_Period,b), c=iClose(_Symbol,_Period,b);
bool isDef=(isBear)?(c>o):(c<o);
if(isDef){ if(blkStart < 0){ blkStart=b; blkEnd=b; } else blkStart=b; } else break; } } }
if(blkStart < 0) return;
keyLvl = iOpen(_Symbol,_Period,blkStart); startTm = iTime(_Symbol,_Period,blkStart); }
// ------------------- BREAKOUT SCAN (BACKWARDS) -------------------
int brkBar = -1; double brkClose = 0; datetime brkTm = 0;
for(int b = swBar - 1; b >= 0; b--){
datetime ct = iTime(_Symbol,_Period,b); if(ct < swT) break; if(ct > cut) continue;
double o = iOpen(_Symbol,_Period,b); double c = iClose(_Symbol,_Period,b);
bool breakout = false; if(isBear){ if(o < keyLvl || c < keyLvl) breakout = true; } else{ if(o > keyLvl || c > keyLvl) breakout = true; }
if(breakout){ brkBar = b; brkClose = c; brkTm = ct; break; } }
// ------------------- FORWARD SCAN -------------------
bool forwardFound = false;
if(brkBar < 0){
int lastDefBar = iBarShift(_Symbol,_Period,startTm);
if(lastDefBar >= 0){
int firstDefBar = lastDefBar;
for(int b = lastDefBar - 1; b >= 0; b--){
datetime ct = iTime(_Symbol,_Period,b); if(ct < swT) break;
double o = iOpen(_Symbol,_Period,b); double c = iClose(_Symbol,_Period,b);
bool isDef = (isBear) ? (c > o) : (c < o);
if(isDef) firstDefBar = b; else break; }
datetime firstDefTime = iTime(_Symbol,_Period,firstDefBar); double firstDefOpen = iOpen(_Symbol,_Period,firstDefBar);
for(int b = lastDefBar + 1; b < iBars(_Symbol,_Period) && b <= lastDefBar + maxL; b++){
datetime ct = iTime(_Symbol,_Period,b); if(ct < swT) continue; if(ct > cut) break;
double o = iOpen(_Symbol,_Period,b); double c = iClose(_Symbol,_Period,b);
bool breakout = false; if(isBear){ if(o < firstDefOpen || c < firstDefOpen) breakout = true; } else{ if(o > firstDefOpen || c > firstDefOpen) breakout = true; }
if(breakout){ brkBar = b; brkClose = c; brkTm = ct; keyLvl = firstDefOpen; startTm = firstDefTime; forwardFound = true; break; } } }
if(brkBar < 0) return; }
// ---------- Common drawing ----------
datetime endTm = brkTm + PeriodSeconds(_Period); string ln = pfx+htfStr+"_"+(isBear?"BEAR_":"BULL_")+IntegerToString(brkBar); if(StringLen(ln)>63) ln=StringSubstr(ln,0,63);
bool needRedraw = true; if(ObjectFind(0,ln)>=0){ double existingLevel = ObjectGetDouble(0, ln, OBJPROP_PRICE, 0); if(MathAbs(existingLevel-keyLvl)<=_Point) needRedraw=false; }
if(needRedraw){ if(ObjectFind(0,ln)>=0) ObjectDelete(0,ln); ObjectCreate(0,ln,OBJ_TREND,0,startTm,keyLvl,endTm,keyLvl); color clr=isBear?CISD_BearishColor:CISD_BullishColor; ObjectSetInteger(0,ln,OBJPROP_COLOR,clr); ObjectSetInteger(0,ln,OBJPROP_WIDTH,CISD_LineWidth); ObjectSetInteger(0,ln,OBJPROP_STYLE,CISD_LineStyle); ObjectSetInteger(0,ln,OBJPROP_RAY,false); ObjectSetInteger(0,ln,OBJPROP_BACK,true); ObjectSetInteger(0,ln,OBJPROP_SELECTABLE,false); string dir=isBear?"BEARISH":"BULLISH"; string extra = forwardFound ? " (post-sweep)" : ""; string tip = StringFormat("%s CISD [%s→%s]%s\nC1 %s: %.*f @ %s\nLevel: %.*f\nBroken: %.*f @ %s",dir,htfStr,TimeframeToString(_Period),extra,isBear?"HIGH":"LOW",dgt,swP,TimeToString(swT-PeriodSeconds(htf),TIME_MINUTES),dgt,keyLvl,dgt,brkClose,TimeToString(brkTm,TIME_MINUTES)); ObjectSetString(0,ln,OBJPROP_TOOLTIP,tip); }
// ------------------- LOCK & STORE -------------------
if(isH1){ lastCISD_SweepTime_HTF1=swT; lastCISD_KeyLevel_HTF1=keyLvl; lastCISD_StartTime_HTF1=startTm; lastCISD_Locked_HTF1=true; lastCISD_IsBullish_HTF1=!isBear; lastCISD_Start_HTF1=startTm; lastCISD_End_HTF1=endTm; lastCISD_Level_HTF1=keyLvl; lastCISD_Valid_HTF1=true; }
if(isH2){ lastCISD_SweepTime_HTF2=swT; lastCISD_KeyLevel_HTF2=keyLvl; lastCISD_StartTime_HTF2=startTm; lastCISD_Locked_HTF2=true; lastCISD_IsBullish_HTF2=!isBear; }
if(isH1) AlertCISD(!isBear,htf,keyLvl,brkTm,"HTF1"); }