ZhuLinsen/daily_stock_analysis · error · FutuPortfolioError
Futu OpenD 地址无效: {host!r}:{port}
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.
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)
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_OPEND_PORT 不是有效端口: {raw_port!r}
- FUTU_ACC_ID 必须是正整数账户 ID
- 不支持的 FUTU_SECURITY_FIRM: {name}
- TUSHARE_HTTP_URL 必须以 http:// 或 https:// 开头,当前值为 {url!r}
- 加载 Futu OpenAPI SDK 失败: {exc}
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/89b3257568efc5b1.
Report an issue: GitHub.