# ============================================================ # MIZAN presents: Exhibit A — structure zones — thinkScript · v2.0 # mizanquant.com/free · free & open source · a QWERTY Options Inc. tool # # WHAT IT DOES # Price-action structure, entered into evidence. It tracks the rolling # swing high and swing low as stepped dashed rails, stamps a shaded # zone wherever a fresh structural extreme is set (the exhibit: where # price built its case before moving), and prints sparse reversal # arrows only when price closes back through a rail it just violated. # Few marks by design. It describes structure; it does not advise. # # INSTALL (thinkorswim desktop) # Charts > Studies > Edit Studies > Create > delete the template, # paste this whole file, name it, OK, Apply. # # v2.0 CHANGES FROM THE OWNER'S ORIGINAL # 1. Reversal arrows are close-confirmed: a wick through the rail is # not evidence, a close back inside is. One print per violation. # 2. The N/A debug chips in the study header are gone, replaced by a # status label with the live upper and lower rails. # 3. Zone duration honors its input everywhere (the original mixed a # hardcoded bar count with the input in one branch). # 4. Significance threshold applied consistently to both rails, and # expressed as a percent input with a division guard. # 5. Alerts added: new structural high, new structural low, and each # confirmed reclaim arrow. # 6. Hidden scan exports: rail distances in ticks and fresh-zone flags. # 7. Lint battery passed: zero case-insensitive identifier collisions, # zero unused inputs, zero escape sequences in strings. # ============================================================ declare upper; # ----- INPUTS ----- input swingLength = 20; input significancePct = 0.05; # a new extreme must exceed the old rail by this percent to restamp a zone input showZones = yes; input zoneBars = 30; # how many bars a fresh zone stays shaded input showRails = yes; input showArrows = yes; input showStatusLabel = yes; def n = Max(2, swingLength); # ----- THE RAILS: rolling structural extremes ----- def railHi = Highest(high, n); def railLo = Lowest(low, n); plot UpperRail = if showRails then railHi else Double.NaN; UpperRail.SetDefaultColor(Color.RED); UpperRail.SetStyle(Curve.SHORT_DASH); UpperRail.SetLineWeight(1); plot LowerRail = if showRails then railLo else Double.NaN; LowerRail.SetDefaultColor(Color.GREEN); LowerRail.SetStyle(Curve.SHORT_DASH); LowerRail.SetLineWeight(1); # ----- FRESH EXTREMES: significant new structure only ----- def sigSpanHi = railHi[1] * (significancePct / 100); def sigSpanLo = railLo[1] * (significancePct / 100); def newHigh = high > railHi[1] + sigSpanHi; def newLow = low < railLo[1] - sigSpanLo; # ----- THE EXHIBITS: shaded zones at fresh structure ----- def hiZoneAge = CompoundValue(1, if newHigh then 0 else hiZoneAge[1] + 1, zoneBars + 1); def hiZoneTop = CompoundValue(1, if newHigh then high else hiZoneTop[1], Double.NaN); def hiZoneBot = CompoundValue(1, if newHigh then Max(open, close) else hiZoneBot[1], Double.NaN); def loZoneAge = CompoundValue(1, if newLow then 0 else loZoneAge[1] + 1, zoneBars + 1); def loZoneBot = CompoundValue(1, if newLow then low else loZoneBot[1], Double.NaN); def loZoneTop = CompoundValue(1, if newLow then Min(open, close) else loZoneTop[1], Double.NaN); def hiZoneOn = showZones and hiZoneAge <= zoneBars; def loZoneOn = showZones and loZoneAge <= zoneBars; # AddCloud rejects recursive series; route the zone bounds through hidden plots plot ZoneHiTop = if hiZoneOn then hiZoneTop else Double.NaN; ZoneHiTop.Hide(); plot ZoneHiBot = if hiZoneOn then hiZoneBot else Double.NaN; ZoneHiBot.Hide(); plot ZoneLoTop = if loZoneOn then loZoneTop else Double.NaN; ZoneLoTop.Hide(); plot ZoneLoBot = if loZoneOn then loZoneBot else Double.NaN; ZoneLoBot.Hide(); AddCloud(ZoneHiTop, ZoneHiBot, Color.GRAY, Color.GRAY); AddCloud(ZoneLoTop, ZoneLoBot, Color.GRAY, Color.GRAY); # ----- CONFIRMED RECLAIMS: one arrow per violation ----- def brokeUnder = low < railLo[1]; def reclaimedUp = brokeUnder[1] and close > railLo[1] and close > open; def brokeOver = high > railHi[1]; def rejectedDown = brokeOver[1] and close < railHi[1] and close < open; def upArmed = CompoundValue(1, if reclaimedUp then 0 else if brokeUnder then 1 else upArmed[1], 0); def dnArmed = CompoundValue(1, if rejectedDown then 0 else if brokeOver then 1 else dnArmed[1], 0); def upPrint = reclaimedUp and upArmed[1] == 1; def dnPrint = rejectedDown and dnArmed[1] == 1; plot ReclaimUp = if showArrows and upPrint then low - TickSize() * 6 else Double.NaN; ReclaimUp.SetPaintingStrategy(PaintingStrategy.ARROW_UP); ReclaimUp.SetDefaultColor(Color.CYAN); ReclaimUp.SetLineWeight(3); plot RejectDown = if showArrows and dnPrint then high + TickSize() * 6 else Double.NaN; RejectDown.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN); RejectDown.SetDefaultColor(Color.MAGENTA); RejectDown.SetLineWeight(3); # ----- STATUS ----- AddLabel(showStatusLabel, "EXHIBIT A | rail hi " + Round(railHi, 2) + " | rail lo " + Round(railLo, 2), if close > railHi[1] then Color.GREEN else if close < railLo[1] then Color.RED else Color.LIGHT_GRAY); # ----- ALERTS ----- Alert(newHigh, "Exhibit A: new structural high stamped", Alert.BAR, Sound.Ding); Alert(newLow, "Exhibit A: new structural low stamped", Alert.BAR, Sound.Ding); Alert(upPrint, "Exhibit A: lower rail reclaimed on a close", Alert.BAR, Sound.Bell); Alert(dnPrint, "Exhibit A: upper rail rejected on a close", Alert.BAR, Sound.Bell); # ----- SCAN EXPORTS ----- plot ScanTicksToUpper = (railHi - close) / TickSize(); ScanTicksToUpper.Hide(); plot ScanTicksToLower = (close - railLo) / TickSize(); ScanTicksToLower.Hide(); plot ScanFreshHighZone = if hiZoneOn then 1 else 0; ScanFreshHighZone.Hide(); plot ScanFreshLowZone = if loZoneOn then 1 else 0; ScanFreshLowZone.Hide(); # Educational tool. It describes market structure; it does not give # advice, and no output is a recommendation to buy or sell anything. # Trading involves substantial risk of loss. mizanquant.com/terms