文件预览

symbols.md

查看 paper-test2 技能包中的文件内容。

文件内容

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` |