Skip to content

script 1 #36

@doceparesvancouver

Description

@doceparesvancouver

//@Version=6,
strategy(title=johnnys_Scalp_Control)''
title=johnnys_Scalp_Control
shorttitle="10m, 15m, No-Chop, Volume-Aware")
overlay=true,
pyramiding=2,
calc_on_every_tick=false,
calc_on_order_fills=true,
initial_capital=10000,
commission_type=strategy.commission.percent,
commission_value=0.05,
slippage=1,
max_labels_count=500,
max_lines_count=500

//====================== Presets & Controls ======================
groupPresets = "Presets"
assetPreset = input.string("Auto", "Asset Preset", options=["Auto", "XRP", "XLM", "ADA", "Custom"], group=groupPresets)
controller = input.string("10m", "Controller (manual)", options=["10m", "15m"], group=groupPresets)
useKillzones = input.bool(true, "Limit to Killzones (London/NY overlap bias)", group=groupPresets)

// Exchange/asset multipliers (spread/ATR tuning)
spreadMult = switch assetPreset
"XRP" => 1.00
"XLM" => 1.10
"ADA" => 1.15
=> 1.00

//====================== Filters & Signal Params =================
groupFilters = "Filters"
adxLen = input.int(14, "ADX Len (15m Gate)", group=groupFilters)
adxMin = input.float(18.0, "Min ADX (trendiness)", step=0.5, group=groupFilters)
chopLen = input.int(14, "Choppiness Len (15m Gate)", group=groupFilters)
chopMax = input.float(45.0, "Max Choppiness (≤ trending)", step=0.5, group=groupFilters)

groupSig = "Signals"
rsiLen = input.int(14, "RSI Len", group=groupSig)
rsiOB = input.int(72, "RSI Overbought", group=groupSig)
rsiOS = input.int(28, "RSI Oversold", group=groupSig)
kLen = input.int(20, "Keltner EMA Len", group=groupSig)
kMult = input.float(1.6, "Keltner ATR Mult", step=0.1, group=groupSig)

groupVol = "Volume Flow"
vLen = input.int(20, "Vol MA Len", group=groupVol)
cmfLen = input.int(20, "CMF Len", group=groupVol)
mfiLen = input.int(14, "MFI Len", group=groupVol)
cmfMin = input.float(0.06, "CMF Min |±|", step=0.01, group=groupVol)
mfiMin = input.int(55, "MFI Long Min", group=groupVol)
mfiMax = input.int(45, "MFI Short Max", group=groupVol)
vSpikeK = input.float(1.25, "Volume Spike = v > K × vMA", step=0.05, group=groupVol)

groupRisk = "Risk / Exits"
atrLen = input.int(14, "ATR Len", group=groupRisk)
slMult = input.float(1.25, "Stop = ATR ×", step=0.05, group=groupRisk)
tpMult = input.float(1.85, "Target = ATR ×", step=0.05, group=groupRisk)
trailOn = input.bool(true, "Arm Trailing after RR≥1", group=groupRisk)
trailATR = input.float(1.00, "Trail = ATR ×", step=0.05, group=groupRisk)
cooldownBars = input.int(6, "Cooldown bars after exit", minval=0, group=groupRisk)
dailyStop = input.float(3.0, "Daily Loss Stop (%)", step=0.1, group=groupRisk)

groupViz = "Visuals"
show10Bands = input.bool(true, "Show 10m Keltner", group=groupViz)
showMarks = input.bool(true, "Mark Entries", group=groupViz)

//====================== Utility Functions ======================
choppiness(o, h, l, c, _len) =>
tr = math.max(h - l, math.max(math.abs(h - nz(c[1], c)), math.abs(l - nz(c[1], c))))
sumTr = ta.sum(tr, _len)
hh = ta.highest(h, _len)
ll = ta.lowest(l, _len)
100 * math.log10(sumTr / math.max(hh - ll, syminfo.mintick)) / math.log10(_len)

rejectionCandles(o, h, l, c) =>
body = math.abs(c - o)
upper = h - math.max(o, c)
lower = math.min(o, c) - l
bull = c > o and lower > body * 1.2 and upper <= body * 0.8
bear = o > c and upper > body * 1.2 and lower <= body * 0.8
[bull, bear]

// Killzones (London 10:00–13:00 UTC & NY 13:30–17:00 UTC approximations)
inSession(sess) =>
not useKillzones or not na(time(timeframe.period, sess))

sessLondon = "1000-1300"
sessNY = "1330-1700"
sessionOK = inSession(sessLondon) or inSession(sessNY)

