ZhuLinsen/daily_stock_analysis · error · FutuPortfolioError
Futu 非零持仓返回了无效证券代码: {code}
Error message
Futu 非零持仓返回了无效证券代码: {code} What it means
Raised when a non-zero position's code is a non-empty string but does not contain the expected '<MARKET>.<SYMBOL>' shape (e.g. '00700' with no dot, '.00700', or 'HK.'). The loader partitions on '.' and requires market, separator, and symbol all present so it can later group codes by market prefix for get_stock_basicinfo classification. A malformed code means the security cannot be routed to a market query.
Source
Thrown at src/brokers/futu/portfolio.py:295
try:
if isinstance(raw_quantity, bool):
raise TypeError("boolean quantity")
quantity = float(raw_quantity)
except (TypeError, ValueError) as exc:
suffix = f": {code}" if code else ""
raise FutuPortfolioError(f"Futu 持仓数量无效{suffix}") from exc
if not math.isfinite(quantity):
suffix = f": {code}" if code else ""
raise FutuPortfolioError(f"Futu 持仓数量无效{suffix}")
if quantity == 0:
continue
if not isinstance(raw_code, str):
raise FutuPortfolioError("Futu 非零持仓返回了无效证券代码")
if not code:
raise FutuPortfolioError("Futu 非零持仓返回了空证券代码")
market, separator, symbol = code.partition(".")
if not separator or not market or not symbol:
raise FutuPortfolioError(
f"Futu 非零持仓返回了无效证券代码: {code}"
)
if code in seen_codes:
continue
seen_codes.add(code)
codes.append(code)
except FutuPortfolioError:
raise
except Exception as exc: # noqa: BLE001 - translate SDK/network errors for CLI callers
raise FutuPortfolioError(f"查询 Futu 真实持仓失败: {exc}") from exc
finally:
_safe_close(context)
if skipped_short_count:
logger.info("已跳过 %d 个 Futu SHORT 空头持仓", skipped_short_count)
if skipped_unknown_side_count:
logger.warning(
"已跳过 %d 个持仓方向不是 LONG 的 Futu 持仓",View on GitHub (pinned to 5159bd72e8)
Solutions
- Log/inspect the actual code value from the exception message (it is included verbatim) to see which shape arrived.
- Ensure futu-api version matches FutuOpenD so codes keep the MARKET.SYMBOL format.
- If codes legitimately lack the prefix, map them to the account's market before calling this loader rather than patching the guard.
Defensive patterns
Strategy: validation
Validate before calling
def is_dotted_futu_code(code: str) -> bool:
market, sep, symbol = code.partition(".")
return bool(sep and market and symbol) Type guard
def is_futu_code(value: object) -> bool:
if not isinstance(value, str):
return False
m, s, sym = value.partition(".")
return bool(s and m and sym) Try / catch
try:
codes = load_futu_stock_codes()
except FutuPortfolioError as exc:
logger.error("Futu code contract violated: %s", exc)
raise Prevention
- Keep futu-api version aligned with FutuOpenD releases
- Never hand-craft position codes without the MARKET.SYMBOL shape
- Log raw SDK rows when contract errors first appear to capture schema drift
When it happens
Trigger: position_list returns codes in a bare format like '00700' or 'AAPL' without the 'HK.'/'US.'/'SH.' market prefix, or codes that are just a market prefix 'HK.'. Also triggered by whitespace-only symbols that survived the earlier checks (partition succeeds but symbol part is empty).
Common situations: SDK schema change dropping the market prefix; custom/mock data fed into the loader; positions in markets whose code format differs from the expected dotted convention.
Related errors
- Futu 非零持仓返回了无效证券代码
- Futu 非零持仓返回了空证券代码
- 无法确认证券类型的 Futu 持仓: {codes}
- 查询 Futu 真实持仓失败: {exc}
- 查询 Futu 持仓证券类型失败({prefix}): {data}
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/7e3e9b8ea0e85dbd.
Report an issue: GitHub.