Position sizer
@qtrader/position-sizer
Work out how many shares to buy before you click. Fixed-fractional, ATR (volatility) based, and capped fractional-Kelly sizing, plus a portfolio heat check that totals the risk across open positions and tells you if a new trade fits. Not financial advice.
- Activity
- New: be the first to try it
- Installs
- 0 installs
- Likes
- 0 likes
- Clones
- 0 clones
- 1---
- 2name: position-sizer
- 3description: Calculate position size for a trade and check total portfolio risk. Fixed-fractional (risk a set percent of equity to the stop), ATR or volatility-based stops and size, capped fractional Kelly from a win rate and payoff or from a trade history CSV, and a portfolio heat check across open positions with a "does this new trade fit" answer. Use when the user asks "how many shares should I buy", "size this trade", "where should my stop go", "what does Kelly say", "how much am I risking right now", "portfolio heat", or "can I add this position". Not financial advice.
- 4license: MIT
- 5---
- 7# Position sizer
- 9Size comes from risk, not conviction. Every method here answers one question: if the stop is hit, how much of the account is lost? The script does the arithmetic so nothing is rounded the wrong way under pressure.
- 11This is a calculator, not advice. It never says whether to take a trade.
- 13## Inputs to ask for
- 15- **Equity:** account value the user sizes against (net liquidation value, not buying power).
- 16- **Risk per trade:** percent of equity to lose if stopped. Default suggestion 1%; 0.5% for new or volatile strategies. Above 2% per trade, say plainly that it is aggressive.
- 17- **Entry and stop,** or ATR and a multiple, or a price CSV to compute ATR.
- 18- **Max position size** as a percent of equity, if the user has one (default 100%, which means no leverage).
- 19- For heat: a positions CSV `symbol,side,qty,entry,stop,price` (price optional, stop may be blank).
- 21## Steps
- 231. **Pick the method** from what the user has:
- 24 - Has a chart-based stop: `fixed`.
- 25 - Wants the stop set by volatility: `atr`.
- 26 - Has a track record and asks about Kelly: `kelly`, then show the fixed-fractional size next to it.
- 27 - Already holds positions: always run `heat` before adding a new one.
- 282. **Run it.**
- 30 ```bash
- 31 node scripts/size.mjs fixed --equity 50000 --risk-pct 1 --entry 100 --stop 95 --max-position-pct 25
- 32 node scripts/size.mjs atr --equity 50000 --risk-pct 1 --prices data/XYZ-1Day.csv --atr-period 14 --atr-mult 2
- 33 node scripts/size.mjs atr --equity 50000 --risk-pct 1 --atr 2.4 --entry 100 --side short
- 34 node scripts/size.mjs kelly --trades data/trades.csv --fraction 0.5 --cap 0.05 --equity 50000 --entry 100 --stop 95
- 35 node scripts/size.mjs heat --equity 100000 --positions data/positions.csv --max-heat-pct 6 --max-risk-pct 2 --add XYZ,long,120,25,23
- 36 ```
- 38 Add `--json` for JSON or `--out out/size.json` to save it. Exit code 2 means bad input; the message says which flag.
- 393. **Report** with the template below. Always give shares, stop, dollar risk, percent of equity, and position value.
- 404. **Flag** anything the script noted: a cap that bound, a size that rounds to 0, a position with no stop, a single trade over the per-trade limit, or total heat over the limit.
- 42## How each method works
- 44- **Fixed fractional:** shares = floor(equity x risk% / |entry - stop|), then capped so shares x entry stays under the max position percent.
- 45- **ATR:** Wilder ATR (first value is the average of the first N true ranges, then smoothed). Stop = entry minus (long) or plus (short) mult x ATR, then fixed-fractional. With `--prices`, entry defaults to the last close.
- 46- **Kelly:** f* = p - (1 - p) / b, where p is the win rate and b is average win / average loss. Here f is the share of equity **at risk to the stop**, not the position size. The script uses half Kelly by default and caps it at 5% of equity at risk. Full Kelly assumes the stats are exact; they never are, and it produces deep drawdowns. Under 30 trades, say the estimate is noisy.
- 47- **Heat:** for each position, qty x distance from the current price (or entry) to the stop. No stop means the whole position value counts. Total heat is compared to the limit (default 6%), each position to the per-trade limit (default 2%). For a proposed add, it reports the largest size that keeps both limits.
- 49## Output template
- 51```markdown
- 52**XYZ long: 100 shares at 100.00, stop 95.00**
- 53Risk $500 (1.00% of $50,000) | Position $10,000 (20% of equity)
- 54Portfolio heat after this trade: 4.3% of 6% limit. Fits.
- 55Notes: none
- 56Not financial advice.
- 57```
- 59## Guardrails
- 61- Never round shares up. The script floors; keep it that way.
- 62- Never suggest moving a stop further away to get a bigger size. Size follows the stop, not the reverse.
- 63- Do not place orders. If the user wants to place one, hand off to the `alpaca-connector` kit and its confirmation rules.
- 64- If equity, entry, or stop is missing, ask. Do not guess prices.