//====================== 15m “No-Chop” Gate =====================
adx15 = request.security(syminfo.tickerid, "15", ta.adx(adxLen), barmerge.gaps_off, barmerge.lookahead_off)
chop15 = request.security(syminfo.tickerid, "15", choppiness(open, high, low, close, chopLen), barmerge.gaps_off, barmerge.lookahead_off)
gateOK = adx15 >= adxMin and chop15 <= chopMax

//====================== Volume Flow ============================
cmf10 = request.security(syminfo.tickerid, "10", ta.cmf(high, low, close, volume, cmfLen), barmerge.gaps_off, barmerge.lookahead_off)
cmf15 = request.security(syminfo.tickerid, "15", ta.cmf(high, low, close, volume, cmfLen), barmerge.gaps_off, barmerge.lookahead_off)
mfi10 = request.security(syminfo.tickerid, "10", ta.mfi(high, low, close, volume, mfiLen), barmerge.gaps_off, barmerge.lookahead_off)
mfi15 = request.security(syminfo.tickerid, "15", ta.mfi(high, low, close, volume, mfiLen), barmerge.gaps_off, barmerge.lookahead_off)

v10 = request.security(syminfo.tickerid, "10", volume, barmerge.gaps_off, barmerge.lookahead_off)
vma10 = request.security(syminfo.tickerid, "10", ta.sma(volume, vLen), barmerge.gaps_off, barmerge.lookahead_off)
vSpike10 = v10 > vma10 * vSpikeK

v15 = request.security(syminfo.tickerid, "15", volume, barmerge.gaps_off, barmerge.lookahead_off)
vma15 = request.security(syminfo.tickerid, "15", ta.sma(volume, vLen), barmerge.gaps_off, barmerge.lookahead_off)
vSpike15 = v15 > vma15 * vSpikeK

//====================== 10m Engine =============================
o10 = request.security(syminfo.tickerid, "10", open, barmerge.gaps_off, barmerge.lookahead_off)
h10 = request.security(syminfo.tickerid, "10", high, barmerge.gaps_off, barmerge.lookahead_off)
l10 = request.security(syminfo.tickerid, "10", low, barmerge.gaps_off, barmerge.lookahead_off)
c10 = request.security(syminfo.tickerid, "10", close, barmerge.gaps_off, barmerge.lookahead_off)
ema10 = request.security(syminfo.tickerid, "10", ta.ema(close, kLen), barmerge.gaps_off, barmerge.lookahead_off)
atr10 = request.security(syminfo.tickerid, "10", ta.atr(atrLen), barmerge.gaps_off, barmerge.lookahead_off)
kHi10 = ema10 + kMult * atr10
kLo10 = ema10 - kMult * atr10
rsi10 = request.security(syminfo.tickerid, "10", ta.rsi(close, rsiLen), barmerge.gaps_off, barmerge.lookahead_off)
[bBull10, bBear10] = request.security(syminfo.tickerid, "10", rejectionCandles(open, high, low, close), barmerge.gaps_off, barmerge.lookahead_off)
conf10 = request.security(syminfo.tickerid, "10", barstate.isconfirmed, barmerge.gaps_off, barmerge.lookahead_off)

long10 = conf10 and gateOK and sessionOK and (c10 <= kLo10) and (rsi10 <= rsiOS) and bBull10 and vSpike10 and cmf10 >= cmfMin and (mfi10 >= mfiMin or mfi15 >= mfiMin)
short10 = conf10 and gateOK and sessionOK and (c10 >= kHi10) and (rsi10 >= rsiOB) and bBear10 and vSpike10 and cmf10 <= -cmfMin and (mfi10 <= mfiMax or mfi15 <= mfiMax)

//====================== 15m Engine =============================
o15 = request.security(syminfo.tickerid, "15", open, barmerge.gaps_off, barmerge.lookahead_off)
h15 = request.security(syminfo.tickerid, "15", high, barmerge.gaps_off, barmerge.lookahead_off)
l15 = request.security(syminfo.tickerid, "15", low, barmerge.gaps_off, barmerge.lookahead_off)
c15 = request.security(syminfo.tickerid, "15", close, barmerge.gaps_off, barmerge.lookahead_off)
ema15 = request.security(syminfo.tickerid, "15", ta.ema(close, kLen), barmerge.gaps_off, barmerge.lookahead_off)
atr15 = request.security(syminfo.tickerid, "15", ta.atr(atrLen), barmerge.gaps_off, barmerge.lookahead_off)
kHi15 = ema15 + kMult * atr15
kLo15 = ema15 - kMult * atr15
rsi15 = request.security(syminfo.tickerid, "15", ta.rsi(close, rsiLen), barmerge.gaps_off, barmerge.lookahead_off)
[bBull15, bBear15] = request.security(syminfo.tickerid, "15", rejectionCandles(open, high, low, close), barmerge.gaps_off, barmerge.lookahead_off)
conf15 = request.security(syminfo.tickerid, "15", barstate.isconfirmed, barmerge.gaps_off, barmerge.lookahead_off)

