Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Handle money and numeric precision correctly with the Alpaca API — numbers-as-strings on the wire, decimals vs floats, rounding/truncation before sending amounts, fractional-share precision, and safe DB storage. Use when handling monetary amounts, order quantities, or prices in any Alpaca integration in any language.
.claude/skills/alpacahq-alpaca-broker-money-precision/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | -20% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 9% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 13% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 36% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 21% | 0% |
Financial bugs are silent and expensive. Alpaca's wire format and the realities of decimal arithmetic create a few specific traps. This skill is short, opinionated, and language-agnostic.
> Read alpaca-broker-integration first.
Alpaca returns prices, quantities, notional, and money amounts as JSON strings ("100.50", "1.5", "190.2345"), and accepts them as strings on the way in. This is deliberate: it avoids the precision loss of JSON's binary floats.
Rule: parse string money fields into a decimal type, never a binary float/double. Serialize back to a string. Don't let a number ever live as an IEEE-754 float in the money path.
| Language | Use | Avoid | |----------|-----|-------| | Python | decimal.Decimal("100.50") | float("100.50") | | TypeScript/JS | a decimal lib (decimal.js/big.js) or string arithmetic | Number(...), parseFloat | | Go | shopspring/decimal | float64 for accumulation | | Java/Kotlin | java.math.BigDecimal | double |
> Real-world caveat: not every Alpaca endpoint is consistent — some market-data numeric fields come as JSON numbers (e.g. bar OHLC). Prices for display/analytics can tolerate floats; money you move or store must not. Know which field you're touching.
Alpaca generally accepts 2 decimal places for cash amounts and up to 9 for fractional share qty/notional. If you send more precision than allowed, you risk rejection or silent rounding on their side.
Rule: explicitly round/truncate to the target precision before the API call, using a deliberate rounding mode.
floor(amount * 100) / 100.)ROUND_DOWN vs ROUND_HALF_UP) — don't inherit whatever the default float formatting does.amount * percentage for a split allocation), not just at the end.# splitting a deposit across holdings — round each slice down, track remainder
slice = truncate(total * (pct / 100), 2)qty and notional support up to 9 decimal places.qty XOR notional — never both (see alpaca-broker-trading-orders).qty from notional / price and send it — pass notional and let Alpaca compute the fill. Round-tripping through a price you fetched introduces drift.DECIMAL(20, 8) — wide enough for multi-currency and fractional, with headroom beyond Alpaca's 2-dp cash so you never lose data you received.USD, EUR, JPY, …) and carries FX fees. When you touch it, never assume USD — read and store the currency, and treat FX amounts as decimals end-to-end.Related skills: order qty/notional rules → alpaca-broker-trading-orders; journal/transfer amounts → alpaca-broker-journals, alpaca-broker-funding-transfers; reconciling stored vs Alpaca values → alpaca-broker-reconciliation-idempotency.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 19,856 | 15,275 | -23% | 1 | 1 | 0% | 4,515 | 3,601 | -20% | 0 | 0 | — |
case-02 | fail→fail | 17,808 | 17,112 | -4% | 1 | 1 | 0% | 3,961 | 4,026 | +2% | 0 | 0 | — |
case-03 | pass→pass | 13,146 | 14,307 | +9% | 1 | 1 | 0% | 3,058 | 3,850 | +26% | 0 | 0 | — |
case-04 | pass→fail | 16,152 | 9,223 | -43% | 1 | 1 | 0% | 2,979 | 2,691 | -10% | 0 | 0 | — |
case-05 | pass→pass | 14,161 | 10,843 | -23% | 1 | 1 | 0% | 2,622 | 3,209 | +22% | 0 | 0 | — |
case-06 | fail→fail | 14,416 | 12,167 | -16% | 1 | 1 | 0% | 3,154 | 3,128 | -1% | 0 | 0 | — |
case-07 | fail→pass | 16,227 | 13,087 | -19% | 1 | 1 | 0% | 3,603 | 3,917 | +9% | 0 | 0 | — |
case-08 | pass→pass | 17,224 | 12,513 | -27% | 1 | 1 | 0% | 3,610 | 3,871 | +7% | 0 | 0 | — |
case-09 | fail→pass | 11,146 | 7,611 | -32% | 1 | 1 | 0% | 2,298 | 2,602 | +13% | 0 | 0 | — |
case-10 | fail→pass | 21,861 | 17,675 | -19% | 1 | 1 | 0% | 3,870 | 5,249 | +36% | 0 | 0 | — |
case-11 | pass→pass | 12,825 | 7,596 | -41% | 1 | 1 | 0% | 2,410 | 2,494 | +3% | 0 | 0 | — |
case-12 | pass→pass | 16,552 | 12,729 | -23% | 1 | 1 | 0% | 3,590 | 3,206 | -11% | 0 | 0 | — |
case-13 | fail→pass | 6,584 | 2,032 | -69% | 1 | 1 | 0% | 1,155 | 1,400 | +21% | 0 | 0 | — |
case-14 | pass→pass | 8,120 | 4,638 | -43% | 1 | 1 | 0% | 1,632 | 1,930 | +18% | 0 | 0 | — |
case-15 | fail→fail | 18,454 | 15,788 | -14% | 1 | 1 | 0% | 3,485 | 4,219 | +21% | 0 | 0 | — |
case-16 | fail→pass | 19,600 | 9,153 | -53% | 1 | 1 | 0% | 4,047 | 2,993 | -26% | 0 | 0 | — |
case-17 | pass→pass | 11,336 | 7,679 | -32% | 1 | 1 | 0% | 2,451 | 2,330 | -5% | 0 | 0 | — |
case-18 | fail→pass | 12,407 | 10,331 | -17% | 1 | 1 | 0% | 2,592 | 3,303 | +27% | 0 | 0 | — |
case-19 | pass→pass | 11,880 | 8,588 | -28% | 1 | 1 | 0% | 2,430 | 2,764 | +14% | 0 | 0 | — |
case-20 | pass→pass | 13,194 | 9,692 | -27% | 1 | 1 | 0% | 2,892 | 3,133 | +8% | 0 | 0 | — |
case-21 | fail→pass | 9,408 | 2,768 | -71% | 1 | 1 | 0% | 1,240 | 1,542 | +24% | 0 | 0 | — |
case-22 | pass→pass | 14,351 | 5,350 | -63% | 1 | 1 | 0% | 2,379 | 1,982 | -17% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +32 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.