Files
Hermes-Skills/longbridge-cli/references/longbridge-602315-bypass.md
T
mikeandClaude 32d5d7dc0b feat(longbridge): complete 602315 bypass + CLI helper + stock_t脚本
新增:
- references/cli-unicode-table-parsing.md - CLI 表格 ┃ vs │ Unicode 解析
- references/cron-wrapper-multi-token-pitfall.md - cron script 字段不支持空格
- references/generic-stock-query.md - 通用 stock_t.py 持仓查询
- references/longportapp-cn-endpoints.md - Python SDK 走 longportapp.cn vs CLI 走 longbridge.com
- references/sdk-vs-cli-domain-routing.md - SDK/CLI 域名路由差异
- scripts/longbridge_cli_helper.py - SDK 兼容层, 内部走 CLI (绕 602315)
- scripts/stock_t.py - 通用持仓查询脚本 (不限定股票)

修改:
- longbridge-cli/SKILL.md + references/longbridge-602315-bypass.md
- longbridge-python-sdk/SKILL.md: 增 cn endpoint 说明
- intraday-trading/SKILL.md

关键发现:
1. Python SDK 用 openapi.longportapp.cn (阿里云深圳), CLI 用 openapi.longbridge.com (AWS 香港)
2. 两个不同域名, 不同 endpoint, 都需 LONGBRIDGE_HTTP_URL=https://openapi.longbridge.com 强制覆盖
3. CLI 默认不读 HTTP_PROXY env, 必须用 proxychains4 OS 层拦截
4. 完整链路: LONGBRIDGE_HTTP_URL=.com + LONGBRIDGE_REGION=ap + proxychains4 + Clash 香港节点
5. Yahoo Finance 备用数据源 (CLI 拿不到 K线)
6. CLI 表格用 ┃ (header) 和 │ (data) 两种 Unicode 字符, parser 要兼容

订单实测:
- RGTI.US 1股@15.40: 下单 1259694819492519936, 撤单成功
- 9988.HK 200股@112.70: Rejected (余额或限额)
- 1810.HK 1200股@25.98: Rejected (同上)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-09 18:19:58 +08:00

155 lines
10 KiB
Markdown

