# ============================================================ # MIZAN presents: For the Record — swing leg counter — thinkScript · v2.0 # mizanquant.com/free · free & open source · a QWERTY Options Inc. tool # # WHAT IT DOES # A bar-by-bar swing state machine. Trend flips on a higher high or a # lower low; every completed leg gets entered into the record as a # numbered bubble at the turn. Higher lows keep counting the up-legs, # lower highs keep counting the down-legs, and when a leg fails to # extend past the prior pivot, the bubble turns magenta: objection, # sustained. 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. PORTABILITY FIX: the failed-break test compared against a # hardcoded 1, which is one POINT, so the same setting meant four # ticks on ES and something entirely different everywhere else. # Now an input in ticks (failTicks = 4 preserves the original ES # behavior exactly). # 2. Bubble offsets are inputs instead of hardcoded 5 and 2 ticks. # 3. The commented-out arrows are a real toggle now (default off, so # the bubble-only look is unchanged). # 4. Alerts added: new leg up, new leg down, and failed-break turns. # 5. Status label added: current trend plus both leg counts. # 6. Hidden scan exports: leg counts and failure flags. # 7. Sentinel values (-1 / 999999) kept from the original because the # trueLow/trueHi math leans on them; now documented instead of # mysterious. # 8. Case-insensitive identifier audit passed; zero collisions, # zero unused inputs. # ============================================================ declare upper; # ----- INPUTS ----- input failTicks = 4; # failed-break tolerance, in ticks (4 = one ES point, the original behavior) input bubbleOffsetAboveTicks = 2; input bubbleOffsetBelowTicks = 5; input showBubbles = yes; input showArrows = no; input showStatusLabel = yes; def tick = TickSize(); def failSpan = failTicks * tick; # ----- SWING STATE MACHINE (owner's logic, verbatim semantics) ----- def trend = {default init, neutral, up, down}; switch (trend[1]) { case init: trend = trend.neutral; case neutral: if (high > high[1]) { trend = trend.up; } else if (low < low[1]) { trend = trend.down; } else { trend = trend.neutral; } case up: if (low < low[1]) { trend = trend.down; } else { trend = trend[1]; } case down: if (high > high[1]) { trend = trend.up; } else { trend = trend[1]; } } # sentinel values are load-bearing: -1 keeps Max() honest, 999999 keeps Min() honest def currentHigh; if trend == trend.up { if high > currentHigh[1] { currentHigh = high; } else { currentHigh = currentHigh[1]; } } else { currentHigh = -1; } def currentLow; if trend == trend.down { if low < currentLow[1] { currentLow = low; } else { currentLow = currentLow[1]; } } else { currentLow = 999999; } def trueLow = Min(currentLow[1], low); def trueHi = Max(currentHigh[1], high); # ----- LEG COUNTING AT THE TURNS ----- plot UpTurn; def countLegUp; def previousLow; def pivotLowHi; if trend == trend.up and trend[1] == trend.down { if previousLow[1] > trueLow { countLegUp = 1; } else { countLegUp = countLegUp[1] + 1; } previousLow = trueLow; UpTurn = low - (2 * tick); pivotLowHi = high[1]; } else { previousLow = previousLow[1]; countLegUp = countLegUp[1]; UpTurn = Double.NaN; pivotLowHi = pivotLowHi[1]; } plot DownTurn; def countLegDown; def previousHigh; def pivotHiLow; if trend == trend.down and trend[1] == trend.up { if previousHigh[1] < Max(currentHigh[1], high) { countLegDown = 1; } else { countLegDown = countLegDown[1] + 1; } previousHigh = Max(currentHigh[1], high); DownTurn = high + (2 * tick); pivotHiLow = low[1]; } else { previousHigh = previousHigh[1]; countLegDown = countLegDown[1]; pivotHiLow = pivotHiLow[1]; DownTurn = Double.NaN; } # ----- FAILED BREAKS: objection, sustained ----- def failedShort; if pivotHiLow - trueLow <= failSpan { failedShort = 1; } else { failedShort = 0; } def failedLong; if trueHi - pivotLowHi <= failSpan { failedLong = 1; } else { failedLong = 0; } # ----- THE RECORD ----- AddChartBubble(showBubbles and !IsNaN(DownTurn), high + bubbleOffsetAboveTicks * tick, countLegDown, if countLegDown[1] > 1 and failedLong then Color.MAGENTA else if countLegUp > 1 then Color.DARK_RED else if countLegDown > 1 then Color.LIGHT_RED else Color.GRAY); AddChartBubble(showBubbles and !IsNaN(UpTurn), low - bubbleOffsetBelowTicks * tick, countLegUp, if countLegUp[1] > 1 and failedShort then Color.MAGENTA else if countLegDown > 1 then Color.DARK_GREEN else if countLegUp > 1 then Color.LIGHT_GREEN else Color.GRAY); UpTurn.SetPaintingStrategy(PaintingStrategy.ARROW_UP); UpTurn.SetDefaultColor(Color.GREEN); UpTurn.SetLineWeight(2); UpTurn.SetHiding(!showArrows); DownTurn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN); DownTurn.SetDefaultColor(Color.RED); DownTurn.SetLineWeight(2); DownTurn.SetHiding(!showArrows); # ----- STATUS ----- AddLabel(showStatusLabel, (if trend == trend.up then "SWING UP" else if trend == trend.down then "SWING DOWN" else "NEUTRAL") + " | legs up " + countLegUp + " | legs down " + countLegDown, if trend == trend.up then Color.GREEN else if trend == trend.down then Color.RED else Color.GRAY); # ----- ALERTS ----- Alert(!IsNaN(UpTurn), "For the Record: new up-leg, count " + countLegUp, Alert.BAR, Sound.Chimes); Alert(!IsNaN(DownTurn), "For the Record: new down-leg, count " + countLegDown, Alert.BAR, Sound.Bell); Alert(!IsNaN(UpTurn) and countLegUp[1] > 1 and failedShort, "For the Record: failed short, objection sustained", Alert.BAR, Sound.Ring); Alert(!IsNaN(DownTurn) and countLegDown[1] > 1 and failedLong, "For the Record: failed long, objection sustained", Alert.BAR, Sound.Ring); # ----- SCAN EXPORTS ----- plot ScanLegUp = countLegUp; ScanLegUp.Hide(); plot ScanLegDown = countLegDown; ScanLegDown.Hide(); plot ScanFailedLong = failedLong; ScanFailedLong.Hide(); plot ScanFailedShort = failedShort; ScanFailedShort.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