//
@version
=5
indicator("BTC Indicator v5 - Macro Momentum & Contrarian Learning", shorttitle="BTC MacroLearn v5", overlay=false, precision=3, max_bars_back=2000)
// ══════════════════════════════════════════════════════════════════
// INPUTS
// ══════════════════════════════════════════════════════════════════
grp1 = "── Macro Anchors ──"
wRsiLen =
input.int(14, "Weekly RSI Period", group=grp1)
wRsiOB = input.float(68.0, "Weekly RSI Contrarian Bear (Overbought)", group=grp1)
wRsiOS = input.float(32.0, "Weekly RSI Contrarian Bull (Oversold)", group=grp1)
grp2 = "── Advanced Learning Engine ──"
learnWindow =
input.int(300, "Learning Window (bars)", minval=50, maxval=1000, group=grp2)
outcomeDelay =
input.int(15, "Outcome Delay (bars forward)", minval=3, maxval=30, group=grp2)
minSamples =
input.int(15, "Min Samples Before Learning", minval=5, maxval=50, group=grp2)
minLongCon = input.float(0.68,"Min Long Confidence (Filter Noise)", minval=0.50, maxval=0.95, step=0.01, group=grp2)
minShortCon = input.float(0.70,"Min Short Confidence (Filter Noise)",minval=0.50, maxval=0.95, step=0.01, group=grp2)
cooldown =
input.int(40, "Cooldown Bars After Signal", minval=5, maxval=100, group=grp2)
grp4 = "── Mock Strategy Risk Management ──"
atrPeriod =
input.int(14, "ATR Period for Stops", group=grp4)
stopLossMult = input.float(2.5, "Stop Loss ATR Multiplier", group=grp4)
takeProfitMult=input.float(4.0, "Take Profit ATR Multiplier", group=grp4)
// ══════════════════════════════════════════════════════════════════
// DATA RECOVERY & TIME CONSTRAINTS
// ══════════════════════════════════════════════════════════════════
yield5 =
request.security("TVC:US05Y", timeframe.period, close)
yield10 =
request.security("TVC:US10Y", timeframe.period, close)
yield30 =
request.security("TVC:US30Y", timeframe.period, close)
btc =
request.security("BITSTAMP:BTCUSD", timeframe.period, close)
dxy =
request.security("TVC:DXY", timeframe.period, close)
// Force data lookback assignments for safety on execution
max_bars_back(btc, 2000)
// Fetching Weekly Asset Momentum Anchor (Forcing barmerge.lookahead_off to eliminate backtesting repainting)
weeklyRsi =
request.security("BITSTAMP:BTCUSD", "1W", ta.rsi(close, wRsiLen), barmerge.gaps_off, barmerge.lookahead_off)
btcATR = ta.atr(atrPeriod)
atrPct = btcATR / btc
// ══════════════════════════════════════════════════════════════════
// RE-CONFIGURED SELECTIVE REGIME SIGNALS
// ══════════════════════════════════════════════════════════════════
// --- Anchor 1: Weekly RSI Components ---
weeklyBullTrend = weeklyRsi > 50.0
weeklyBearTrend = weeklyRsi < 50.0
weeklyOversold = weeklyRsi < wRsiOS
weeklyOverbought= weeklyRsi > wRsiOB
// --- Style A: Momentum & Trend Following ---
bEmaF = ta.ema(btc, 13), bEmaS = ta.ema(btc, 55)
btcROC = (btc - btc[20]) / btc[20] * 100
sig9Bull = bEmaF > bEmaS and weeklyBullTrend
sig9Bear = bEmaF < bEmaS and weeklyBearTrend
sig10Bull = btcROC > 2.0 and btcROC < 15.0 and weeklyBullTrend
sig10Bear = btcROC < -4.0 and weeklyBearTrend
// --- Style B: Macro Intermarket Contrarian Drivers ---
r5 = ta.rsi(yield5, 14), r10 = ta.rsi(yield10, 14), r30 = ta.rsi(yield30, 14)
aRSI = (r5 r10 r30) / 3
sig3Bull = aRSI < 30 and (weeklyBullTrend or weeklyOversold)
sig3Bear = aRSI > 70 and (weeklyBearTrend or weeklyOverbought)
e5f = ta.ema(yield5, 8), e5s = ta.ema(yield5, 21)
e10f = ta.ema(yield10, 8), e10s = ta.ema(yield10, 21)
emaBullN = (e5f < e5s ? 1 : 0) (e10f < e10s ? 1 : 0)
emaBearN = (e5f > e5s ? 1 : 0) (e10f > e10s ? 1 : 0)
sig1Bull = emaBullN == 2 and weeklyOversold
sig1Bear = emaBearN == 2 and weeklyOverbought
dxyEmaF = ta.ema(dxy, 8), dxyEmaS = ta.ema(dxy, 21)
sig11Bull = dxyEmaF < dxyEmaS and weeklyOversold
sig11Bear = dxyEmaF > dxyEmaS and weeklyOverbought
// ══════════════════════════════════════════════════════════════════
// ADVANCED ADAPTIVE LEARNING CORRECTIONS
// ══════════════════════════════════════════════════════════════════
f_learn_improved(sigBull, sigBear, fwd, win, targetPct) =>
var float bHits = 0.0, var float bTot = 0.0
var float sHits = 0.0, var float sTot = 0.0
lowest_fwd = ta.lowest(btc, 30)
highest_fwd = ta.highest(btc, 30)
if bar_index >= (fwd win 5)
btcReturn = (btc - btc[fwd]) / btc[fwd]
btcMaxDrawdown = (lowest_fwd - btc[fwd]) / btc[fwd]
btcMaxRunup = (highest_fwd - btc[fwd]) / btc[fwd]
longWin = btcReturn >= targetPct[fwd] and btcMaxDrawdown > -targetPct[fwd] * 1.3
shortWin = btcReturn <= -targetPct[fwd] and btcMaxRunup < targetPct[fwd] * 1.3
if sigBull[fwd]
bTot = 1.0
if longWin
bHits = 1.0
if sigBear[fwd]
sTot = 1.0
if shortWin
sHits = 1.0
bReturnOld = (btc[win] - btc[fwd win]) / btc[fwd win]
bLowOld = (lowest_fwd[win] - btc[fwd win]) / btc[fwd win]
bHighOld = (highest_fwd[win] - btc[fwd win]) / btc[fwd win]
longWinOld = bReturnOld >= targetPct[fwd win] and bLowOld > -targetPct[fwd win] * 1.3
shortWinOld = bReturnOld <= -targetPct[fwd win] and bHighOld < targetPct[fwd win] * 1.3
if sigBull[fwd win]
bTot -= 1.0
if longWinOld
bHits -= 1.0
if sigBear[fwd win]
sTot -= 1.0
if shortWinOld
sHits -= 1.0
bAcc = bTot >= minSamples ? bHits / bTot : float(na)
sAcc = sTot >= minSamples ? sHits / sTot : float(na)
[bAcc, sAcc]
dynamicTarget = ta.sma(atrPct, 20) * math.sqrt(outcomeDelay) * 1.3
[a1b, a1s] = f_learn_improved(sig1Bull, sig1Bear, outcomeDelay, learnWindow, dynamicTarget)
[a3b, a3s] = f_learn_improved(sig3Bull, sig3Bear, outcomeDelay, learnWindow, dynamicTarget)
[a9b, a9s] = f_learn_improved(sig9Bull, sig9Bear, outcomeDelay, learnWindow, dynamicTarget)
[a10b, a10s] = f_learn_improved(sig10Bull, sig10Bear, outcomeDelay, learnWindow, dynamicTarget)
[a11b, a11s] = f_learn_improved(sig11Bull, sig11Bear, outcomeDelay, learnWindow, dynamicTarget)
f_wt_exponential(acc) =>
na(acc) ? 0.25 : math.pow(math.max(0.0, (acc - 0.42) / 0.58), 1.8)
w1b = f_wt_exponential(a1b), w1s = f_wt_exponential(a1s)
w3b = f_wt_exponential(a3b), w3s = f_wt_exponential(a3s)
w9b = f_wt_exponential(a9b), w9s = f_wt_exponential(a9s)
w10b = f_wt_exponential(a10b), w10s = f_wt_exponential(a10s)
w11b = f_wt_exponential(a11b), w11s = f_wt_exponential(a11s)
// ══════════════════════════════════════════════════════════════════
// CONFIDENCE MATRICES WITH FIXED EXTRA 50% WEEKLY RSI ANCHOR WEIGHT
// ══════════════════════════════════════════════════════════════════
secondarySumLong = w1b w3b w9b w10b w11b 0.0001
secondarySumShort = w1s w3s w9s w10s w11s 0.0001
rawSecondaryLong = (sig1Bull ? w1b : 0.0) (sig3Bull ? w3b : 0.0) (sig9Bull ? w9b : 0.0) (sig10Bull ? w10b : 0.0) (sig11Bull ? w11b : 0.0)
rawSecondaryShort = (sig1Bear ? w1s : 0.0) (sig3Bear ? w3s : 0.0) (sig9Bear ? w9s : 0.0) (sig10Bear ? w10s : 0.0) (sig11Bear ? w11s : 0.0)
// Standardize alternative indicators to scale from 0.0 up to 0.50 max
subScoreLong = (rawSecondaryLong / secondarySumLong) * 0.50
subScoreShort = (rawSecondaryShort / secondarySumShort) * 0.50
// Apply direct strict 50% allocations exclusively to the Weekly RSI Engine conditions
rsiWeightLong = weeklyBullTrend or weeklyOversold ? 0.50 : 0.0
rsiWeightShort = weeklyBearTrend or weeklyOverbought ? 0.50 : 0.0
longConfidence = rsiWeightLong subScoreLong
shortConfidence = rsiWeightShort subScoreShort
// ══════════════════════════════════════════════════════════════════
// INDICATOR TRADING EMULATION (MOCK BACKTESTER)
// ══════════════════════════════════════════════════════════════════
var int pos = 0
var int barsSinceSig = 999
var float mockEntry = na
var float mockStop = na
var float mockTarget = na
var int totalTrades = 0
var int winTrades = 0
var float totalPips = 0.0
barsSinceSig = 1
candidateLong = longConfidence >= minLongCon and barsSinceSig >= cooldown and pos == 0
candidateShort = shortConfidence >= minShortCon and barsSinceSig >= cooldown and pos == 0
if pos == 1
if low <= mockStop
totalTrades = 1
totalPips = (mockStop - mockEntry) / mockEntry
pos := 0
barsSinceSig := 0
else if high >= mockTarget
totalTrades = 1
winTrades = 1
totalPips = (mockTarget - mockEntry) / mockEntry
pos := 0
barsSinceSig := 0
if pos == -1
if high >= mockStop
totalTrades = 1
totalPips = (mockEntry - mockStop) / mockEntry
pos := 0
barsSinceSig := 0
else if low <= mockTarget
totalTrades = 1
winTrades = 1
totalPips = (mockEntry - mockTarget) / mockEntry
pos := 0
barsSinceSig := 0
longSignal = candidateLong and pos == 0
shortSignal = candidateShort and pos == 0
if longSignal
pos := 1
mockEntry := btc
mockStop := btc - (btcATR * stopLossMult)
mockTarget := btc (btcATR * takeProfitMult)
barsSinceSig := 0
if shortSignal
pos := -1
mockEntry := btc
mockStop := btc (btcATR * stopLossMult)
mockTarget := btc - (btcATR * takeProfitMult)
barsSinceSig := 0
winRate = totalTrades > 0 ? float(winTrades) / float(totalTrades) * 100.0 : float(na)
netReturn = totalPips * 100.0
// ══════════════════════════════════════════════════════════════════
// PLOTS
// ══════════════════════════════════════════════════════════════════
plot(weeklyRsi, title="Weekly BTC RSI Anchor", color=
color.orange, linewidth=2)
hline(50, "Trend Threshold", color=color.gray, linestyle=
hline.style_dotted)
hline(wRsiOB, "Macro Overbought", color=
color.red, linestyle=
hline.style_dashed)
hline(wRsiOS, "Macro Oversold", color=
color.green, linestyle=
hline.style_dashed)
bgcolor(pos == 1 ?
color.new(color.teal, 93) : pos == -1 ?
color.new(color.purple, 93) : na)
plotshape(longSignal, title="LONG", location=
location.top, color=color.lime, style=shape.labelup, text="LONG", textcolor=
color.black, size=size.large)
plotshape(shortSignal, title="SHORT", location=location.bottom, color=
color.red, style=shape.labeldown, text="SHORT", textcolor=color.white, size=size.large)
// ══════════════════════════════════════════════════════════════════
// RENDER FULL METRIC LIVE DISPLAY
// ══════════════════════════════════════════════════════════════════
var table tb =
table.new(
position.top_right, 3, 16,
bgcolor=
color.new(
color.black, 15),
border_color=
color.new(color.gray, 60), border_width=1,
frame_color=
color.new(color.white, 60), frame_width=1)
// Helper row logic updates (Corrected Version 5 Syntax Structure)
f_map(table targetTable, int r, string l, float b, float s) =>
bS = na(b) ? "–" : str.tostring(b * 100, "#.#") "%"
sS = na(s) ? "–" : str.tostring(s * 100, "#.#") "%"
table.cell(targetTable, 0, r, l, text_color=color.white, text_size=size.tiny)
table.cell(targetTable, 1, r, bS, text_color=na(b) ? color.gray : b >= 0.6 ? color.lime : b >= 0.5 ? color.yellow :
color.red, text_size=size.tiny)
table.cell(targetTable, 2, r, sS, text_color=na(s) ? color.gray : s >= 0.6 ? color.lime : s >= 0.5 ? color.yellow :
color.red, text_size=size.tiny)
if barstate.islast
table.cell(tb, 0, 0, "Macro Engine v5", text_color=color.white, text_size=size.small, bgcolor=
color.new(
color.navy, 30))
table.cell(tb, 1, 0, "Long Learning", text_color=color.lime, text_size=size.small, bgcolor=
color.new(
color.navy, 30))
table.cell(tb, 2, 0, "Short Learning", text_color=
color.red, text_size=size.small, bgcolor=
color.new(
color.navy, 30))
// Direct structural feedback mapping for the anchor row
table.cell(tb, 0, 1, "Weekly RSI Anchor", text_color=
color.orange, text_size=size.tiny)
table.cell(tb, 1, 1, "50% FIXED WT", text_color=
color.orange, text_size=size.tiny)
table.cell(tb, 2, 1, "50% FIXED WT", text_color=
color.orange, text_size=size.tiny)
// Execute table maps
f_map(tb, 2, "Yield EMA (Contra)", a1b, a1s)
f_map(tb, 3, "Avg RSI (Contra)", a3b, a3s)
f_map(tb, 4, "BTC EMA (Momentum)", a9b, a9s)
f_map(tb, 5, "BTC ROC (Momentum)", a10b, a10s)
f_map(tb, 6, "DXY Cross (Contra)", a11b, a11s)
// Metrics tracking
table.cell(tb, 0, 8, "Total Confidence", text_color=color.white, text_size=size.small)
table.cell(tb, 1, 8, str.tostring(longConfidence * 100, "#.#") "%", text_color=longConfidence >= minLongCon ? color.lime : color.gray, text_size=size.small)
table.cell(tb, 2, 8, str.tostring(shortConfidence * 100, "#.#") "%", text_color=shortConfidence >= minShortCon ?
color.red : color.gray, text_size=size.small)
table.cell(tb, 0, 9, "Position State", text_color=color.white, text_size=size.small)
table.cell(tb, 1, 9, pos == 1 ? "LONG" : pos == -1 ? "SHORT" : "FLAT", text_color=pos==1?color.lime : pos==-1?
color.red : color.yellow, text_size=size.small)
table.cell(tb, 2, 9, str.tostring(math.max(0, cooldown - barsSinceSig)) " bars cool", text_color=
color.orange, text_size=size.small)
table.cell(tb, 0, 11, "── Backtester ──", text_color=
color.orange, text_size=size.small)
table.cell(tb, 1, 11, "Trades: " str.tostring(totalTrades), text_color=color.white, text_size=size.small)
table.cell(tb, 2, 11, "Win %: " (na(winRate) ? "–" : str.tostring(winRate, "#.#") "%"), text_color=color.white, text_size=size.small)
table.cell(tb, 0, 12, "Net Return", text_color=color.white, text_size=size.small)
table.cell(tb, 1, 12, str.tostring(netReturn, "#.#") "%", text_color=netReturn >= 0.0 ? color.lime :
color.red, text_size=size.small)
table.cell(tb, 2, 12, "", text_size=size.small)