文件内容
references/symbols.md
# symbols
Look up per-symbol trading metadata via `GET /v1/symbols/{symbol}`:
lot size, qty step, tick size, market, board, T+1 stock rule, price limits.
## When to consult this
- User gives a qty that may not be lot-aligned ("买 350 股 600519.SH" — 350 is
not a multiple of CN main-board 100). Fetch `lot_size`/`qty_step` and round
the qty *locally* before submitting. Don't surface `INVALID_LOT_SIZE` to
the user when you could round and proceed (see SKILL.md R9).
- User asks "这股一手多少", "最小买多少", "tick 多大", "T+1 吗", "what's the
lot size for X", "minimum order for Y".
- A previous order rejected with `INVALID_LOT_SIZE`, `INVALID_TICK_SIZE`, or
`SYMBOL_METADATA_UNAVAILABLE` and you need the parameters to repair.
No confirmation required (read-only).
## Calling
python3 -c "
from scripts._http import Client
print(Client().get('/v1/symbols/600519.SH'))
"
## Response shape
{
"symbol": "600519.SH",
"market": "CN",
"board": "MAIN",
"currency": "CNY",
"lot_size": 100,
"min_qty": 100,
"qty_step": 100,
"tick_size": 0.01,
"t1_stock_rule": true,
"price_limit_pct": 0.10,
"price_cage_pct": null
}
| Field | Meaning |
|-------|---------|
| `market` | `CN` / `HK` / `US` |
| `board` | `MAIN` / `STAR` / `CHINEXT` / `BSE` (CN); board determines lot rule |
| `currency` | Settlement currency for fills/fees |
| `lot_size`, `min_qty` | Minimum order qty; equal in the current model |
| `qty_step` | Valid increments above `min_qty` (CN MAIN 100, STAR/CHINEXT 1 above 200, US 1) |
| `tick_size` | Smallest LIMIT-price increment |
| `t1_stock_rule` | `true` → shares bought today aren't sellable until next trading day |
| `price_limit_pct` | Daily ±N% price band (CN); rejects LIMITs outside it |
| `price_cage_pct` | LIMIT submit-time price cage (STAR/CHINEXT ±2% vs last); `null` if board has no cage |
## Rounding recipe (BUY / SELL)
Use this when the user's qty is not lot-aligned:
meta = Client().get(f'/v1/symbols/{symbol}')
min_q, step = meta['min_qty'], meta['qty_step']
# Round down to the largest valid qty ≤ user_qty
rounded = max(min_q, ((user_qty - min_q) // step) * step + min_q) if user_qty >= min_q else 0
If `rounded == 0` (user asked for less than `min_qty`), tell the user the
minimum and ask whether to proceed at `min_qty`.
If the resulting BUY notional exceeds available cash, fall back further:
fetch the quote, compute `max_affordable_qty`, round that down with the same
formula. Report all three numbers to the user: **original / rounded /
affordable**.
## Error responses
| Code | HTTP | recovery_hint | Action |
|------|------|---------------|--------|
| `SYMBOL_NOT_FOUND` | 404 | fix_input | Unknown market suffix; check symbol code |
| `SYMBOL_METADATA_UNAVAILABLE` | 503 | retry | Metadata not loaded; `_http.py` retries once. If raised, run `references/troubleshooting.md` |
| `RULES_NOT_WIRED` | 500 | retry | Service mis-started; tell user to run `scripts/doctor.py` |