ZhuLinsen/daily_stock_analysis · error · FutuPortfolioError

查询 Futu 持仓证券类型失败({prefix}): {data}

Error message

查询 Futu 持仓证券类型失败({prefix}): {data}

What it means

Raised during the security-type classification step: after grouping position codes by market prefix, the loader batches codes (in _STATIC_INFO_BATCH_SIZE chunks) into context.get_stock_basicinfo(market, stock_type=STOCK, code_list=batch). If the futu API returns ret != RET_OK (the SDK's non-exception failure mode), the error is raised with the market prefix and the raw data payload futu returned (usually an error string).

Source

Thrown at src/brokers/futu/portfolio.py:404

    stock_codes = set()
    classified_codes = set()
    context = None
    try:
        context = api.OpenQuoteContext(host=host, port=port)
        for prefix, codes in grouped.items():
            market = getattr(api.Market, prefix, None)
            if market is None:
                unsupported_codes.extend(codes)
                continue
            for start in range(0, len(codes), _STATIC_INFO_BATCH_SIZE):
                batch = codes[start : start + _STATIC_INFO_BATCH_SIZE]
                ret, data = context.get_stock_basicinfo(
                    market,
                    stock_type=api.SecurityType.STOCK,
                    code_list=batch,
                )
                if ret != api.RET_OK:
                    raise FutuPortfolioError(
                        f"查询 Futu 持仓证券类型失败({prefix}): {data}"
                    )
                for row in _iter_rows(data, "Futu 证券类型查询"):
                    code = str(row.get("code", "") or "").strip().upper()
                    if not code:
                        continue
                    stock_type = _enum_text(row.get("stock_type"))
                    if stock_type in _UNKNOWN_SECURITY_TYPES:
                        continue
                    classified_codes.add(code)
                    if stock_type == "STOCK":
                        stock_codes.add(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)

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Inspect the {data} payload — it contains futu's own error string which pinpoints the cause (invalid code, frequency limit, permission).
  2. If a specific code is rejected, exclude that position/account or handle it as unsupported instead of STOCK.
  3. Check market permissions for the account in Futu OpenD (e.g. US market data/quote rights).
  4. Restart/re-auth FutuOpenD and retry; if persistent, reduce portfolio size to isolate the failing batch.
Defensive patterns

Strategy: try-catch

Try / catch

try:
    stock_codes = classify_futu_positions(position_codes)
except FutuPortfolioError as exc:
    logger.error("basicinfo failed: %s", exc)  # message embeds prefix + futu error text
    raise

Prevention

When it happens

Trigger: get_stock_basicinfo returning RET_ERROR for a batch, e.g. too many codes requested, an invalid code slipped into code_list, market temporarily unavailable, rate limiting, or OpenD protocol errors. The message embeds which prefix (SH/HK/US...) failed and futu's own error text in data.

Common situations: Large portfolios where a batch hits futu's code_list limits; one malformed code poisoning the whole batch; FutuOpenD not subscribed/logged in for that market; API quota exceeded.

Related errors


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