The sizing problem
On a CFD account, the question "how many contracts do I trade" is the highest-leverage decision in your strategy. A 1% account risk on a 10x leveraged instrument with a 2% stop means you can take a position equal to 50% of your equity — that's fine. The same risk with a 50x instrument and a 1% stop means 200% of equity — and a single tick against you wipes the account.
Risk-based sizing in Pine
riskPct = input.float(1.0, "Risk %", minval=0.1)
stopDist = ta.atr(14) * 1.5
riskMoney = strategy.equity * riskPct / 100
contracts = riskMoney / (stopDist * syminfo.pointvalue)
strategy.entry("Long", strategy.long, qty=contracts)
strategy.exit("X", "Long", stop=close - stopDist, limit=close + stopDist * 2)
For a CFD, syminfo.pointvalue is the value of a one-point move per contract. Combined with stop distance in price, this gives you a contract size that risks exactly riskPct percent of equity if the stop is hit.
Why this is better than fixed-contract sizing
If you size to "always 1 contract", your risk scales with volatility. In calm markets you under-trade; in volatile markets a single tick can blow the account. Risk-based sizing keeps your dollar risk constant — your position shrinks when volatility expands, which is exactly when you want it to.
Edge cases
If stopDist is too small (syminfo.mintick rounds), you'll get division blowups or weird fractions. Clamp with max(stopDist, syminfo.mintick * 10).
Testing sizing
The strategy tester reports PnL accurately when sizing is dynamic — that is one of the few areas where Pine's backtest engine handles complexity well. What it does not model: spread widening during your stop, requotes, slippage during news. Subtract at least 1 tick per side to be conservative.
What you should not do
Do not let Pine use default_qty_type=strategy.cash with a hard-coded number — it will over-size in calm markets and under-size in volatile ones, the opposite of what you want.