feat(symbol)!: send symbols instead of counter_ids, add multi-leg orders - #128
Draft
sunli829 wants to merge 1 commit into
Draft
feat(symbol)!: send symbols instead of counter_ids, add multi-leg orders#128sunli829 wants to merge 1 commit into
sunli829 wants to merge 1 commit into
Conversation
The backend now resolves user-facing symbols itself, so this server no
longer converts between `TSLA.US` and `ST/US/TSLA` in either direction.
Request path: `src/counter.rs` (a re-export of the SDK's conversion
helpers, backed by a 25,590-line embedded ETF/index/warrant directory) is
gone. All 55 call sites pass the caller's symbol through, and the 61
`counter_id` query parameters become `symbol` / `symbols`. Parameter names
follow the SDK for the 44 endpoints it wraps; the remaining raw endpoints
were each confirmed against a live environment.
Response path: wherever the backend still returns a `counter_id` it
returns the matching `symbol` alongside it, so `counter_id` is now passed
through untouched. Renaming it would emit the key `symbol` twice — which
the old transform already did on `/v1/quote/short-positions/*`. Also
replaces `looks_like_counter_id` with `is_field_name`, so a map keyed by
symbol (`{"symbols": {"AAPL.US": …}}`) is no longer mangled into
`a_a_p_l._u_s` by the snake_case pass.
Without a local directory nothing distinguishes an ETF from an index or a
stock before the call, so `is_etf` is gone and upstream decides instead:
- `constituent` asks for the ETF asset allocation first and falls back to
index constituents on an empty answer. Verified live: ETFs return four
allocation groups, indexes and stocks return none.
- `dividend` always uses `company-dividends`, which covers ETFs and
returns a superset of `etf-dividend-info` (same TTM figures and
fiscal-year rows, plus payout ratios and individual payout events).
This also fixes the ETF branch's response not matching the declared
`DividendResponse` schema.
Callers must pass canonical symbols: the backend matches HK codes exactly,
so `00700.HK` is not `700.HK` and comes back as an empty record.
Also adds `submit_multileg_order`, exposing the SDK's multi-leg option
combination orders (vertical spreads, straddles, strangles, collars,
covered calls/puts) as the 164th tool, scoped under `trade.write`.
BREAKING CHANGE: tool responses no longer rename `counter_id` to `symbol`
or rewrite its value; `symbol` now comes from the backend directly.
sunli829
marked this pull request as draft
August 26, 2026 06:59
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requests become symbol-based end to end, the embedded ETF directory and the
counter_idconversion go away in both directions, andsubmit_multileg_orderis added.
Two things must land before this can ship:
Cargo.tomlpoints atlongbridge/openapi@feat/remove-counter-id-conversion,not
main. That branch carries the symbol-based request contract (it is alsowhere the 25,590-line
US-ETF.csv/US-IX.csv/US-WT.csvdirectory wasdeleted). Switch back to
mainonce it merges there.symbol=yet. Verified directly: productionanswers
/v1/quote/index-constituents?symbol=…withinvalid GetIndexConstituentsReq.CounterId, returns an empty record fromcomp-overview, and 500s onetf-dividend-info. Only canary serves the newcontract today, so merging this before the backend rolls out will break every
symbol-taking tool.
Request path
src/counter.rs— a re-export of the SDK's conversion helpers backed by theembedded directory — is deleted. All 55 call sites now pass the caller's symbol
straight through, and the 61
counter_idquery parameters becomesymbol/symbols.Parameter names are not guesswork:
symbol;symbolsforcompany-professionalsandsharelists/{id}/items;comparison_symbolsforcompare/valuation).canary — all accept
symbol=.POST /v1/quant/run_scriptreturnscode=14forsymbolandcounter_id, with several script bodies. Thefailure is symmetric, so it is not a parameter problem, but the endpoint is
unavailable on canary. It sends
symbolfor consistency.Response path
Wherever the backend still returns a
counter_id, it returns the matchingsymbolalongside it, socounter_idis now passed through untouched. Thisfixes a live bug: the old rename emitted the key twice.
looks_like_counter_idis replaced byis_field_name, which keeps anynon-identifier map key out of the snake_case pass. That fixes a second live bug —
the backend's new symbol-keyed map was being mangled:
serialize/counter_id.rs,counter_id_to_symbolandFieldKind::CounterId(s)are all removed.
No local ETF table, so upstream decides
Nothing distinguishes an ETF from an index or a stock before the call any more,
so
is_etfis gone. Its two callers were reworked and both were checked againstlive data first:
constituentasks for the ETF asset allocation first and falls back to indexconstituents on an empty answer. The existing fallback was already there; only the
is_etfguard was removed. Production data:etf-asset-allocationSPY.US/QQQ.US/2800.HKinfo[4].DJI.US/.IXIC.US/HSI.HKinfo[0]AAPL.US/700.HK/MSFT.USinfo[0]Order matters and is preserved:
SPY.USalso resolves onindex-constituents(503 rows), so asking that first would shadow the allocation.
dividenddrops the ETF branch entirely and always usescompany-dividends."Try the ETF endpoint, fall back when empty" does not work here — measured on
production,
etf-dividend-infoanswers for plain stocks too (AAPL.US→dividend_ttm=1.06,dividend_frequency=4), so it would never fall back. Butcompany-dividendsturns out to be a strict superset for ETFs:Same figures, more fields. This also removes a schema wart: the ETF branch's
response never matched the declared
DividendResponse, which only models thegeneric and US-company shapes.
Input contract
Callers must pass canonical symbols. The backend matches HK codes exactly, and a
padded code fails silently —
200with an empty record, not an error:The old conversion used to strip that padding. Normalizing it here was considered
and deliberately rejected:
700.HKis the required input form.New tool:
submit_multileg_orderWraps the SDK's
submit_multileg(POST /v1/trade/order/multileg) — verticalspreads, straddles, strangles, collars, covered calls/puts. All legs are submitted
as one strategy order. Scoped under
trade.write, excluded from/v2like theother order-write tools, with zh-CN / zh-HK descriptions. Input validation covers
empty
legs, an unknownstrategy, and a non-positiveratio_quantity(legdirection comes from
strategy+side, so the sign carries no meaning and theserver rejects it with
602001).Tool count 163 → 164 across
README.mdandserver.json.Verification
cargo +nightly fmt --check,cargo clippy --all-features --all-targets(0 warnings),
cargo test(144 passed).server now emits for every migrated tool; those 52 requests were then replayed
against canary: 48/50 GET OK, 0 endpoints still demanding
counter_id, plusPOST /v1/dailycoins/batch-check-supportwithsymbolsOK.option-volume-stats/daily500s on every combination of symbol and timestampand 500s identically with
counter_id=, while its non-daily sibling succeedswith the same symbol;
quant/run_scriptis the unverified endpoint above.(
POST /v1/notify/reminders,dailycoins/create,sharelists/{id}/items);their parameter names come from the SDK branch.
submit_multileg_orderwas driven end to end through the MCP server andproduced exactly the SDK's request body.
🤖 Generated with Claude Code