# LongPort HTTP Endpoint Fallback (2026-08-02) ## Problem Cron scripts that use the LongPort Python SDK fail with: ``` longport.OpenApiException: error sending request for url (https://openapi.longportapp.cn/v1/socket/token): client error (Connect) ``` The script set `LONGBRIDGE_HTTP_URL`, but the SDK silently ignores it and uses the default `openapi.longportapp.cn`. When the .cn endpoint is down (Aliyun load balancer 502), the cron fails. ## Root Cause The SDK's `Config.from_env()` reads **`LONGPORT_HTTP_URL`**, NOT `LONGBRIDGE_HTTP_URL`. The CLI uses `LONGBRIDGE_*`; the Python SDK uses `LONGPORT_*`. This is a frequent bug because: 1. The CLI's documentation uses `LONGBRIDGE_*` 2. The Python wheel's type stubs (`.pyi`) document `LONGPORT_*` 3. Scripts often copy bashrc exports (`LONGBRIDGE_*`) and assume they work ## Fix Pattern Always set **both** env vars in cron wrappers (they don't conflict): ```bash # In the wrapper script (e.g. cn_dividend_buy_timing_cron.sh): export LONGPORT_HTTP_URL=https://openapi.longportapp.cn export LONGPORT_QUOTE_WS_URL=wss://openapi-quote.longportapp.cn export LONGPORT_TRADE_WS_URL=wss://openapi-trade.longportapp.cn export LONGPORT_LANGUAGE=zh-CN ``` ## Fallback Pattern (Python init) When the .cn endpoint is down, try the .com endpoint: ```python def get_longbridge(): """带重试的长桥 SDK init - 优先 .cn (国内), fallback .com (海外)""" import time load_longbridge_env() configs = [ { 'http': 'https://openapi.longportapp.cn', 'quote_ws': 'wss://openapi-quote.longportapp.cn', 'trade_ws': 'wss://openapi-trade.longportapp.cn', }, { 'http': 'https://openapi.longbridge.com', 'quote_ws': 'wss://openapi-quote.longbridge.com/v2', 'trade_ws': 'wss://openapi-trade.longbridge.com/v2', }, ] from longport import openapi last_err = None for i, c in enumerate(configs): try: os.environ['LONGPORT_HTTP_URL'] = c['http'] os.environ['LONGPORT_QUOTE_WS_URL'] = c['quote_ws'] os.environ['LONGPORT_TRADE_WS_URL'] = c['trade_ws'] os.environ.setdefault('LONGPORT_LANGUAGE', 'zh-CN') cfg = openapi.Config.from_env() ctx = openapi.QuoteContext(config=cfg) try: ctx.quote(['600000.SH']) # test connection except Exception as e: last_err = e if i < len(configs) - 1: print(f"[longbridge] {c['http']} quote 失败: {e}, 重试下一节点", flush=True) time.sleep(1) continue else: return ctx, openapi.Period print(f"[longbridge] 使用 {c['http']} ✓", flush=True) return ctx, openapi.Period except Exception as e: last_err = e print(f"[longbridge] {c['http']} init 失败: {e}", flush=True) if i < len(configs) - 1: time.sleep(1) continue raise last_err or RuntimeError("长桥 SDK init 全部失败") ``` ## Test 2026-08-02: cron `8000d3cfed23 cn-dividend-buy-timing` failed at 11:30 with `OpenApiException: client error (Connect)`. After applying the fix: - `.cn` (Aliyun) endpoint came back online — script ran successfully - `longrun_http_url=https://openapi.longportapp.cn` printed ✓ ## Open Questions - Are `.cn` and `.com` endpoints actually interchangeable? E.g. do quotes for the same symbol return identical data? The fallback assumes yes; not verified. - Could there be a subtle difference between the SDK's hardcoded `openapi.longportapp.cn` and the user-configured one? E.g. token validation, rate limits, etc.? ## Files Touched - `~/.hermes/scripts/cn_dividend_buy_timing.py` — get_longbridge() with fallback - `~/.hermes/skills/trading/lottery-hk/scripts/lottery_4frame.py` — same idempotent init - `~/.hermes/scripts/cn_dividend_buy_timing_cron.sh` — wrapper sets LONGPORT_* env vars