Risk and sizing
Position Heat
For an account size and a risk percentage, the panel shows the cash at stake, the current ATR stop distance, the units that combination buys and the resulting exposure, flagging the risk figure when it climbs past a threshold you set.
indicator
//@version=6
indicator("Position Heat", "Heat", overlay = true)
account = input.float(25000, "Account size", minval = 1, step = 100, group = "Settings")
riskPct = input.float(0.5, "Risk per trade in percent", minval = 0.01, maxval = 100, step = 0.05, group = "Settings")
atrLen = input.int(14, "ATR length", minval = 1, group = "Settings")
mult = input.float(2.0, "Stop distance in ATR", minval = 0.1, step = 0.1, group = "Settings")
flagAbove = input.float(2.0, "Flag risk above percent", minval = 0.01, step = 0.05, group = "Settings")
textCol = input.color(#787B86, "Text", group = "Style")
flagCol = input.color(#EF5350, "Flagged", group = "Style")
atr = ta.atr(atrLen)
stopDistance = atr * mult
riskCash = account * riskPct / 100
units = stopDistance > 0 ? math.floor(riskCash / stopDistance) : 0
exposure = account > 0 ? units * close / account * 100 : 0
flagged = riskPct > flagAbove
riskRowCol = flagged ? flagCol : textCol
var table panel = table.new(position.top_right, 2, 5, border_width = 1)
if barstate.islast
table.cell(panel, 0, 0, "Risk", text_color = riskRowCol, text_size = size.small)
table.cell(panel, 1, 0, str.tostring(riskPct, "#.##") + "% of account", text_color = riskRowCol, text_size = size.small)
table.cell(panel, 0, 1, "Risk in cash", text_color = riskRowCol, text_size = size.small)
table.cell(panel, 1, 1, str.tostring(riskCash, "#.##"), text_color = riskRowCol, text_size = size.small)
table.cell(panel, 0, 2, "Stop distance", text_color = textCol, text_size = size.small)
table.cell(panel, 1, 2, str.tostring(stopDistance, format.mintick), text_color = textCol, text_size = size.small)
table.cell(panel, 0, 3, "Units", text_color = textCol, text_size = size.small)
table.cell(panel, 1, 3, str.tostring(units), text_color = textCol, text_size = size.small)
table.cell(panel, 0, 4, "Exposure", text_color = textCol, text_size = size.small)
table.cell(panel, 1, 4, str.tostring(exposure, "#.#") + "% of account", text_color = textCol, text_size = size.small)
This runs in TradingView, not here
Pine Script only executes inside TradingView. Paste the source into the Pine Editor and add it to a chart to see it plotted.
What it will not do
- Units are rounded down and ignore fees, slippage and contract multipliers. Check every number against your broker before sizing a trade from it.
- Exposure assumes one unit is worth the current close. For futures, options and anything with a multiplier that is simply wrong.
- The stop distance moves with ATR, so the size shown changes bar by bar. Read it once, at the point of entry.
- A size that fits your risk percentage is not the same as a sensible trade. This panel has no opinion on the trade itself.
Written from this description
Show a corner table that converts an account size and a risk percentage into the cash at risk, then divides it by an ATR based stop distance to give a position size and the exposure that size represents, and colour the risk rows when the percentage is above a threshold.
Educational only, not financial advice. The maths is simple arithmetic on the numbers you enter; it knows nothing about your broker, fees, slippage or the market. Something wrong with it? Say so in Site Feedback.