Files
Hermes-Skills/longbridge-python-sdk/references/longrun-http-endpoint-fallback.md
T

4.0 KiB

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):

# 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:

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