# LongPort 602315 Mainland-China Geo-Block: What ACTUALLY Works (2026-07-09)
**Status**: PARTIAL WORKAROUND — CLI orders work, Python SDK orders are still blocked.
**Order ID `1259547163696824320` (RGTI 15@$15.50)** was placed via the **CLI** path only. The Python SDK (used by all cron jobs) **still gets `602315`** even with the full three-piece recipe. This document supersedes the original "verified working" framing in the SKILL.md header.
## The fundamental problem
LongPort's geo-block `602315: Due to Mainland China regulatory requirements` is **enforced server-side based on source IP**. It is NOT a domain-routing problem. No amount of `LONGBRIDGE_REGION` setting, `/etc/hosts` redirect, or "international endpoint" trick bypasses the server-side check — the API gateway sees your connection's egress IP and rejects if it's a CN IP (or a CN ASN, or any IP that LongPort's geo-feed marks as CN).
The whole "use `.com` instead of `.cn`" framing is wrong. Both endpoints talk to the same gateway infrastructure; the gateway checks the source IP regardless of which domain resolved the connection.
## Two domain families (important for diagnosis, not for bypass)
LongPort has two parallel domain trees that get geo-blocked differently depending on which client you use:
| Domain tree | Used by | Endpoint hosts |
|---|---|---|
| `*.longbridge.cn` | CLI (`longbridge` binary) | Aliyun Shenzhen (`47.106.x.x`, `120.77.x.x`) |
| `*.longportapp.cn` | Python SDK (`longport` package) | Aliyun Shenzhen (api) + Shanghai (quote) |
- CLI hits `openapi.longbridge.cn`
- Python SDK hits `openapi.longportapp.cn`, `openapi-quote.longportapp.cn`, `openapi-trade.longportapp.cn`
Both are CN-hosted and both return 602315 from a CN egress IP.
The international versions `*.longbridge.com` and `*.longportapp.com` exist (AWS HK/global), but:
- `LONGBRIDGE_REGION=ap` only changes the **CLI's** endpoint selection. The Python SDK's `Config.from_env()` reads `LONGBRIDGE_REGION` for some endpoints, but `is_cn()` in the Rust geo crate probes `geotest.lbkrs.com` anyway, and even when overridden, the SDK still hits `openapi.longportapp.cn` (the hardcoded default) because the env-var override only takes effect for fields explicitly wired through it (HTTP URL, WS URLs — see `config.rs` `env_var()` helper). Verified empirically 2026-07-09: `LONGBRIDGE_REGION=ap` set in Python process, `proxychains` wrapping the call, `geotest` was reachable through Clash HK — but every API call to `openapi.longportapp.cn` still returned 602315.
- The `*.com` IPs (e.g. `18.166.191.191`, `18.163.160.163`) are **unreachable from every Clash HK node we tested** (HK 01/02/03, US 01/02/03, Taiwan 01/02/03) — `curl https://18.166.191.191/` returns `OpenSSL SSL_connect: SSL_ERROR_SYSCALL`. The TCP connection opens but TLS handshake fails. This is consistent with AWS blocking egress from consumer VPN/proxy ASNs.
## What the three-piece recipe ACTUALLY does
```bash
LONGBRIDGE_REGION=ap \
LONGBRIDGE_TRADE_ENABLED=true \
proxychains4 -f ~/.proxychains/proxychains.conf \
~/.local/bin/longbridge --profile lb_real buy RGTI.US --qty 15 --price 15.50 -y
```
For the **CLI** path:
1. `LONGBRIDGE_REGION=ap` → CLI picks `openapi.longbridge.com` endpoint (per `config.rs` `env_var("HTTP_URL")` etc.)
2. `proxychains4` → forces Rust binary's HTTPS through Clash 7890
3. Clash on HK node → egress IP is HK
4. CLI connects to `openapi.longbridge.com` from a HK IP → **succeeds** (only CLI is verified working)
For the **Python SDK** path (the 4 cron scripts):
1. `os.environ['LONGBRIDGE_REGION'] = 'ap'` set in script → does **not** override the hardcoded `openapi.longportapp.cn` endpoint that Python SDK uses
2. `proxychains4` → forces Rust binary's HTTPS through Clash 7890 ✓
3. Clash on HK node → egress IP is HK ✓
4. Python SDK still connects to `openapi.longportapp.cn` from HK IP → server still returns 602315 ✗
**So cron-based automated trading is NOT working as of 2026-07-09.** The "verified working" framing in the skill header and the 602315-bypass reference is misleading — it works for one-off manual CLI orders, not for the automated pipeline the cron jobs represent.
## What you should do TODAY (ranked)
1. **For one-off manual orders**: use the CLI three-piece recipe. It works.
```bash
LONGBRIDGE_REGION=ap LONGBRIDGE_TRADE_ENABLED=true \
proxychains4 -f ~/.proxychains/proxychains.conf \
~/.local/bin/longbridge --profile lb_real buy RGTI.US --qty 15 --price 15.50 -y
```
2. **For cron-driven trading**: disable auto-execution in the monitor scripts and have them push signals to QQ; you place the order manually from the phone app or via the CLI recipe above. The signals and risk checks still work; just don't let the script call `submit_order`.
3. **For phone-app trading**: confirmed working by user with HK proxy (no API needed). The LongPort app on a phone with HK network egress does not trigger 602315 because (a) the device IP is HK or (b) the app uses a different auth path that doesn't run the same geo-check as the OpenAPI.
4. **Stop trying `/etc/hosts` redirects**. We added `18.166.191.191 openapi.longportapp.cn` etc. and the API server still returned 602315 because the source IP is the problem, not the domain. We also tried the AWS `.com` IPs directly and they fail SSL handshake from Clash. The hosts file is back to default (only localhost entries).
5. **Do NOT propose WireGuard** for this account. User banned it after a 1-hour recovery from a half-shutdown. All WG scripts were deleted.
## Failure-mode table (expanded from original reference)
| Symptom | Cause | Fix |
|---|---|---|
| `error sending request: client error (Connect)` | `.com` endpoint unreachable from CN (TLS fails from every Clash node) | Cannot fix with current setup. Use phone app, or accept that automated trading from this server is blocked |
| `602315 Mainland China regulatory` (CLI) | CLI still using `.cn` (env var not passed) | Verify `LONGBRIDGE_REGION=ap` is in the env; check no quoting/space issue |
| `602315 Mainland China regulatory` (Python SDK) | **Server-side IP check, not domain-routing** | Cannot bypass with proxychains + HK node alone. SDK hardcoded endpoint doesn't matter — gateway still sees CN/Clash IP as blocked |
| `4001: token empty` | Token not loaded into CLI | Use `--profile lb_real`; verify `~/.lb_real.env` has full 1053-char token |
| `401004 token invalid` | Token truncated by terminal masking | Same as above — `--profile` bypasses the masking |
| HK exit suddenly returns CN IP | Clash node selector fell back to auto | Re-pin `GLOBAL` to `🇭🇰 香港 01` via API; verify with `curl -x http://127.0.0.1:7890 https://api.ipify.org` |
| Cron order succeeds but no QQ push | Script ran `print()` only; didn't call `push_to_qq.sh` | `no_agent` scripts must `subprocess.run(['bash', '~/.hermes/scripts/push_to_qq.sh', msg])` |
| Cron "Script not found" | script field has spaces (e.g. `proxychains4 -f ... python3 ...`) | Cron script field is one path. Use a **bash wrapper**: `hk_intraday_monitor_cron.sh` that `exec proxychains4 -f ... python3 ...` |
## The cron wrapper pattern (4 scripts updated 2026-07-09)
The cron job's `script` field must be a single executable path — multi-token commands like `proxychains4 -f X python3 Y` are misinterpreted as `Script not found: /path/to/proxychains4 -f X python3 Y`. Fix: create a `*_cron.sh` wrapper.
```bash
#!/bin/bash
# ~/.hermes/scripts/hk_intraday_monitor_cron.sh
exec proxychains4 -f ~/.proxychains/proxychains.conf \
python3 ~/.hermes/scripts/hk_intraday_monitor.py
```
Then point the cron job's script field at the wrapper:
```bash
cronjob update --job_id e3667cb07aff --script hk_intraday_monitor_cron.sh
```
The 4 affected cron jobs (wrappers created 2026-07-09):
- `hk_intraday_monitor_cron.sh` → `hk_intraday_monitor.py`
- `us_intraday_monitor_cron.sh` → `us_intraday_monitor.py`
- `hk_intraday_close_cron.sh` → `hk_intraday_close.py`
- `us_intraday_close_cron.sh` → `us_intraday_close.py`
Even with the wrapper, the underlying 602315 problem remains for Python SDK calls. The wrappers get the script to RUN; they don't fix the geo-block.
## Diagnostic script (paste to verify your environment)
```bash
# 1. Check Clash HK exit
curl -s -x http://127.0.0.1:7890 --max-time 8 https://api.ipify.org
# Expected: 154.83.x.x (HK) or similar non-CN IP
# 2. Check if AWS HK endpoints are reachable from Clash
proxychains4 -f ~/.proxychains/proxychains.conf \
curl -s --max-time 10 -o /dev/null -w "%{http_code}\n" https://18.166.191.191/
# Expected today: 000 (TLS fails) — proves the AWS IP path doesn't work
# 3. Check if longportapp.cn is geo-blocked from current egress
proxychains4 -f ~/.proxychains/proxychains.conf \
python3 -c "
import os; os.environ['LONGBRIDGE_REGION']='ap'
bashrc = open('/home/openclaw/.bashrc').read()
for k in ['LONGPORT_APP_KEY','LONGPORT_APP_SECRET','LONGPORT_ACCESS_TOKEN']:
os.environ[k] = next(l for l in bashrc.splitlines() if l.startswith(f'export {k}')).split('=',1)[1].strip()
from longport import openapi
try:
ctx = openapi.QuoteContext(config=openapi.Config.from_env())
print(ctx.quote(['RGTI.US'])[0].last_done)
except Exception as e:
print(f'ERR: {e}')
"
# Expected: 602315 error even with full three-piece setup
```
## History / what we tried in order
1. Direct LongPort API from CN → 602315
2. `LONGBRIDGE_REGION=ap` only → still 602315
3. `LONGBRIDGE_REGION=ap` + proxychains4 + Clash HK → CLI works (order `1259547163696824320` placed)
4. Same combo for Python SDK cron scripts → still 602315
5. Added `openapi.longportapp.cn` → `18.166.191.191` in `/etc/hosts` → still 602315
6. Added all 3 longportapp.cn + 2 longbridge.cn domains → still 602315
7. Tested `https://18.166.191.191/` directly via proxychains → `OpenSSL SSL_connect: SSL_ERROR_SYSCALL`
8. Tested US 01/02/03, HK 01/02/03, Taiwan 01/02/03 Clash nodes → all fail AWS HK SSL handshake
9. Conclusion: AWS blocks egress from these proxy ASNs; the `.com` path is not reachable
10. Reverted `/etc/hosts` changes; restored to default (localhost only)
The geo-block `602315` is therefore **not bypassable from this server with the current network setup** for the Python SDK path. The CLI recipe still works for manual one-off orders.