Here is a complete Pine Script v5 strategy template built around your three-tier money management framework.
This script functions as a "risk wrapper." It dynamically calculates your daily PnL, adjusts your position size on the fly, and halts trading if you hit your hard stop. I've included a dummy moving average crossover just so the script compiles and runs, which you can replace with your actual price action triggers.
Code: Select all
//@version=5
strategy("Intraday Risk Manager [House Money System]", overlay=true, calc_on_every_tick=true, initial_capital=10000)
// =========================================================================
// 1. INPUTS & RISK PARAMETERS
// =========================================================================
grp_risk = "Core Risk Parameters"
baseRiskPct = input.float(1.0, title="Base Risk per Trade (%)", group=grp_risk)
hardStopPct = input.float(3.0, title="Hard Daily Loss Stop (%)", tooltip="Platform shuts down if daily loss hits this %", group=grp_risk)
softStopPct = input.float(1.0, title="Soft Throttle Drawdown (%)", tooltip="Drawdown % where size is cut in half", group=grp_risk)
grp_house = "House Money (Scaling up on profits)"
useHouseMoney = input.bool(true, title="Enable House Money Scaling?", group=grp_house)
profitThreshold = input.float(2.0, title="Profit Threshold to Scale (%)", tooltip="Daily profit % required to start risking house money", group=grp_house)
riskProfitPct = input.float(100.0, title="% of Daily Profit to Risk", tooltip="100% means you risk all intraday profits on the next setup. If you lose, you return to break-even for the day.", group=grp_house)
// =========================================================================
// 2. DAILY PNL TRACKING
// =========================================================================
var float startOfDayEquity = strategy.initial_capital
var float currentRiskPct = baseRiskPct
var bool canTradeToday = true
// Detect new trading day
isNewDay = ta.change(time("D")) != 0
if isNewDay
startOfDayEquity := strategy.equity
canTradeToday := true
// Calculate current daily performance
dailyPnL = strategy.equity - startOfDayEquity
dailyPnLPct = (dailyPnL / startOfDayEquity) * 100
// =========================================================================
// 3. THE RISK ENGINE
// =========================================================================
// Rule A: Hard Stop
if dailyPnLPct <= -hardStopPct
canTradeToday := false
// Rule B & C: Throttles and House Money
if canTradeToday
if dailyPnLPct <= -softStopPct
// Soft throttle: Cut size in half to catch the spiral
currentRiskPct := baseRiskPct * 0.5
else if useHouseMoney and dailyPnLPct >= profitThreshold
// House money: Risk a percentage of the profits you've already made today
// We use math.max to ensure you at least risk your base amount
houseMoneyRisk = dailyPnLPct * (riskProfitPct / 100)
currentRiskPct := math.max(baseRiskPct, houseMoneyRisk)
else
// Standard operating size
currentRiskPct := baseRiskPct
// =========================================================================
// 4. EXECUTION (Replace with your actual setups)
// =========================================================================
// Dummy triggers for demonstration
fastMA = ta.sma(close, 9)
slowMA = ta.sma(close, 21)
longSetup = ta.crossover(fastMA, slowMA)
shortSetup = ta.crossunder(fastMA, slowMA)
// Calculate position size based on current dynamic risk and a fixed 1% Stop Loss
// Formula: Size = (Equity * Risk%) / (Price * SL%)
fixedSlPct = 1.0
posSize = (strategy.equity * (currentRiskPct / 100)) / (close * (fixedSlPct / 100))
if longSetup and canTradeToday and strategy.opentrades == 0
strategy.entry("Long", strategy.long, qty=posSize)
strategy.exit("Exit Long", "Long", loss=close * (fixedSlPct/100) / syminfo.mintick, profit=close * (fixedSlPct*2/100) / syminfo.mintick)
if shortSetup and canTradeToday and strategy.opentrades == 0
strategy.entry("Short", strategy.short, qty=posSize)
strategy.exit("Exit Short", "Short", loss=close * (fixedSlPct/100) / syminfo.mintick, profit=close * (fixedSlPct*2/100) / syminfo.mintick)
// =========================================================================
// 5. ON-CHART DASHBOARD
// =========================================================================
var table dash = table.new(position.top_right, 2, 4, border_width = 1, border_color=color.new(color.gray, 50))
if barstate.islast
// Daily PnL
table.cell(dash, 0, 0, "Daily PnL %", bgcolor=color.new(color.black, 20), text_color=color.white)
table.cell(dash, 1, 0, str.tostring(dailyPnLPct, "#.##") + "%", bgcolor=dailyPnLPct > 0 ? color.new(color.green, 50) : color.new(color.red, 50), text_color=color.white)
// Active Risk
table.cell(dash, 0, 1, "Current Risk %", bgcolor=color.new(color.black, 20), text_color=color.white)
table.cell(dash, 1, 1, str.tostring(currentRiskPct, "#.##") + "%", bgcolor=color.new(color.blue, 50), text_color=color.white)
// System Status
table.cell(dash, 0, 2, "Status", bgcolor=color.new(color.black, 20), text_color=color.white)
table.cell(dash, 1, 2, canTradeToday ? "ACTIVE" : "HALTED", bgcolor=canTradeToday ? color.new(color.green, 50) : color.new(color.red, 50), text_color=color.white)
// Current Mode
table.cell(dash, 0, 3, "State", bgcolor=color.new(color.black, 20), text_color=color.white)
modeText = not canTradeToday ? "Hard Stop Hit" : dailyPnLPct <= -softStopPct ? "Throttled Down" : (useHouseMoney and dailyPnLPct >= profitThreshold) ? "House Money" : "Standard Size"
table.cell(dash, 1, 3, modeText, bgcolor=color.new(color.black, 0), text_color=color.white)