ZhuLinsen/daily_stock_analysis · error · FutuPortfolioError
查询 Futu 真实账户失败: {exc}
Error message
查询 Futu 真实账户失败: {exc} What it means
FutuPortfolioError raised at src/brokers/futu/portfolio.py:215 as the catch-all translation around the whole account-discovery block: any exception that is not already a FutuPortfolioError (SDK runtime errors, socket failures, protobuf decode errors, pandas errors) is re-raised with the '查询 Futu 真实账户失败' prefix and the original exception chained via 'from exc'.
Source
Thrown at src/brokers/futu/portfolio.py:215
raise FutuPortfolioError(
"Futu 账户查询返回了无效账户 ID"
) from exc
if isinstance(raw_acc_id, bool) or not exact_integer or acc_id <= 0:
raise FutuPortfolioError("Futu 账户查询返回了无效账户 ID")
if acc_id in seen_ids:
continue
returned_firm_name = _enum_text(row.get("security_firm"))
returned_firm = getattr(
api.SecurityFirm,
returned_firm_name,
security_firm,
)
seen_ids.add(acc_id)
accounts.append(_FutuAccount(acc_id=acc_id, security_firm=returned_firm))
except FutuPortfolioError:
raise
except Exception as exc: # noqa: BLE001 - translate SDK/network failures
raise FutuPortfolioError(f"查询 Futu 真实账户失败: {exc}") from exc
finally:
_safe_close(context)
if requested_acc_id is not None:
accounts = [account for account in accounts if account.acc_id == requested_acc_id]
if not accounts:
raise FutuPortfolioError(
"FUTU_ACC_ID 未匹配到可用的真实证券账户;请检查账户 ID、券商和 OpenD 登录状态。"
)
if not accounts:
raise FutuPortfolioError(
"未找到状态为 ACTIVE 的 Futu REAL 普通或 MASTER 证券账户"
)
return accounts
def _load_position_codes(View on GitHub (pinned to 5159bd72e8)
Solutions
- Read the chained original exception (raise ... from exc preserves it) — it names the real failure; fix that root cause first.
- Verify OpenD stability: is it up, logged in, and does a minimal standalone get_acc_list() with futu-api==10.8.6808 succeed?
- If the failure is transient network drop, retry the portfolio fetch after confirming connectivity.
- Check that only one context set is used at a time (the code closes contexts via _safe_close; external long-lived contexts can conflict).
Example fix
# before
accounts = portfolio.discover_accounts(api, host, port)
# after — surface root cause and retry once on transient network errors
import socket
try:
accounts = portfolio.discover_accounts(api, host, port)
except FutuPortfolioError as exc:
root = exc.__cause__ or exc
if isinstance(root, (socket.timeout, ConnectionError)):
accounts = portfolio.discover_accounts(api, host, port) # one retry
else:
raise Defensive patterns
Strategy: try-catch
Validate before calling
import socket
def opend_healthy(host: str, port: int) -> bool:
try:
with socket.create_connection((host, port), timeout=2.0):
return True
except OSError:
return False Try / catch
from src.brokers.futu.portfolio import FutuPortfolioError
import socket
try:
accounts = discover(api, host, port)
except FutuPortfolioError as exc:
root = exc.__cause__
if isinstance(root, (socket.timeout, ConnectionError)):
accounts = discover(api, host, port) # bounded single retry
else:
raise Prevention
- Inspect exc.__cause__: the wrapper preserves the real SDK/network exception.
- Probe OpenD connectivity before long broker workflows.
- Avoid running multiple concurrent OpenSecTradeContext sessions against one OpenD.
When it happens
Trigger: OpenD connection drops mid-query (socket.timeout, ConnectionResetError); SDK internal errors while opening OpenSecTradeContext; protobuf/pandas failures while processing get_acc_list output; any unexpected exception inside the discovery loop.
Common situations: Flaky network to a remote OpenD; OpenD restarting during the query; resource exhaustion (too many open contexts); SDK bugs triggered by unusual payloads.
Related errors
- 查询 Futu 真实账户失败: {data}
- 查询 Futu 真实持仓失败: {data}
- futu-api==10.8.6808 的网络层仅支持 IPv4;FUTU_OPEND_HOST 当前为 {host!r
- 未找到状态为 ACTIVE 的 Futu REAL 普通或 MASTER 证券账户
- 查询 Futu 真实持仓失败: {exc}
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/3af92cfc8f9dafda.
Report an issue: GitHub.