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
What it makes
Real output from this kit
- Sample file268 bytes, download to openFixedFrom the kit's tests
- Sample file1 KB, download to openHeatFrom the kit's tests
How this works
- It is a skill: written instructions Claude reads when your request matches what the skill is for. You do not call it by name; just ask for the task.
- While it works, it reads and changes files in the places it lists, nowhere else.
- It runs these commands on your computer: node scripts/size.mjs, node scripts/selftest.mjs.
- Nothing runs until you choose to use it, and you can remove it any time.
SKILL.md
Position sizer
Size 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.
This is a calculator, not advice. It never says whether to take a trade.
Inputs to ask for
- Equity: account value the user sizes against (net liquidation value, not buying power).
- 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.
- Entry and stop, or ATR and a multiple, or a price CSV to compute ATR.
- Max position size as a percent of equity, if the user has one (default 100%, which means no leverage).
- For heat: a positions CSV
symbol,side,qty,entry,stop,price(price optional, stop may be blank).
Steps
Pick the method from what the user has:
- Has a chart-based stop:
fixed. - Wants the stop set by volatility:
atr. - Has a track record and asks about Kelly:
kelly, then show the fixed-fractional size next to it. - Already holds positions: always run
heatbefore adding a new one.
- Has a chart-based stop:
Run it.
node scripts/size.mjs fixed --equity 50000 --risk-pct 1 --entry 100 --stop 95 --max-position-pct 25 node scripts/size.mjs atr --equity 50000 --risk-pct 1 --prices data/XYZ-1Day.csv --atr-period 14 --atr-mult 2 node scripts/size.mjs atr --equity 50000 --risk-pct 1 --atr 2.4 --entry 100 --side short node scripts/size.mjs kelly --trades data/trades.csv --fraction 0.5 --cap 0.05 --equity 50000 --entry 100 --stop 95 node scripts/size.mjs heat --equity 100000 --positions data/positions.csv --max-heat-pct 6 --max-risk-pct 2 --add XYZ,long,120,25,23Add
--jsonfor JSON or--out out/size.jsonto save it. Exit code 2 means bad input; the message says which flag.- Report with the template below. Always give shares, stop, dollar risk, percent of equity, and position value.
- 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.
How each method works
- Fixed fractional: shares = floor(equity x risk% / |entry - stop|), then capped so shares x entry stays under the max position percent.
- 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. - 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.
- 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.
Output template
**XYZ long: 100 shares at 100.00, stop 95.00**
Risk $500 (1.00% of $50,000) | Position $10,000 (20% of equity)
Portfolio heat after this trade: 4.3% of 6% limit. Fits.
Notes: none
Not financial advice.Guardrails
- Never round shares up. The script floors; keep it that way.
- Never suggest moving a stop further away to get a bigger size. Size follows the stop, not the reverse.
- Do not place orders. If the user wants to place one, hand off to the
alpaca-connectorkit and its confirmation rules. - If equity, entry, or stop is missing, ask. Do not guess prices.
README.md
position-sizer
Know your size before you click buy. This kit turns your account size, risk per trade, and stop into a share count, with fixed-fractional, ATR-based, and capped Kelly methods, and checks your total open risk ("portfolio heat") before you add a new position.
Who it is for: discretionary and systematic traders who want a consistent, written-down sizing rule instead of a gut feel.
Not financial advice. It is a calculator; it never tells you whether to take a trade.
Example
node scripts/size.mjs heat --equity 100000 --positions examples/positions.csv --add FFF,long,120,25,23Portfolio heat: 5.80% of equity at risk ($5,800.00) | limit 6.00% | OK
Symbol Side Qty Ref Stop Risk $ Risk % Flags
AAA long 100 52 46 600.00 0.60%
BBB long 200 35 31 800.00 0.80% stop locks in profit vs entry
CCC short 50 80 84 200.00 0.20%
DDD long 150 20 - 3,000.00 3.00% NO STOP: full value at risk; over 2% single-trade limit
EEE long 300 41 37 1,200.00 1.20%
Proposed FFF x120: risk $240.00 (0.24%), heat after 6.04%. Does not fit. Max that fits: 100 shares.Hand check (verify it yourself)
- Fixed fractional: equity 50,000, risk 1%, entry 100, stop 95. Risk budget 500, per-share risk 5, so 100 shares, a 10,000 position (20% of equity). With a 15% max position: floor(7,500 / 100) = 75 shares.
- ATR(3) on
examples/prices.csv. True ranges: 1.0 (first bar, high - low), 0.8, 1.1, 0.8, 1.7 (12 - 10.3 beats 12 - 10.5). Seed = (1.0 + 0.8 + 1.1) / 3 = 0.966667. Then (0.966667 x 2 + 0.8) / 3 = 0.911111, then (0.911111 x 2 + 1.7) / 3 = 1.174074. With 2 x ATR, stop = 11.8 - 2.348148 = 9.451852. With 10,000 equity at 1%: floor(100 / 2.348148) = 42 shares. - Kelly: win rate 0.55, payoff 1.5. f* = 0.55 - 0.45 / 1.5 = 0.25. Half Kelly = 12.5% of equity at risk, which the default 5% cap cuts to 5%. From
examples/trades.csv(3 wins averaging 216.67, 3 losses averaging 83.33): p = 0.5, b = 2.6, f* = 0.5 - 0.5 / 2.6 = 0.3077. - Heat: AAA 100 x (52 - 46) = 600. BBB 200 x (35 - 31) = 800. CCC short 50 x (84 - 80) = 200. DDD has no stop: 150 x 20 = 3,000. EEE 300 x (41 - 37) = 1,200. Total 5,800 = 5.8% of 100,000. Room left 0.2% = 200, so FFF with a 2-point stop fits at most 100 shares.
node scripts/selftest.mjs checks every number above.
Opinionated defaults
- Kelly is half Kelly capped at 5% of equity at risk. Full Kelly assumes you know your edge exactly, and you do not.
- Heat limit 6% of equity, single-trade limit 2%. Change them with
--max-heat-pctand--max-risk-pct. - Shares always round down.
What it can access
- Reads CSVs you point it at in
data/, writes JSON toout/when you pass--out. - Runs only its own scripts with Node. No network, no keys, no broker access.
Setup
Node 22 or newer. Nothing to install.
Files
- README.md
- SKILL.md
- examples/positions.csv
- examples/prices.csv
- examples/trades.csv
- kit.json
- scripts/selftest.mjs
- scripts/size.mjs
Did it work?
0worked for them0did not work
Sign in to say whether it worked for you.
Nobody has said yet. Tried it? Tell the next person.
