{"record":{"id":"ac40353108fab77e","repo":"ZhuLinsen/daily_stock_analysis","slug":"futu-acc-id-id","errorCode":null,"errorMessage":"FUTU_ACC_ID 必须是正整数账户 ID","messagePattern":"FUTU_ACC_ID 必须是正整数账户 ID","errorType":"exception","errorClass":"FutuPortfolioError","httpStatus":null,"severity":"error","filePath":"src/brokers/futu/portfolio.py","lineNumber":149,"sourceCode":"        address = None\n    if address is not None and address.version != 4:\n        raise FutuPortfolioError(\n            \"futu-api==10.8.6808 的网络层仅支持 IPv4；\"\n            f\"FUTU_OPEND_HOST 当前为 {host!r}，请改用 IPv4 地址或可解析到 IPv4 的主机名。\"\n        )\n    return host, port\n\n\ndef _configured_account_id() -> Optional[int]:\n    \"\"\"Return the optional configured real account ID.\"\"\"\n\n    value = (os.getenv(\"FUTU_ACC_ID\") or \"\").strip()\n    if not value:\n        return None\n    try:\n        account_id = int(value)\n    except ValueError as exc:\n        raise FutuPortfolioError(\"FUTU_ACC_ID 必须是正整数账户 ID\") from exc\n    if account_id <= 0:\n        raise FutuPortfolioError(\"FUTU_ACC_ID 必须是正整数账户 ID\")\n    return account_id\n\n\ndef _configured_security_firm(api: _FutuApi) -> Any:\n    \"\"\"Resolve one firm, defaulting to the SDK's official auto-detection mode.\"\"\"\n\n    name = (os.getenv(\"FUTU_SECURITY_FIRM\") or \"NONE\").strip().upper()\n    firm = getattr(api.SecurityFirm, name, None)\n    if firm is None:\n        raise FutuPortfolioError(f\"不支持的 FUTU_SECURITY_FIRM: {name}\")\n    return firm\n\n\ndef _discover_real_accounts(api: _FutuApi, host: str, port: int) -> List[_FutuAccount]:\n    \"\"\"Discover explicitly ACTIVE NORMAL or MASTER REAL accounts.\"\"\"\n","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/brokers/futu/portfolio.py#L131-L167","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","Retype the .env line manually to remove invisible characters.","If unsure of the ID, unset FUTU_ACC_ID first, let discovery list accounts, then pin the value."],"exampleFix":"# before (.env)\nFUTU_ACC_ID=我的账户 / FUTU_ACC_ID=1,234,567\n\n# after (.env)\nFUTU_ACC_ID=1234567","handlingStrategy":"validation","validationCode":"def valid_acc_id_env(raw: str | None) -> bool:\n    if raw is None or not raw.strip():\n        return True  # unset => auto-discovery\n    try:\n        return int(raw.strip()) > 0\n    except ValueError:\n        return False","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use the numeric acc_id from get_acc_list, not the app display number.","No separators, labels, or quotes in FUTU_ACC_ID.","When unsure, unset the variable and let discovery print valid IDs."],"tags":["configuration","futu","validation","environment"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}