ZhuLinsen/daily_stock_analysis · error · FutuPortfolioError

查询 Futu 持仓证券类型失败: {exc}

Error message

查询 Futu 持仓证券类型失败: {exc}

What it means

Catch-all translator for the security-type classification step: any non-FutuPortfolioError exception raised while iterating rows (_iter_rows), parsing stock_type enums, or interacting with the futu context is re-raised as FutuPortfolioError with the original message chained. Context is closed in finally via _safe_close.

Source

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

                )
                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)

    missing_codes = [
        code
        for codes in grouped.values()
        for code in codes
        if code not in classified_codes
    ]
    if unsupported_codes:
        logger.warning(
            "已跳过 %d 个当前分析流程不支持的 Futu 持仓: %s",
            len(unsupported_codes),
            ", ".join(unsupported_codes),
        )
    if missing_codes:
        raise FutuPortfolioError(
            "无法确认证券类型的 Futu 持仓: " + ", ".join(missing_codes)

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Read the chained original exception message to find the real cause and fix that (connection, version, permissions).
  2. Ensure futu-api and FutuOpenD versions are matched and up to date.
  3. Retry after FutuOpenD is confirmed healthy; persistent failures mean a schema/contract bug worth reporting with the traceback.
Defensive patterns

Strategy: try-catch

Try / catch

try:
    result = classify_futu_positions(codes)
except FutuPortfolioError as exc:
    logger.error("classification failed, root cause: %r", exc.__cause__)
    raise

Prevention

When it happens

Trigger: Exceptions (not RET_ERROR returns) from get_stock_basicinfo or row iteration: connection drops mid-query, unexpected data shapes raising AttributeError/KeyError inside _iter_rows or _enum_text, SDK internal exceptions.

Common situations: Network instability between host and FutuOpenD during classification; futu-api version returning a different row container type; OpenD crash mid-request.

Related errors


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