ZhuLinsen/daily_stock_analysis · error · FutuPortfolioError
Futu OpenD 地址无效
Error message
Futu OpenD 地址无效: {host!r}:{port} What it means
FutuPortfolioError raised in _connection_settings (src/brokers/futu/portfolio.py:125) when the OpenD host is empty after stripping, or the parsed port is outside 1..65535. Host defaults to 127.0.0.1 and port to 11111, so this only fires when explicitly configured values are out of range — e.g. port 0, 70000, or FUTU_OPEND_HOST set to only whitespace.
Solutions
- Use port 11111 (stock OpenD API port) or your OpenD instance's actual listening port within 1-65535.
- Set FUTU_OPEND_HOST to the machine running OpenD (127.0.0.1 for local; an IPv4 LAN address for remote) and ensure it is non-empty.
- Unset both variables if the defaults are correct, which eliminates misconfiguration entirely.
Example fix
# before (.env) FUTU_OPEND_HOST= FUTU_OPEND_PORT=70000 # after (.env) FUTU_OPEND_HOST=127.0.0.1 FUTU_OPEND_PORT=11111
Defensive patterns
Strategy: validation
Validate before calling
def valid_opend_address(host: str | None, raw_port: str | None) -> bool:
h = (host or '127.0.0.1').strip()
p = (raw_port or '11111').strip()
try:
port = int(p)
except ValueError:
return False
return bool(h) and 1 <= port <= 65535 Prevention
- Use the OpenD default pair 127.0.0.1:11111 unless you know otherwise.
- Never put host and port in the same variable.
- Fail fast on config parse at startup rather than deep inside broker calls.
When it happens
Trigger: FUTU_OPEND_PORT=0 or >65535 (e.g. accidentally using an OpenD PID or a documentation port like 99999); FUTU_OPEND_HOST=' ' (spaces only) which strips to empty; swapping host and port values in configuration.
Common situations: Copy-paste from OpenD docs listing WebSocket ports above 65535; template variables that expand to empty; confusing OpenD's API port with its GUI/protocol ports.
Related errors
- FUTU_ACC_ID 必须是正整数账户 ID
- FUTU_OPEND_PORT 不是有效端口
- 不支持的 FUTU_SECURITY_FIRM
- FUTU_ACC_ID 未匹配到可用的真实证券账户;请检查账户 ID、券商和 OpenD 登录状态。
- futu-api==10.8.6808 的网络层仅支持 IPv4;FUTU_OPEND_HOST 当前为
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/89b3257568efc5b1.
Report an issue: GitHub.
Appendix: source
Thrown at src/brokers/futu/portfolio.py:125
if context is None:
return
try:
context.close()
except Exception: # pragma: no cover - closing is best effort
logger.debug("关闭 Futu OpenD 连接失败", exc_info=True)
def _connection_settings() -> tuple[str, int]:
"""Return the validated IPv4 OpenD host and port from environment settings."""
host = (os.getenv("FUTU_OPEND_HOST") or "127.0.0.1").strip()
raw_port = (os.getenv("FUTU_OPEND_PORT") or "11111").strip()
try:
port = int(raw_port)
except ValueError as exc:
raise FutuPortfolioError(f"FUTU_OPEND_PORT 不是有效端口: {raw_port!r}") from exc
if not host or not 1 <= port <= 65535:
raise FutuPortfolioError(f"Futu OpenD 地址无效: {host!r}:{port}")
address_text = host[1:-1] if host.startswith("[") and host.endswith("]") else host
try:
address = ipaddress.ip_address(address_text)
except ValueError:
address = None
if address is not None and address.version != 4:
raise FutuPortfolioError(
"futu-api==10.8.6808 的网络层仅支持 IPv4;"
f"FUTU_OPEND_HOST 当前为 {host!r},请改用 IPv4 地址或可解析到 IPv4 的主机名。"
)
return host, port
def _configured_account_id() -> Optional[int]:
"""Return the optional configured real account ID."""
value = (os.getenv("FUTU_ACC_ID") or "").strip()View on GitHub (pinned to 5159bd72e8)