From 27c67ac3b6ae3a3ac2cd3220006e47ac0a65d2d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E7=AB=A0=E6=B4=AA?= Date: Fri, 28 Aug 2026 19:03:35 +0800 Subject: [PATCH] fix(fundamental): send comparison_symbols as a query array (gateway now accepts it) The gateway now supports the comparison_symbols parameter on GET /v1/quote/compare/valuation, expecting a standard HTTP array (repeated keys: comparison_symbols=A&comparison_symbols=B), not a JSON array string. Drop the temporary stopgap that converted the peer symbols to counter-ids and sent the legacy comparison_counter_ids parameter; pass the user symbols straight through as Option>, which the qs serializer emits as repeated keys. Removes the symbol_to_counter_id shim added for the stopgap. Verified live on staging (2/3/4 peers return the stock plus all peers). Note: the gateway fix is on staging first; production still answers this new format with code 13 until its rollout lands. --- rust/src/fundamental/context.rs | 40 ++------------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/rust/src/fundamental/context.rs b/rust/src/fundamental/context.rs index e80dc25b2..7199f962b 100644 --- a/rust/src/fundamental/context.rs +++ b/rust/src/fundamental/context.rs @@ -6,31 +6,6 @@ use tracing::{Subscriber, dispatcher, instrument::WithSubscriber}; use crate::{Config, Market, Result, fundamental::types::*}; -/// Convert a user-facing symbol (e.g. `700.HK`, `AAPL.US`, `HSI.HK`) to the -/// backend counter-id form (e.g. `ST/HK/700`, `ST/US/AAPL`, `IX/HK/HSI`). -/// -/// TODO: temporary shim used only by -/// [`FundamentalContext::valuation_comparison`] while the gateway does not yet -/// accept the `comparison_symbols` parameter. Remove it once the gateway -/// converts the symbols itself, and pass the user symbols straight through. -/// This is a naive best-effort conversion: it maps dotted-index symbols -/// (leading `.`, e.g. `.DJI.US`) to the `IX/` prefix and everything else to -/// `ST/`, so ETF / warrant peers may resolve to the wrong prefix — acceptable -/// because valuation peers are virtually always equities. -fn symbol_to_counter_id(symbol: &str) -> String { - match symbol.rsplit_once('.') { - Some((code, market)) => { - let market = market.to_uppercase(); - if code.starts_with('.') { - format!("IX/{market}/{}", &code[1..]) - } else { - format!("ST/{market}/{code}") - } - } - None => symbol.to_string(), - } -} - /// Convert a Unix-seconds string to RFC 3339. fn unix_secs_str_to_rfc3339(s: &str) -> String { s.parse::() @@ -792,31 +767,20 @@ impl FundamentalContext { currency: impl Into, comparison_symbols: Option>, ) -> Result { - // TODO: The gateway does not yet accept the `comparison_symbols` - // parameter (user symbols). Until it does, keep sending the legacy - // `comparison_counter_ids` parameter and convert the user symbols to - // counter-ids here. Once the gateway supports `comparison_symbols`, - // drop this local conversion and pass the user symbols straight - // through as `comparison_symbols` (serde_json array string) — the - // public API already takes user symbols so no signature change. #[derive(Serialize)] struct Query { symbol: String, currency: String, #[serde(skip_serializing_if = "Option::is_none")] - comparison_counter_ids: Option, + comparison_symbols: Option>, } - let comparison_counter_ids = comparison_symbols.map(|syms| { - let ids: Vec = syms.iter().map(|s| symbol_to_counter_id(s)).collect(); - serde_json::to_string(&ids).unwrap_or_default() - }); let raw: serde_json::Value = self .get( "/v1/quote/compare/valuation", Query { symbol: symbol.into(), currency: currency.into(), - comparison_counter_ids, + comparison_symbols, }, ) .await?;