long15 = conf15 and gateOK and sessionOK and (c15 <= kLo15) and (rsi15 <= rsiOS) and bBull15 and vSpike15 and cmf15 >= cmfMin and mfi15 >= mfiMin
short15 = conf15 and gateOK and sessionOK and (c15 >= kHi15) and (rsi15 >= rsiOB) and bBear15 and vSpike15 and cmf15 <= -cmfMin and mfi15 <= mfiMax

//====================== Routing & Cooldown =====================
fire10 = controller == "10m"
fire15 = controller == "15m"

flatExit = strategy.position_size == 0 and strategy.position_size[1] != 0
cooldownActive = ta.barssince(flatExit) <= cooldownBars

//====================== Orders & Risk ==========================
lossTicks10 = math.round(atr10 * slMult * spreadMult / syminfo.mintick)
profitTicks10 = math.round(atr10 * tpMult * spreadMult / syminfo.mintick)
lossTicks15 = math.round(atr15 * slMult * spreadMult / syminfo.mintick)
profitTicks15 = math.round(atr15 * tpMult * spreadMult / syminfo.mintick)

// Daily kill-switch (percent of start-of-day equity)
var float dayStartEq = strategy.equity
newDay = ta.change(time("D")) != 0
if newDay
dayStartEq := strategy.equity

dayDrawdownPct = 100 * (dayStartEq - strategy.equity) / math.max(dayStartEq, 1)
dailyBlock = dayDrawdownPct >= dailyStop

canEnter = not cooldownActive and not dailyBlock

// 10m orders
if fire10 and canEnter and long10
strategy.entry("L10", strategy.long, comment="10m Long")
strategy.exit("XL10", from_entry="L10", loss=lossTicks10, profit=profitTicks10)

if fire10 and canEnter and short10
strategy.entry("S10", strategy.short, comment="10m Short")
strategy.exit("XS10", from_entry="S10", loss=lossTicks10, profit=profitTicks10)

// 15m orders
if fire15 and canEnter and long15
strategy.entry("L15", strategy.long, comment="15m Long")
strategy.exit("XL15", from_entry="L15", loss=lossTicks15, profit=profitTicks15)

if fire15 and canEnter and short15
strategy.entry("S15", strategy.short, comment="15m Short")
strategy.exit("XS15", from_entry="S15", loss=lossTicks15, profit=profitTicks15)

// Optional trailing (arms once RR ≥ 1, using current ATR)
if trailOn and strategy.position_size != 0
avg = strategy.position_avg_price
rrOK = not na(avg) and (math.abs(close - avg) >= ta.atr(atrLen) * slMult)
if rrOK
trailTicks = math.round(ta.atr(atrLen) * trailATR / syminfo.mintick)
strategy.exit(id="TRAIL", trail_points=trailTicks, trail_offset=trailTicks)

//====================== Visuals & Alerts =======================
if show10Bands
plot(kHi10, "10m Keltner Hi", color=color.new(color.red, 0))
plot(ema10, "10m Keltner Mid", color=color.new(color.gray, 0))
plot(kLo10, "10m Keltner Lo", color=color.new(color.green, 0))

if showMarks
plotchar(fire10 and long10, title="L10", char="▲", location=location.belowbar)
plotchar(fire10 and short10, title="S10", char="▼", location=location.abovebar)
plotchar(fire15 and long15, title="L15", char="▲", location=location.belowbar)
plotchar(fire15 and short15, title="S15", char="▼", location=location.abovebar)

alertcondition(fire10 and long10, title="10m Long", message="10m Long")
alertcondition(fire10 and short10, title="10m Short", message="10m Short")
alertcondition(fire15 and long15, title="15m Long", message="15m Long")
alertcondition(fire15 and short15, title="15m Short", message="15m Short")
alertcondition(dailyBlock, title="Daily Stop Hit", message="Daily loss stop triggered — entries blocked.")

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions