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.
Installs into .claude/skills of the current project.
Are you the author of Money Precision?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/alpacahq-money-precision)
---
name: alpaca-broker-money-precision
description: 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.
---
# Alpaca — Money & Numeric Precision
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.
## 1. Numbers come as strings — keep them that way
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.
## 2. Round/truncate before sending — and know the direction
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.
- For **money you're moving out / charging**, **truncate (round down)** to 2 dp so you never move more than intended. (e.g. `floor(amount * 100) / 100`.)
- Pick the rounding mode consciously (`ROUND_DOWN` vs `ROUND_HALF_UP`) — don't inherit whatever the default float formatting does.
- Re-round after every arithmetic step that could reintroduce precision (e.g. computing `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)
```
## 3. Fractional shares
- `qty` and `notional` support up to **9 decimal places**.
- `qty` XOR `notional` — never both (see `alpaca-broker-trading-orders`).
- Don't reconstruct `qty` from `notional / price` and send it — pass `notional` and let Alpaca compute the fill. Round-tripping through a price you fetched introduces drift.
## 4. Storage
- Store money in your DB as **fixed-point decimal**, not float. A practical pattern is generous precision/scale, e.g. `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.
- **Store what Alpaca sent verbatim** alongside any converted/derived values. If you truncate to 2 dp for the API call but received more precision back, keep both — it makes reconciliation and audits possible.
- Keep an explicit **currency** column; Alpaca is multi-currency on some rails (funding wallet) even though most is USD.
## 5. Multi-currency notes
- Most Broker/trading flows are USD; journals default to USD.
- The **funding wallet** rail supports many currencies (`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.
## 6. Checklist
- [ ] Money fields parsed from strings into a **decimal** type; serialized back to strings.
- [ ] **No binary floats** anywhere in the move-money path.
- [ ] Amounts rounded/truncated to the allowed precision **before** the call, with an intentional rounding mode (round *down* for outgoing money).
- [ ] Re-round after each intermediate computation.
- [ ] DB columns are fixed-point decimal with headroom; raw Alpaca values stored verbatim.
- [ ] Explicit currency tracked.
**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`.