ZhuLinsen/daily_stock_analysis · error · FutuPortfolioError

FUTU_ACC_ID 必须是正整数账户 ID

Error message

FUTU_ACC_ID 必须是正整数账户 ID

What it means

FutuPortfolioError raised in _configured_account_id (src/brokers/futu/portfolio.py:149) when FUTU_ACC_ID is set but int() cannot parse its value — e.g. 'abc', '12345 ', partial numbers, or account IDs containing separators. Unset/empty returns None (auto-discovery mode); only a set-but-non-numeric value raises.

Source

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

        address = None
    if address is not None and address.version != 4:
        raise FutuPortfolioError(
            "futu-api==10.8.6808 的网络层仅支持 IPv4;"
            f"FUTU_OPEND_HOST 当前为 {host!r},请改用 IPv4 地址或可解析到 IPv4 的主机名。"
        )
    return host, port


def _configured_account_id() -> Optional[int]:
    """Return the optional configured real account ID."""

    value = (os.getenv("FUTU_ACC_ID") or "").strip()
    if not value:
        return None
    try:
        account_id = int(value)
    except ValueError as exc:
        raise FutuPortfolioError("FUTU_ACC_ID 必须是正整数账户 ID") from exc
    if account_id <= 0:
        raise FutuPortfolioError("FUTU_ACC_ID 必须是正整数账户 ID")
    return account_id


def _configured_security_firm(api: _FutuApi) -> Any:
    """Resolve one firm, defaulting to the SDK's official auto-detection mode."""

    name = (os.getenv("FUTU_SECURITY_FIRM") or "NONE").strip().upper()
    firm = getattr(api.SecurityFirm, name, None)
    if firm is None:
        raise FutuPortfolioError(f"不支持的 FUTU_SECURITY_FIRM: {name}")
    return firm


def _discover_real_accounts(api: _FutuApi, host: str, port: int) -> List[_FutuAccount]:
    """Discover explicitly ACTIVE NORMAL or MASTER REAL accounts."""

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Set FUTU_ACC_ID to the plain positive integer acc_id (no separators, labels, or quotes); get the exact value from OpenD's get_acc_list payload or leave it unset to auto-discover.
  2. Retype the .env line manually to remove invisible characters.
  3. If unsure of the ID, unset FUTU_ACC_ID first, let discovery list accounts, then pin the value.

Example fix

# before (.env)
FUTU_ACC_ID=我的账户 / FUTU_ACC_ID=1,234,567

# after (.env)
FUTU_ACC_ID=1234567
Defensive patterns

Strategy: validation

Validate before calling

def valid_acc_id_env(raw: str | None) -> bool:
    if raw is None or not raw.strip():
        return True  # unset => auto-discovery
    try:
        return int(raw.strip()) > 0
    except ValueError:
        return False

Prevention

When it happens

Trigger: Setting FUTU_ACC_ID to a broker login name, phone, or email instead of the numeric acc_id; values like '1,234,567' or 'ID-12345'; OCR/copy artifacts from the Futu app where the account number was copied with labels or spaces.

Common situations: Confusing the Futu trading account number shown in the app with the numeric acc_id returned by OpenD's get_acc_list; formatting the ID with thousands separators; leftover placeholder text from an .env template.

Related errors


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