trading: 日内T/长桥/六合彩文档与脚本 + quant-factor-mining 新目录
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user