diff --git a/Bullmania_Money_Line.pine b/Bullmania_Money_Line_v1.pine similarity index 100% rename from Bullmania_Money_Line.pine rename to Bullmania_Money_Line_v1.pine diff --git a/Bullmania_Money_Line_v2.pine b/Bullmania_Money_Line_v2.pine new file mode 100644 index 0000000..546d26a --- /dev/null +++ b/Bullmania_Money_Line_v2.pine @@ -0,0 +1,115 @@ +//@version=5 +strategy("Bullmania Money Line v2", overlay=true, + initial_capital=10000, currency=currency.USD, pyramiding=0, + commission_type=strategy.commission.percent, commission_value=0.1, // 0.1% commission + slippage=1, process_orders_on_close=true) + +// Inputs +atrPeriod = input.int(10, "ATR Period", minval=1) +multiplier = input.float(3.0, "Multiplier", minval=0.1, step=0.1) + +// Backtest toggles +enableLongs = input.bool(true, "Enable Longs") +enableShorts = input.bool(true, "Enable Shorts") + +// Date range filter +startYear = input.int(2020, "Start Year", minval=1970, maxval=2100) +startMonth = input.int(1, "Start Month", minval=1, maxval=12) +startDay = input.int(1, "Start Day", minval=1, maxval=31) +endYear = input.int(2100, "End Year", minval=1970, maxval=2100) +endMonth = input.int(12, "End Month", minval=1, maxval=12) +endDay = input.int(31, "End Day", minval=1, maxval=31) +startTime = timestamp(startYear, startMonth, startDay, 0, 0) +endTime = timestamp(endYear, endMonth, endDay, 23, 59) +inDateRange = time >= startTime and time <= endTime + +// Position sizing +riskMode = input.string("Percent of equity", "Sizing Mode", options=["Percent of equity", "Fixed contracts"]) +posSizePct = input.float(10.0, "Position Size % of Equity", minval=0.0, step=0.1) +fixedQty = input.float(1.0, "Fixed Contracts/Qty", minval=0.0, step=0.1) +allowFractional = input.bool(true, "Allow fractional quantity") +usePct = riskMode == "Percent of equity" + +calcQty(price) => + qtyCalc = usePct ? (strategy.equity * (posSizePct / 100.0)) / price : fixedQty + allowFractional ? qtyCalc : math.floor(qtyCalc) + +// Stops/Targets +useMoneyLineStop = input.bool(true, "Use Money Line as Stop") +tpAtrMult = input.float(0.0, "Take Profit ATR Multiplier (0 = Off)", minval=0.0, step=0.1) + +// Core calculations (same as v1) +atr = ta.atr(atrPeriod) +src = (high + low) / 2 + +up = src - (multiplier * atr) +dn = src + (multiplier * atr) + +var float up1 = na +var float dn1 = na + +up1 := nz(up1[1], up) +dn1 := nz(dn1[1], dn) + +up1 := close[1] > up1 ? math.max(up, up1) : up +dn1 := close[1] < dn1 ? math.min(dn, dn1) : dn + +var int trend = 1 +var float tsl = na + +tsl := nz(tsl[1], up1) + +if trend == 1 + tsl := math.max(up1, tsl) + trend := close < tsl ? -1 : 1 +else + tsl := math.min(dn1, tsl) + trend := close > tsl ? 1 : -1 + +supertrend = tsl + +// Plot the Money Line +upTrend = trend == 1 ? supertrend : na +downTrend = trend == -1 ? supertrend : na + +plot(upTrend, "Up Trend", color=color.new(color.green, 0), style=plot.style_linebr, linewidth=2) +plot(downTrend, "Down Trend", color=color.new(color.red, 0), style=plot.style_linebr, linewidth=2) + +// Signals +longSignal = trend == 1 and trend[1] == -1 +shortSignal = trend == -1 and trend[1] == 1 + +// Plot buy/sell signals +plotshape(longSignal, title="Buy Signal", location=location.belowbar, color=color.green, style=shape.circle, size=size.small) +plotshape(shortSignal, title="Sell Signal", location=location.abovebar, color=color.red, style=shape.circle, size=size.small) + +// Fill area between price and Money Line +fill(plot(close, display=display.none), plot(upTrend, display=display.none), color=color.new(color.green, 90)) +fill(plot(close, display=display.none), plot(downTrend, display=display.none), color=color.new(color.red, 90)) + +// Alerts +alertcondition(longSignal, title="Bullmania Long", message="Bullmania Money Line: Long signal") +alertcondition(shortSignal, title="Bullmania Short", message="Bullmania Money Line: Short signal") + +// Backtest entries +canLong = enableLongs and inDateRange +canShort = enableShorts and inDateRange + +// Issue entries on signal +if longSignal and canLong + strategy.entry(id="Long", direction=strategy.long, qty = calcQty(close)) + +if shortSignal and canShort + strategy.entry(id="Short", direction=strategy.short, qty = calcQty(close)) + +// Dynamic stops/targets via strategy.exit +longStop = useMoneyLineStop and trend == 1 ? supertrend : na +shortStop = useMoneyLineStop and trend == -1 ? supertrend : na + +// Optional ATR-based take profits referenced from average fill price +longTP = tpAtrMult > 0 and strategy.position_size > 0 ? strategy.position_avg_price + atr * tpAtrMult : na +shortTP = tpAtrMult > 0 and strategy.position_size < 0 ? strategy.position_avg_price - atr * tpAtrMult : na + +// Update exits every bar (works even when not in position) +strategy.exit("XL", from_entry="Long", stop=longStop, limit=longTP) +strategy.exit("XS", from_entry="Short", stop=shortStop, limit=shortTP) diff --git a/Bullmania_Money_Line_v4_plus.pine b/Bullmania_Money_Line_v4_plus.pine index 9d6b21d..a07b68a 100644 --- a/Bullmania_Money_Line_v4_plus.pine +++ b/Bullmania_Money_Line_v4_plus.pine @@ -54,9 +54,13 @@ showFlipLevelLine = input.bool(true, "Show Flip Level line") flipLineAutoColor = input.bool(true, "Flip line color by trend") flipLineCustomCol = input.color(color.new(color.silver, 0), "Flip line custom color") showFlipLevelValue = input.bool(true, "Show Flip Level value label") +flipLabelPosOpt = input.string("Flip bar", "Flip Level label position", options=["Current bar","Flip bar"], tooltip="Where to place the Flip Level value label. 'Flip bar' anchors the label to the candle where the last flip occurred so it moves with that candle when you pan the chart.") +extendLinesRight = input.bool(false, "Extend lines to right edge", tooltip="If enabled, flip and next-flip lines will extend to the right edge (HUD-style). Disable to keep them glued strictly to candles.") flipLineWidth = input.int(3, "Flip line width", minval=1, maxval=6) nextFlipLineWidth = input.int(2, "Next flip line width", minval=1, maxval=6) labelSizeOpt = input.string("small", "Value label size", options=["tiny","small","normal"]) +// Global label size derived from option (used by all labels) +lblSize = labelSizeOpt == "tiny" ? size.tiny : labelSizeOpt == "small" ? size.small : size.normal // Preview of the next flip thresholds showNextBullFlip = input.bool(true, "Show Next Bull Flip level") showNextBearFlip = input.bool(false, "Show Next Bear Flip level") @@ -359,20 +363,35 @@ downTrend = trend == -1 ? supertrend : na // Persistent Flip Level (holds value from last flip until next) var float flipLevel = na +var int flipBarIndex = na flipLevel := (flipUp or flipDn) ? supertrend : nz(flipLevel[1]) +flipBarIndex := (flipUp or flipDn) ? bar_index : nz(flipBarIndex[1]) flipLineColor = flipLineAutoColor ? (trend == 1 ? color.new(color.green, 0) : color.new(color.red, 0)) : flipLineCustomCol -plot(showFlipLevelLine ? flipLevel : na, title="Flip Level", color=flipLineColor, linewidth=flipLineWidth, style=plot.style_linebr, trackprice=true) +plot(showFlipLevelLine ? flipLevel : na, title="Flip Level", color=flipLineColor, linewidth=flipLineWidth, style=plot.style_linebr, trackprice=extendLinesRight) // Optional always-visible value label at current bar (high-contrast) var label flipValLbl = na if showFlipLevelValue and not na(flipLevel) - if not na(flipValLbl) - label.delete(flipValLbl) // High-contrast: black text on green (bull), white text on maroon (bear) flipLblBg = flipLineAutoColor ? (trend == 1 ? color.new(color.green, 0) : color.new(color.maroon, 0)) : flipLineCustomCol flipLblTxt = flipLineAutoColor ? (trend == 1 ? color.black : color.white) : color.white - lblSize = labelSizeOpt == "tiny" ? size.tiny : labelSizeOpt == "small" ? size.small : size.normal - flipValLbl := label.new(bar_index, flipLevel, text="Flip Level: " + str.tostring(flipLevel, format.mintick), style=label.style_label_left, color=flipLblBg, textcolor=flipLblTxt, yloc=yloc.price, size=lblSize) + // Determine x position based on user preference + flipLblX = flipLabelPosOpt == "Flip bar" and not na(flipBarIndex) ? flipBarIndex : bar_index + if na(flipValLbl) + flipValLbl := label.new(flipLblX, flipLevel, text="Flip Level: " + str.tostring(flipLevel, format.mintick), xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, color=flipLblBg, textcolor=flipLblTxt, size=lblSize) + else + label.set_x(flipValLbl, flipLblX) + label.set_y(flipValLbl, flipLevel) + label.set_text(flipValLbl, "Flip Level: " + str.tostring(flipLevel, format.mintick)) + label.set_color(flipValLbl, flipLblBg) + label.set_textcolor(flipValLbl, flipLblTxt) + label.set_style(flipValLbl, label.style_label_left) + label.set_size(flipValLbl, lblSize) + +else + if not na(flipValLbl) + label.delete(flipValLbl) + flipValLbl := na // Next flip preview levels (dynamic thresholds) nextBullLevel = tsl + aBufferATR * atr // price needed to start bull flip counting @@ -384,23 +403,54 @@ nextBearActive = trend == 1 nbCol = color.new(color.lime, 0) nsCol = color.new(color.red, 0) -plot(showNextBullFlip and nextBullActive ? nextBullLevel : na, title="Next Bull Flip Level", color=nbCol, linewidth=nextFlipLineWidth, style=plot.style_linebr, trackprice=true) -plot(showNextBearFlip and nextBearActive ? nextBearLevel : na, title="Next Bear Flip Level", color=nsCol, linewidth=nextFlipLineWidth, style=plot.style_linebr, trackprice=true) +plot(showNextBullFlip and nextBullActive ? nextBullLevel : na, title="Next Bull Flip Level", color=nbCol, linewidth=nextFlipLineWidth, style=plot.style_linebr, trackprice=extendLinesRight) +plot(showNextBearFlip and nextBearActive ? nextBearLevel : na, title="Next Bear Flip Level", color=nsCol, linewidth=nextFlipLineWidth, style=plot.style_linebr, trackprice=extendLinesRight) // Optional live value labels for next flip thresholds (high-contrast) var label nextBullLbl = na var label nextBearLbl = na if showNextFlipValue + // Next Bull label lifecycle if showNextBullFlip and nextBullActive and not na(nextBullLevel) + if na(nextBullLbl) + nextBullLbl := label.new(bar_index, nextBullLevel, text="Next Bull Flip: " + str.tostring(nextBullLevel, format.mintick) + (aConfirmBars > 1 ? " (" + str.tostring(aConfirmBars) + " closes)" : ""), xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, color=color.new(color.lime, 0), textcolor=color.black, size=lblSize) + else + label.set_x(nextBullLbl, bar_index) + label.set_y(nextBullLbl, nextBullLevel) + label.set_text(nextBullLbl, "Next Bull Flip: " + str.tostring(nextBullLevel, format.mintick) + (aConfirmBars > 1 ? " (" + str.tostring(aConfirmBars) + " closes)" : "")) + label.set_color(nextBullLbl, color.new(color.lime, 0)) + label.set_textcolor(nextBullLbl, color.black) + label.set_style(nextBullLbl, label.style_label_left) + label.set_size(nextBullLbl, lblSize) + + else if not na(nextBullLbl) label.delete(nextBullLbl) - // Bright lime background with black text for readability - nextBullLbl := label.new(bar_index, nextBullLevel, text="Next Bull Flip: " + str.tostring(nextBullLevel, format.mintick) + (aConfirmBars > 1 ? " (" + str.tostring(aConfirmBars) + " closes)" : ""), style=label.style_label_left, color=color.new(color.lime, 0), textcolor=color.black, yloc=yloc.price, size=lblSize) + nextBullLbl := na + // Next Bear label lifecycle if showNextBearFlip and nextBearActive and not na(nextBearLevel) + if na(nextBearLbl) + nextBearLbl := label.new(bar_index, nextBearLevel, text="Next Bear Flip: " + str.tostring(nextBearLevel, format.mintick) + (aConfirmBars > 1 ? " (" + str.tostring(aConfirmBars) + " closes)" : ""), xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left, color=color.new(color.maroon, 0), textcolor=color.white, size=lblSize) + else + label.set_x(nextBearLbl, bar_index) + label.set_y(nextBearLbl, nextBearLevel) + label.set_text(nextBearLbl, "Next Bear Flip: " + str.tostring(nextBearLevel, format.mintick) + (aConfirmBars > 1 ? " (" + str.tostring(aConfirmBars) + " closes)" : "")) + label.set_color(nextBearLbl, color.new(color.maroon, 0)) + label.set_textcolor(nextBearLbl, color.white) + label.set_style(nextBearLbl, label.style_label_left) + label.set_size(nextBearLbl, lblSize) + + else if not na(nextBearLbl) label.delete(nextBearLbl) - // Darker red background for contrast - nextBearLbl := label.new(bar_index, nextBearLevel, text="Next Bear Flip: " + str.tostring(nextBearLevel, format.mintick) + (aConfirmBars > 1 ? " (" + str.tostring(aConfirmBars) + " closes)" : ""), style=label.style_label_left, color=color.new(color.maroon, 0), textcolor=color.white, yloc=yloc.price, size=lblSize) + nextBearLbl := na +else + if not na(nextBullLbl) + label.delete(nextBullLbl) + nextBullLbl := na + if not na(nextBearLbl) + label.delete(nextBearLbl) + nextBearLbl := na plot(upTrend, "Up Trend", color=color.new(color.green, 0), style=plot.style_linebr, linewidth=2) plot(downTrend, "Down Trend", color=color.new(color.red, 0), style=plot.style_linebr, linewidth=2) diff --git a/Bullmania_Money_Line_v5.pine b/Bullmania_Money_Line_v5.pine new file mode 100644 index 0000000..b1c20c1 --- /dev/null +++ b/Bullmania_Money_Line_v5.pine @@ -0,0 +1,125 @@ +//@version=5 +indicator("Bullmania Money Line v5", overlay=true) + +// Parameter Mode +paramMode = input.string("Profiles by timeframe", "Parameter Mode", options=["Single", "Profiles by timeframe"], tooltip="Choose whether to use one global set of parameters or timeframe-specific profiles.") + +// Single (global) parameters +atrPeriodSingle = input.int(10, "ATR Period (Single mode)", minval=1, group="Single Mode") +multiplierSingle = input.float(3.0, "Multiplier (Single mode)", minval=0.1, step=0.1, group="Single Mode") + +// Profile override when using profiles +profileOverride = input.string("Auto", "Profile Override", options=["Auto", "Minutes", "Hours", "Daily", "Weekly/Monthly"], tooltip="When in 'Profiles by timeframe' mode, choose a fixed profile or let it auto-detect from the chart timeframe.", group="Profiles") + +// Timeframe profile parameters +// Minutes (<= 59m) +atr_m = input.int(12, "ATR Period (Minutes)", minval=1, group="Profiles — Minutes") +mult_m = input.float(3.3, "Multiplier (Minutes)", minval=0.1, step=0.1, group="Profiles — Minutes") + +// Hours (>=1h and <1d) +atr_h = input.int(10, "ATR Period (Hours)", minval=1, group="Profiles — Hours") +mult_h = input.float(3.0, "Multiplier (Hours)", minval=0.1, step=0.1, group="Profiles — Hours") + +// Daily (>=1d and <1w) +atr_d = input.int(10, "ATR Period (Daily)", minval=1, group="Profiles — Daily") +mult_d = input.float(2.8, "Multiplier (Daily)", minval=0.1, step=0.1, group="Profiles — Daily") + +// Weekly/Monthly (>=1w) +atr_w = input.int(7, "ATR Period (Weekly/Monthly)", minval=1, group="Profiles — Weekly/Monthly") +mult_w = input.float(2.5, "Multiplier (Weekly/Monthly)", minval=0.1, step=0.1, group="Profiles — Weekly/Monthly") + +// Optional MACD confirmation +useMacd = input.bool(false, "Use MACD confirmation", inline="macd") +macdSrc = input.source(close, "MACD Source", inline="macd") +macdFastLen = input.int(12, "Fast", minval=1, inline="macdLens") +macdSlowLen = input.int(26, "Slow", minval=1, inline="macdLens") +macdSigLen = input.int(9, "Signal", minval=1, inline="macdLens") + +// Determine effective parameters based on selected mode/profile +var string activeProfile = "" +resSec = timeframe.in_seconds(timeframe.period) +isMinutes = resSec < 3600 +isHours = resSec >= 3600 and resSec < 86400 +isDaily = resSec >= 86400 and resSec < 604800 +isWeeklyOrMore = resSec >= 604800 + +// Resolve profile bucket +string profileBucket = "Single" +if paramMode == "Single" + profileBucket := "Single" +else + if profileOverride == "Minutes" + profileBucket := "Minutes" + else if profileOverride == "Hours" + profileBucket := "Hours" + else if profileOverride == "Daily" + profileBucket := "Daily" + else if profileOverride == "Weekly/Monthly" + profileBucket := "Weekly/Monthly" + else + profileBucket := isMinutes ? "Minutes" : isHours ? "Hours" : isDaily ? "Daily" : "Weekly/Monthly" + +atrPeriod = profileBucket == "Single" ? atrPeriodSingle : profileBucket == "Minutes" ? atr_m : profileBucket == "Hours" ? atr_h : profileBucket == "Daily" ? atr_d : atr_w +multiplier = profileBucket == "Single" ? multiplierSingle : profileBucket == "Minutes" ? mult_m : profileBucket == "Hours" ? mult_h : profileBucket == "Daily" ? mult_d : mult_w +activeProfile := profileBucket + +// Core Money Line logic (unchanged from v1) +atr = ta.atr(atrPeriod) +src = (high + low) / 2 + +up = src - (multiplier * atr) +dn = src + (multiplier * atr) + +var float up1 = na +var float dn1 = na + +up1 := nz(up1[1], up) +dn1 := nz(dn1[1], dn) + +up1 := close[1] > up1 ? math.max(up, up1) : up +dn1 := close[1] < dn1 ? math.min(dn, dn1) : dn + +var int trend = 1 +var float tsl = na + +tsl := nz(tsl[1], up1) + +if trend == 1 + tsl := math.max(up1, tsl) + trend := close < tsl ? -1 : 1 +else + tsl := math.min(dn1, tsl) + trend := close > tsl ? 1 : -1 + +supertrend = tsl + +// Plot the Money Line +upTrend = trend == 1 ? supertrend : na +downTrend = trend == -1 ? supertrend : na + +plot(upTrend, "Up Trend", color=color.new(color.green, 0), style=plot.style_linebr, linewidth=2) +plot(downTrend, "Down Trend", color=color.new(color.red, 0), style=plot.style_linebr, linewidth=2) + +// Show active profile on chart as a label (once per bar close) +showProfileLabel = input.bool(true, "Show active profile label", group="Profiles") +var label profLbl = na +if barstate.islast and showProfileLabel + if not na(profLbl) + label.delete(profLbl) + profLbl := label.new(bar_index, close, text="Profile: " + activeProfile + " | ATR=" + str.tostring(atrPeriod) + " Mult=" + str.tostring(multiplier), yloc=yloc.price, style=label.style_label_upper_left, textcolor=color.white, color=color.new(color.blue, 20)) + +// MACD confirmation logic +[macdLine, macdSignal, macdHist] = ta.macd(macdSrc, macdFastLen, macdSlowLen, macdSigLen) +longOk = not useMacd or (macdLine > macdSignal) +shortOk = not useMacd or (macdLine < macdSignal) + +// Plot buy/sell signals (gated by optional MACD) +buyFlip = trend == 1 and trend[1] == -1 +sellFlip = trend == -1 and trend[1] == 1 + +plotshape(buyFlip and longOk, title="Buy Signal", location=location.belowbar, color=color.green, style=shape.circle, size=size.small) +plotshape(sellFlip and shortOk, title="Sell Signal", location=location.abovebar, color=color.red, style=shape.circle, size=size.small) + +// Fill area between price and Money Line +fill(plot(close, display=display.none), plot(upTrend, display=display.none), color=color.new(color.green, 90)) +fill(plot(close, display=display.none), plot(downTrend, display=display.none), color=color.new(color.red, 90)) diff --git a/README.md b/README.md index 33c1804..39e6a7f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,27 @@ # Bullmania Money Line +## Bullmania Money Line v2 (strategy) + +`Bullmania_Money_Line_v2.pine` is a TradingView Strategy version of the original indicator with built-in backtesting. + +- Convert the original Money Line into a strategy with entries on trend flips. +- Long/Short toggles and date range filter for backtests. +- Commission/slippage controls via strategy() header. +- Two sizing modes: Percent of equity (qty computed from equity and price) or fixed quantity. +- Optional Money Line-based stop and ATR-multiple take profit. + +How to use: +1. Open the file in TradingView Pine Editor and click Add to chart. +2. In the Inputs tab, set your ATR Period and Multiplier just like v1. +3. Set backtest range (Start/End date) and toggles (Enable Longs/Shorts). +4. Choose sizing mode: Percent of equity (qty_percent) or Fixed contracts (qty). +5. Optionally enable Money Line as Stop and ATR-based Take Profit. + +Notes: +- Entries occur on trend flips (when the Money Line switches from down to up for longs and vice versa for shorts). +- Exits are managed using `strategy.exit` with the Money Line as trailing stop when enabled. TP is optional. +- Default initial capital is 10,000 and commission is 0.1% with 1 tick slippage; adjust as needed. + ATR-based trend line and flip signals for TradingView (Pine v6). The indicator draws a “Money Line” that trails price and flips direction when price crosses it. Green dots mark bullish flips (trend turns up), red dots mark bearish flips (trend turns down). This repo contains multiple versions; v4 is the stable baseline and `v4+` adds optional filters, alerts, and per-timeframe profiles while preserving v4 defaults (off by default). @@ -10,6 +32,7 @@ This repo contains multiple versions; v4 is the stable baseline and `v4+` adds o - `Bullmania_Money_Line_v3.pine` — Historical variant. - `Bullmania_Money_Line_v4.pine` — v1 + optional noise reduction (confirmation bars, ATR buffer). Tagged `v4.0.0`. - `Bullmania_Money_Line_v4_plus.pine` — v4-compatible but with optional filters and quality-of-life features (Pine v6). +- `Bullmania_Money_Line_v5.pine` — v1 + optional MACD confirmation gate and optional timeframe profiles (Single mode or auto profile by chart TF). ## How it works (all versions) - Money Line is derived from a mid-price `(high + low) / 2` and `ATR(atrPeriod)` scaled by `multiplier`. @@ -154,10 +177,35 @@ Keep Multiplier roughly stable and fine-tune by small increments; HA candles all 5) Open Inputs to adjust parameters. ## Changelog +- v5 — v1 + optional MACD gate (buy dot requires MACD line > signal; sell dot requires MACD line < signal). Adds optional timeframe profiles: choose "Single" or "Profiles by timeframe". Profiles buckets: Minutes, Hours, Daily, Weekly/Monthly with independent ATR Period and Multiplier. Defaults keep v1 behavior. - v4+ — Pine v6 variant with optional ADX/MTF/session/cooldown, calc source toggle, EMA trend filter, anti-chop (CHOP, retest, min body), gated markers, and per-timeframe profiles. - v4.0.0 — Adds Flip confirmation bars and Flip buffer (×ATR). Defaults keep v1 behavior. Tag: `v4.0.0`. - v1 — Initial baseline. +## v5 timeframe profiles (quick guide) +In `Bullmania_Money_Line_v5.pine` you can switch "Parameter Mode" between: +- Single — one global ATR Period and Multiplier (same as v1 behavior). +- Profiles by timeframe — separate inputs per bucket with auto-selection from chart TF or via "Profile Override": + - Minutes (<= 59m) + - Hours (>= 1h and < 1d) + - Daily (>= 1d and < 1w) + - Weekly/Monthly (>= 1w) + +Inputs added in v5 when profiles are enabled: +- ATR Period (Minutes/Hours/Daily/Weekly-Monthly) +- Multiplier (Minutes/Hours/Daily/Weekly-Monthly) +- Profile Override: Auto, or force a specific bucket +- Optional: show active profile label on the chart + +Note: Only ATR Period and Multiplier are profiled in v5; filters remain limited to the optional MACD confirmation gate. + +### Default values (v5 profiles) +Out of the box defaults meant to be robust across popular markets; adjust per symbol/volatility: +- Minutes: ATR 12, Multiplier 3.3 +- Hours: ATR 10, Multiplier 3.0 +- Daily: ATR 10, Multiplier 2.8 +- Weekly/Monthly: ATR 7, Multiplier 2.5 + ## Notes - v4 is designed to reduce whips without changing the core Money Line logic. - Optional future add-ons (can be toggled if requested):