trading: 日内T/长桥/六合彩文档与脚本 + quant-factor-mining 新目录

This commit is contained in:
2026-09-25 01:25:38 +08:00
parent 734b168082
commit 3f17a4eb1f
23 changed files with 1821 additions and 376 deletions
+33 -2
View File
@@ -1,6 +1,6 @@
---
name: longbridge-python-sdk
description: LongPort Python SDK — 行情、持仓、自选、估值指标(PE/PB/股息率/EPS/BPS)、资金流向。支持港股/美股/A股。bashrc已有LONGPORT_*变量,可直接Config.from_env()。
description: LongPort Python SDK — 行情、持仓、自选、估值指标(PE/PB/股息率/EPS/BPS)、资金流向。支持港股/美股/A股/期权(0DTE)。bashrc已有LONGPORT_*变量,可直接Config.from_env()。期权字段有 ImpliedVolatility/Delta/Gamma/Theta/Vega/Rho/StrikePrice/OutstandingQty/OpenInterest 等 Greeks + 期权链 `option_chain_info_by_date` + 单腿报价 `option_quote`。
---
# LongPort Python SDK Usage
@@ -310,6 +310,19 @@ resp = openapi.submit_order( # via longbridge buy --profile lb_real
This is the migration path for any cron script that used to call `trade_ctx.submit_order()` directly. **Read operations** (quote, candlesticks, balance, positions) still work fine through the Python SDK — keep them. Only the order placement needs the helper.
## Common Pitfalls
- 🔴 **[2026-09-07] `QuoteContext()` SDK prints 9 quote-permission tables to stdout on every init** — pollutes cron pushes. Each `QuoteContext(config=...)` (or `Config.from_env()`) prints a 4-row table showing tier/access for HK/US/CN/USOption, then a `+---...+` separator, then a `|---` row — repeated ~9 times when a script constructs multiple contexts (e.g. fallback logic). **Fix in cron wrappers** (e.g. `dividend_alert_cn_hk.sh`):
```bash
python3 script.py 2>&1 \
| grep -v "^\[proxychains\]" \
| grep -vE "^\+\-\-\-.*\+$" \ # filter +---+ separator rows
| grep -vE "^\|\-\-\-\-" \ # filter |--- rows
| grep -vE "^\| (US|HK|CN|USOption) +\| +[A-Za-z]" # filter data rows of permission table
```
These filter rules distinguish the longport SDK's permission table (only `[A-Za-z ]+` on right side) from real data tables (contain Chinese 票号/名称 like `| 💎603165 | 荣晟环保 |`). Don't filter data tables — they have emojis/Chinese.
- ⚠️ **`symbol` starting with digit + python3 -c**: same as the HK stock code pitfall below — if a script embeds a symbol literal like `823.HK` in a python heredoc inside bash, `python3 -c` will fail with decimal literal error. Always write to `/tmp/script.py` first. Longport `security_list` returns `symbol` strings like `823.HK` — keep them as string vars, never as literals in `-c` form.
- 🔴 **Token expiry 401003/401004**: see existing pitfalls below for the bashrc-parsing fallback. The error is server-rejected; the bashrc parsing fallback helps when `Config.from_env()` can't find the var. After 401003, run `bash ~/.hermes/scripts/update_longbridge_token.sh <new_token>` to update all locations (bashrc + .env + CLI profile).
## Valuation Metrics (calc_indexes)
Get PE, PB, dividend yield, market cap via `CalcIndex` enum:
@@ -420,7 +433,25 @@ candles = ctx.history_candlesticks_by_offset(
- **python3 -c with HK Stock Codes**: HK codes like `1088.HK`, `3988.HK` start with digits. Python parses them as `1088.HK` → decimal literal error. **Never use `python3 -c` for scripts containing HK stock codes.** Always write to a temp file (`/tmp/script.py`) and run `python3 /tmp/script.py` instead. Same applies to any identifier starting with a digit.
- **`quote()` fields**: `SecurityQuote` has `last_done`, `prev_close`, `volume`, `turnover`, `symbol`. It does **NOT** have `change_rate` — use `calc_indexes` with `CalcIndex.ChangeRate` for price change %. Gotcha: accessing `q.change_rate` raises `AttributeError: 'SecurityQuote' object has no attribute 'change_rate'`.
- **CLI Token Masking (Critical)**: The `terminal` tool masks/redacts secrets from environment variables, causing the `longbridge` CLI to get truncated tokens → 401004/403201 errors. **The Python SDK always works** because scripts read bashrc directly via `open()` and set `os.environ` programmatically. When CLI fails but SDK works, this is why. Always prefer `execute_code` + SDK over `terminal` + CLI for any order/trade operation.
- **🔴 [2026-07-09] The `LONGBRIDGE_REGION=ap` env var is unreliable in the Python wheel.** The Python SDK ignores it for the hardcoded `openapi.longportapp.cn` endpoints — proxychains logs from cron runs (e.g. `hk_intraday_monitor_cron.sh`) show requests still routed to `openapi.longportapp.cn:443` even with the env var set. Result: cron-driven `submit_order()` calls return `602315` despite the three-piece recipe. The CLI version of the same env var works because the CLI binary is a separate Go/Rust process that does honor the override. **Use the CLI for any order you actually want to fill; the Python SDK is for monitoring/quoting only until this is fixed upstream.** See `references/longportapp-cn-endpoints.md` for the full diagnosis.
- 🔴 [2026-07-09] The `LONGBRIDGE_REGION=ap` env var is unreliable in the Python wheel.** The Python SDK ignores it for the hardcoded `openapi.longportapp.cn` endpoints — proxychains logs from cron runs (e.g. `hk_intraday_monitor_cron.sh`) show requests still routed to `openapi.longportapp.cn:443` even with the env var set. Result: cron-driven `submit_order()` calls return `602315` despite the three-piece recipe. The CLI version of the same env var works because the CLI binary is a separate Go/Rust process that does honor the override. **Use the CLI for any order you actually want to fill; the Python SDK is for monitoring/quoting only until this is fixed upstream.** See `references/longportapp-cn-endpoints.md` for the full diagnosis.
- 🔴 [2026-08-02] **HTTP endpoint env var: `LONGPORT_HTTP_URL` (not `LONGBRIDGE_HTTP_URL`).** The SDK ignores `LONGBRIDGE_HTTP_URL` (only the CLI uses it). Cron scripts that set `LONGBRIDGE_HTTP_URL` for the SDK are silently ignored — SDK defaults to `openapi.longportapp.cn`. When the .cn endpoint is down (e.g. 2026-08-04 11:30 cron failure), there's no fallback. **Fix**: always set `LONGPORT_HTTP_URL=https://openapi.longportapp.cn` (or `https://openapi.longbridge.com`) in cron wrappers. Pair with **.cn → .com fallback** in the Python init function: try `.cn` first (China DNS resolves), fall back to `.com` (AWS CloudFront) if `.cn` fails. Pattern in `cn_dividend_buy_timing.py`:
```python
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'},
]
for c in configs:
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']
try:
ctx = openapi.QuoteContext(config=openapi.Config.from_env())
ctx.quote(['600000.SH']) # test connection
return ctx, openapi.Period
except Exception:
continue # try next
```
**Compiled failure mode (`OpenApiException: client error (Connect)`)**: 502 Bad Gateway from Aliyun load balancer — short-lived, retry with the .com fallback handles it.
- **China Mainland Geo-Block (Error 602315)**: LongPort API blocks trading from mainland China IPs. The verified-working bypass is the **CLI three-piece recipe** (see `references/longbridge-602315-bypass.md` in the `longbridge-cli` skill). The Python SDK three-piece recipe is **not currently working** as of 2026-07-09 — see the section "⚠️ CRITICAL: Mainland China Access (602315) — PARTIAL workaround" at the top of this skill. WireGuard is NOT a viable alternative (Ubuntu shutdown unreliable, banned by user).
- **API Rate Limiting (429002)**: LongPort enforces per-app request frequency limits. Error: `api request is limited, please slow down request frequency` (code 429002). **Root cause**: multiple scripts hitting the API simultaneously (e.g. DCA monitor + price alert both running at :00). **Fix**: (1) Stagger cron schedules by ≥15 minutes between LongPort-calling jobs; (2) Reduce polling frequency — 30min is enough for price monitoring, don't use 10/15min intervals; (3) Use market filters (`--market=us/hk/cn`) to reduce per-run API calls; (4) Add exponential backoff retry in scripts for transient 429 errors.
- **`source ~/.bashrc` doesn't work in terminal tool**: The terminal tool runs each command in a fresh shell that doesn't persist env vars from `source ~/.bashrc`. If `Config.from_env()` fails with "missing environment variable: LONGPORT_APP_KEY", use a Python script to parse bashrc directly:
@@ -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