# ============================================================ # MIZAN presents: Blended Math Genius Average — LITE · thinkScript · v1.0 # mizanquant.com/free · free & open source · a QWERTY Options Inc. tool # # WHAT IT IS # The Lite build. Same furniture as the full version: a blended # dual-kernel midline, a volatility envelope that breathes with the # tape, regime and flow labels, transition arrows, and band-touch # markers. The engine underneath is straightforward public math. # The full version's adaptive internals are the same family our paid # engine grew from, so those stay home. Generous, not reckless. # # Markers describe conditions on the tape; they do not advise. # # INSTALL (thinkorswim desktop) # Charts > Studies > Edit Studies > Create > delete the template, # paste this whole file, name it, OK, Apply. # # NOTES # - The screenshots on mizanquant.com/free were taken with the full # build; Lite draws the same read with simpler internals. # - Scan exports at the bottom are hidden plots for the Scan tab. # ============================================================ declare upper; # ----- INPUTS ----- input priceSource = hlc3; input fastLength = 14; input slowLength = 21; input atrLength = 14; input baseAtrMult = 2.0; input volAdapt = 0.5; input adxTrendLevel = 23; input volSpikeRatio = 1.35; input showBands = yes; input showMidline = yes; input showRegimeArrows = yes; input showTouchMarkers = yes; input showLabels = yes; def src = priceSource; # ----- BLENDED MIDLINE: two Hull lengths + one efficiency kernel ----- def hullFast = HullMovingAvg(src, fastLength); def hullSlow = HullMovingAvg(src, slowLength); def erChange = AbsValue(close - close[fastLength]); def erPath = Sum(AbsValue(close - close[1]), fastLength); def erVal = if erPath != 0 then erChange / erPath else 0; def fastSC = 2.0 / 3.0; def slowSC = 2.0 / 31.0; def smoothConst = Power(erVal * (fastSC - slowSC) + slowSC, 2); rec efKernel = if BarNumber() == 1 then src else efKernel[1] + smoothConst * (src - efKernel[1]); def blendMid = (hullFast + hullSlow + efKernel) / 3; # ----- BREATHING ENVELOPE: ATR width, volatility-adaptive ----- def atrVal = ATR(atrLength); def atrBase = Average(atrVal, 50); def atrRatio = if atrBase > 0 then atrVal / atrBase else 1.0; def bandMult = Max(1.5, Min(3.0, baseAtrMult + (atrRatio - 1.0) * volAdapt)); def upperVal = blendMid + atrVal * bandMult; def lowerVal = blendMid - atrVal * bandMult; # ----- REGIME: Wilder ADX + volatility spike ----- def dmiLen = 14; def trVal = TrueRange(high, close, low); def upMove = high - high[1]; def downMove = low[1] - low; def plusDM = if upMove > downMove and upMove > 0 then upMove else 0; def minusDM = if downMove > upMove and downMove > 0 then downMove else 0; def smPlusDM = WildersAverage(plusDM, dmiLen); def smMinusDM = WildersAverage(minusDM, dmiLen); def smTR = WildersAverage(trVal, dmiLen); def plusDI = 100 * smPlusDM / Max(smTR, 0.0001); def minusDI = 100 * smMinusDM / Max(smTR, 0.0001); def dx = 100 * AbsValue(plusDI - minusDI) / Max(plusDI + minusDI, 0.0001); def adxVal = WildersAverage(dx, dmiLen); def volSpike = atrRatio > volSpikeRatio; def trending = adxVal > adxTrendLevel and !volSpike; def ranging = !trending and !volSpike; # ----- FLOW: volume-weighted tick pressure ----- def volWeight = volume / Max(Average(volume, 20), 1); rec vwAccum = if BarNumber() == 1 then 0 else if close > close[1] then vwAccum[1] + volWeight else if close < close[1] then vwAccum[1] - volWeight else vwAccum[1]; def flowVal = vwAccum - vwAccum[20]; # ----- COMPOSITE READ (-100 to +100, generic ingredients) ----- def bandWidth = upperVal - lowerVal; def bandPos = if bandWidth > 0 then (close - lowerVal) / bandWidth else 0.5; def bandScore = if close > upperVal then -25 else if close < lowerVal then 25 else 0; def regimeScore = if trending and plusDI > minusDI then 20 else if trending and minusDI > plusDI then -20 else 0; def flowScore = Max(-40, Min(40, flowVal * 8)); def liteScore = Max(-100, Min(100, flowScore + bandScore + regimeScore)); # ----- PLOTS ----- plot MidLine = if showMidline then blendMid else Double.NaN; MidLine.SetDefaultColor(Color.WHITE); MidLine.SetLineWeight(2); plot UpperBand = if showBands then upperVal else Double.NaN; UpperBand.SetDefaultColor(Color.RED); UpperBand.SetLineWeight(1); plot LowerBand = if showBands then lowerVal else Double.NaN; LowerBand.SetDefaultColor(Color.GREEN); LowerBand.SetLineWeight(1); AddCloud(UpperBand, LowerBand, CreateColor(100, 100, 150), CreateColor(100, 100, 150)); # ----- REGIME TRANSITION ARROWS ----- def toTrend = trending and !trending[1]; def toVolatile = volSpike and !volSpike[1]; def toRange = ranging and !ranging[1]; plot TrendStartArrow = if showRegimeArrows and toTrend then low - atrVal * 0.8 else Double.NaN; TrendStartArrow.SetPaintingStrategy(PaintingStrategy.ARROW_UP); TrendStartArrow.SetDefaultColor(Color.GREEN); TrendStartArrow.SetLineWeight(2); plot VolatileStartArrow = if showRegimeArrows and toVolatile then high + atrVal * 0.8 else Double.NaN; VolatileStartArrow.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN); VolatileStartArrow.SetDefaultColor(Color.RED); VolatileStartArrow.SetLineWeight(2); plot RangeStartDot = if showRegimeArrows and toRange then blendMid else Double.NaN; RangeStartDot.SetPaintingStrategy(PaintingStrategy.POINTS); RangeStartDot.SetDefaultColor(Color.GRAY); RangeStartDot.SetLineWeight(3); # ----- BAND-TOUCH MARKERS (conditions, not advice) ----- def lowTouch = low <= lowerVal and flowVal > 0; def highTouch = high >= upperVal and flowVal < 0; plot LowTouchDot = if showTouchMarkers and lowTouch then low - atrVal * 0.2 else Double.NaN; LowTouchDot.SetPaintingStrategy(PaintingStrategy.POINTS); LowTouchDot.SetDefaultColor(Color.CYAN); LowTouchDot.SetLineWeight(3); plot HighTouchDot = if showTouchMarkers and highTouch then high + atrVal * 0.2 else Double.NaN; HighTouchDot.SetPaintingStrategy(PaintingStrategy.POINTS); HighTouchDot.SetDefaultColor(Color.MAGENTA); HighTouchDot.SetLineWeight(3); # ----- LABELS ----- AddLabel(showLabels, (if volSpike then "VOLATILE" else if trending then "TREND" else "RANGE") + " | Score:" + Round(liteScore, 0), if liteScore > 30 then Color.GREEN else if liteScore < -30 then Color.RED else Color.GRAY); AddLabel(showLabels, "Flow:" + Round(flowVal, 1), if flowVal > 3 then Color.GREEN else if flowVal < -3 then Color.RED else Color.GRAY); # ----- ALERTS ----- Alert(high >= upperVal, "Upper Band", Alert.BAR, Sound.Ding); Alert(low <= lowerVal, "Lower Band", Alert.BAR, Sound.Ding); Alert(lowTouch, "Lower touch with positive flow", Alert.BAR, Sound.Bell); Alert(highTouch, "Upper touch with negative flow", Alert.BAR, Sound.Bell); # ----- SCAN EXPORTS ----- plot ScanScore = liteScore; ScanScore.Hide(); plot ScanBandPct = bandPos * 100; ScanBandPct.Hide(); plot ScanTrend = if trending then 1 else 0; ScanTrend.Hide(); # Educational tool. It describes market conditions; 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