ZhuLinsen/daily_stock_analysis · error · FutuPortfolioError
Futu 账户查询返回了无效账户 ID
Error message
Futu 账户查询返回了无效账户 ID
What it means
FutuPortfolioError raised in _discover_real_accounts (src/brokers/futu/portfolio.py:197) when the acc_id cell of a get_acc_list row cannot be converted to int — int() raises TypeError (None/missing cell), ValueError (non-numeric string like 'N/A'), or OverflowError (float infinity). This indicates the OpenD/SDK response is malformed, since account IDs are always numeric.
Source
Thrown at src/brokers/futu/portfolio.py:197
)
ret, data = context.get_acc_list()
if ret != api.RET_OK:
raise FutuPortfolioError(f"查询 Futu 真实账户失败: {data}")
for row in _iter_rows(data, "Futu 账户查询"):
if _enum_text(row.get("trd_env")) != "REAL":
continue
if _enum_text(row.get("acc_status")) != "ACTIVE":
continue
if _enum_text(row.get("acc_role")) not in _SUPPORTED_ACCOUNT_ROLES:
continue
raw_acc_id = row.get("acc_id")
try:
acc_id = int(raw_acc_id)
exact_integer = isinstance(raw_acc_id, str) or bool(
raw_acc_id == acc_id
)
except (TypeError, ValueError, OverflowError) as exc:
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 excView on GitHub (pinned to 5159bd72e8)
Solutions
- Align versions: use futu-api==10.8.6808 with a compatible OpenD build (check Futu's version matrix).
- Restart OpenD to clear degraded session state, then retry the account query.
- Log the raw row (row.to_dict()) when this fires to see exactly what OpenD returned; report to Futu if the payload is genuinely malformed.
- In tests, always include a valid integer acc_id in stubbed rows.
Example fix
# before (test stub missing acc_id)
pd.DataFrame([{'trd_env': 'REAL', 'acc_status': 'ACTIVE'}])
# after
pd.DataFrame([{'acc_id': 1234567, 'trd_env': 'REAL', 'acc_status': 'ACTIVE', 'acc_role': 'NORMAL'}]) Defensive patterns
Strategy: validation
Validate before calling
def row_has_int_acc_id(row) -> bool:
raw = row.get('acc_id')
if raw is None or isinstance(raw, bool):
return False
try:
return int(raw) > 0 and (isinstance(raw, str) or int(raw) == raw)
except (TypeError, ValueError, OverflowError):
return False Type guard
def is_valid_acc_id_cell(raw: object) -> bool:
if isinstance(raw, bool) or raw is None:
return False
try:
v = int(raw)
except (TypeError, ValueError, OverflowError):
return False
return v > 0 and (isinstance(raw, str) or v == raw) Prevention
- Keep OpenD and futu-api versions in the tested pairing (10.8.6808).
- Always include a valid integer acc_id in SDK test fixtures.
- Log raw rows on discovery failure to catch payload schema drift early.
When it happens
Trigger: A DataFrame row where acc_id is None or NaN (masked by filtering), a placeholder string, or an SDK serialization glitch after an OpenD version mismatch with the pinned SDK.
Common situations: Running a newer/older OpenD whose payload schema differs from futu-api==10.8.6808 expectations; corrupted OpenD session state; mocks in tests returning rows without acc_id.
Related errors
- Futu 持仓数量无效{suffix}
- {operation}返回了非表格数据
- 选股功能不可用。请检查策略配置、数据依赖和服务日志。
- TickFlow daily K-line response may be truncated by count: sy
- 未安装 Futu OpenAPI SDK;请先执行 `pip install "futu-api==10.8.6808"
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/c8ad0c15e0ab6d75.
Report an issue: GitHub.