116 lines
4.5 KiB
Plaintext
116 lines
4.5 KiB
Plaintext
//@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)
|