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

  1. Log/inspect the actual code value from the exception message (it is included verbatim) to see which shape arrived.
  2. Ensure futu-api version matches FutuOpenD so codes keep the MARKET.SYMBOL format.
  3. 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

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


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/7e3e9b8ea0e85dbd. Report an issue: GitHub.