// ============================================================================
// BTC CYCLE ALPHA V3 — Anti-Chop Edition (LIVE SIGNALS)
// 2-DAY TIMEFRAME |
// ============================================================================
// LIVE MODE: Signals fire MID-CANDLE as soon as conditions are met.
// ⚠ WARNING: Signals may REPAINT — a green bar can appear and disappear
// before the candle closes. Use the alert system to catch signals in
// real-time, but be aware the signal is not confirmed until close.
// ============================================================================
//
@version=5
strategy(
"BTC Cycle Alpha V3 LIVE [2D]",
overlay = true,
initial_capital = 10000,
default_qty_type = strategy.percent_of_equity,
default_qty_value = 100,
commission_type = strategy.commission.percent,
commission_value = 0.1,
slippage = 2,
pyramiding = 0,
calc_on_every_tick = true,
process_orders_on_close = false)
// ──────────────────────────────────────────────────────────────────────────────
// INPUTS
// ──────────────────────────────────────────────────────────────────────────────
grp1 = "═══ Trend Factors ═══"
fastLen =
input.int(11, "Fast EMA", minval=3, group=grp1)
slowLen =
input.int(28, "Slow EMA", minval=5, group=grp1)
trendLen =
input.int(100, "Trend SMA", minval=25, group=grp1)
macdFast =
input.int(6, "MACD Fast", minval=2, group=grp1)
macdSlow =
input.int(13, "MACD Slow", minval=3, group=grp1)
macdSig =
input.int(5, "MACD Signal", minval=2, group=grp1)
grp2 = "═══ Anti-Chop Filters ═══"
adxLen =
input.int(14, "ADX Period", minval=5, group=grp2)
adxThresh =
input.int(20, "ADX Threshold", minval=10, group=grp2,
tooltip="Minimum ADX to allow entries. Higher = more selective, fewer trades in ranges.")
donchLen =
input.int(30, "Donchian Length", minval=10, group=grp2)
donchMult = input.float(0.98, "Donchian Mult", minval=0.90, maxval=1.0, step=0.01, group=grp2,
tooltip="Price must be within this % of the Donchian high to enter. 0.98 = within 2%.")
grp3 = "═══ Trade Management ═══"
entryTh =
input.int(2, "Entry Score (≥)", minval=1, maxval=3, group=grp3,
tooltip="Minimum bullish factors to ENTER (with ADX Donchian confirmation).")
exitTh =
input.int(0, "Exit Score (≤)", minval=0, maxval=2, group=grp3,
tooltip="Score at or below which the strategy EXITS. 0 = all factors must turn bearish.")
minHold =
input.int(10, "Min Hold (bars)", minval=0, group=grp3,
tooltip="Minimum bars to hold before exit is allowed. 10 bars = 20 days on 2D chart.")
cooldown =
input.int(8, "Cooldown (bars)", minval=0, group=grp3,
tooltip="Bars to wait after exit before re-entry. Prevents whipsaw in ranges. 8 bars = 16 days.")
grp4 = "═══ Visuals ═══"
showMAs = input.bool(true, "Show Moving Averages", group=grp4)
showBG = input.bool(true, "Show Background Color", group=grp4)
showADX = input.bool(false, "Show ADX Panel", group=grp4)
showTable = input.bool(true, "Show Performance Table", group=grp4)
// ──────────────────────────────────────────────────────────────────────────────
// FACTOR CALCULATIONS
// ──────────────────────────────────────────────────────────────────────────────
// Factor 1: Dual EMA Crossover
fastEMA = ta.ema(close, fastLen)
slowEMA = ta.ema(close, slowLen)
f1_bull = fastEMA > slowEMA
// Factor 2: Price above long-term trend
trendSMA = ta.sma(close, trendLen)
f2_bull = close > trendSMA
// Factor 3: MACD histogram positive
[macdLine, signalLine, histLine] = ta.macd(close, macdFast, macdSlow, macdSig)
f3_bull = histLine > 0
// Composite score (0–3)
score = (f1_bull ? 1 : 0) (f2_bull ? 1 : 0) (f3_bull ? 1 : 0)
// ──────────────────────────────────────────────────────────────────────────────
// ANTI-CHOP FILTERS
// ──────────────────────────────────────────────────────────────────────────────
// ADX — trend strength (direction-agnostic)
[diPlus, diMinus, adxValue] = ta.dmi(adxLen, adxLen)
isTrending = adxValue >= adxThresh
// Donchian Channel — breakout confirmation
donchHigh = ta.highest(high, donchLen)
nearBreakout = close >= donchHigh * donchMult
// ──────────────────────────────────────────────────────────────────────────────
// STATE MACHINE WITH ANTI-CHOP LOGIC
// ──────────────────────────────────────────────────────────────────────────────
var bool isLong = false
var int barsInTrade = 0
var int barsSinceExit = 999
if isLong
barsInTrade = 1
// Exit: score collapsed AND minimum hold period met
if score <= exitTh and barsInTrade >= minHold
isLong := false
barsSinceExit := 0
barsInTrade := 0
else
barsSinceExit = 1
// Entry: score threshold AND ADX trending AND Donchian breakout AND cooldown passed
cooldownOK = barsSinceExit >= cooldown
if score >= entryTh and isTrending and nearBreakout and cooldownOK
isLong := true
barsInTrade := 1
// ──────────────────────────────────────────────────────────────────────────────
// STRATEGY EXECUTION
// ──────────────────────────────────────────────────────────────────────────────
longEntry = isLong and strategy.position_size == 0
longExit = not isLong and strategy.position_size > 0
if longEntry
strategy.entry("Long", strategy.long)
if longExit
strategy.close("Long", comment="Exit")
// ──────────────────────────────────────────────────────────────────────────────
// VISUAL LAYER
// ──────────────────────────────────────────────────────────────────────────────
// Bar coloring
barcolor(isLong ?
#00C853 :
#FF1744)
// Background: green = in position, red = in cash
bgcolor(showBG ? (isLong ?
color.new(
#00C853, 88) :
color.new(
#FF1744, 92)) : na)
// Moving averages
plot(showMAs ? fastEMA : na, "Fast EMA", color=
#2196F3, linewidth=2)
plot(showMAs ? slowEMA : na, "Slow EMA", color=
#FF9800, linewidth=2)
plot(showMAs ? trendSMA : na, "100 SMA", color=
#9E9E9E, linewidth=1, style=
plot.style_cross)
// Donchian high (dashed)
plot(showMAs ? donchHigh * donchMult : na, "Donchian Entry", color=
color.new(
#AB47BC, 50), linewidth=1, style=
plot.style_stepline)
// Entry / Exit markers
plotshape(longEntry, "BUY", shape.triangleup, location.belowbar,
#00C853, size=size.normal, text="IN")
plotshape(longExit, "SELL", shape.triangledown, location.abovebar,
#FF1744, size=size.normal, text="OUT")
// Cooldown indicator (small dots below price when in cooldown)
inCooldown = not isLong and barsSinceExit < cooldown
plotshape(inCooldown, "Cooldown",
shape.circle, location.belowbar,
color.new(
#FFC107, 40), size=size.tiny)
// LIVE MODE INDICATOR — persistent reminder this version repaints
var label liveLabel = na
if barstate.islast
if not na(liveLabel)
label.delete(liveLabel)
liveLabel :=
label.new(bar_index, high * 1.02, "⚡ LIVE",
color=
color.new(
#FFC107, 20), textcolor=#000000,
style=
label.style_label_down, size=size.small)
// ADX panel (optional)
plot(showADX ? adxValue : na, "ADX", color=
#7E57C2, linewidth=2)
hline(showADX ? adxThresh : na, "ADX Threshold", color=color.gray, linestyle=
hline.style_dashed)
// ──────────────────────────────────────────────────────────────────────────────
// PERFORMANCE TABLE
// ──────────────────────────────────────────────────────────────────────────────
if showTable and barstate.islastconfirmedhistory
stratReturn = (strategy.equity / strategy.initial_capital - 1) * 100
firstClose = ta.valuewhen(bar_index == 0, close, 0)
bhReturn = firstClose > 0 ? (close / firstClose - 1) * 100 : 0
mult = bhReturn != 0 ? stratReturn / bhReturn : 0
var float peakEquity = 0.0
var float maxDD = 0.0
peakEquity := math.max(peakEquity, strategy.equity)
currDD = (strategy.equity - peakEquity) / peakEquity * 100
maxDD := math.min(maxDD, currDD)
totalTrades = strategy.closedtrades
var table perfTable =
table.new(
position.top_right, 2, 8,
bgcolor=
color.new(
#1a1a2e, 10), border_color=
color.new(
#e0e0e0, 60), border_width=1)
table.cell(perfTable, 0, 0, "CYCLE ALPHA V3 ⚡LIVE", text_color=
#FFC107, text_size=size.normal, bgcolor=
color.new(
#0d0d1a, 0))
table.cell(perfTable, 1, 0, "ANTI-CHOP", text_color=
#AB47BC, text_size=size.normal, bgcolor=
color.new(
#0d0d1a, 0))
table.cell(perfTable, 0, 1, "Strategy Return", text_color=
#e0e0e0, text_size=size.small)
table.cell(perfTable, 1, 1, str.tostring(stratReturn, "#,##0.0") "%",
text_color=stratReturn >= 0 ?
#00C853 :
#FF1744, text_size=size.small)
table.cell(perfTable, 0, 2, "Buy & Hold Return", text_color=
#e0e0e0, text_size=size.small)
table.cell(perfTable, 1, 2, str.tostring(bhReturn, "#,##0.0") "%",
text_color=bhReturn >= 0 ?
#00C853 :
#FF1744, text_size=size.small)
table.cell(perfTable, 0, 3, "Outperformance (×)", text_color=
#e0e0e0, text_size=size.small)
table.cell(perfTable, 1, 3, str.tostring(mult, "#0.0") "×",
text_color=mult >= 5 ?
#00E676 : (mult >= 3 ?
#FFC107 :
#FF1744), text_size=size.small)
table.cell(perfTable, 0, 4, "Max Drawdown", text_color=
#e0e0e0, text_size=size.small)
table.cell(perfTable, 1, 4, str.tostring(maxDD, "#0.0") "%",
text_color=
#FF9800, text_size=size.small)
table.cell(perfTable, 0, 5, "Total Trades", text_color=
#e0e0e0, text_size=size.small)
table.cell(perfTable, 1, 5, str.tostring(totalTrades),
text_color=
#e0e0e0, text_size=size.small)
table.cell(perfTable, 0, 6, "ADX (trend)", text_color=
#e0e0e0, text_size=size.small)
table.cell(perfTable, 1, 6, str.tostring(adxValue, "#0.0") (isTrending ? " TREND" : " RANGE"),
text_color=isTrending ?
#7E57C2 :
#9E9E9E, text_size=size.small)
table.cell(perfTable, 0, 7, "Current Signal", text_color=
#e0e0e0, text_size=size.small)
signalText = isLong ? "● FULLY IN" : (inCooldown ? "● COOLDOWN" : "● FULLY OUT")
signalColor = isLong ?
#00C853 : (inCooldown ?
#FFC107 :
#FF1744)
table.cell(perfTable, 1, 7, signalText, text_color=signalColor, text_size=size.small)
// ──────────────────────────────────────────────────────────────────────────────
// ALERTS
// ──────────────────────────────────────────────────────────────────────────────
alertcondition(longEntry, "Cycle Alpha V3 LIVE — BUY", "⚡ BTC Cycle Alpha V3 LIVE: GO LONG — Signal fired mid-candle. Confirm at close or act now.")
alertcondition(longExit, "Cycle Alpha V3 LIVE — SELL", "⚡ BTC Cycle Alpha V3 LIVE: EXIT — Signal fired mid-candle. Confirm at close or act now.")
alertcondition(inCooldown, "Cycle Alpha V3 — COOLDOWN", "BTC Cycle Alpha V3: In cooldown period, no re-entry allowed.")