{"record":{"id":"0aedac9719a432a7","repo":"ZhuLinsen/daily_stock_analysis","slug":"futu-data","errorCode":null,"errorMessage":"查询 Futu 真实账户失败: {data}","messagePattern":"查询 Futu 真实账户失败: (.+?)","errorType":"exception","errorClass":"FutuPortfolioError","httpStatus":null,"severity":"error","filePath":"src/brokers/futu/portfolio.py","lineNumber":182,"sourceCode":"\ndef _discover_real_accounts(api: _FutuApi, host: str, port: int) -> List[_FutuAccount]:\n    \"\"\"Discover explicitly ACTIVE NORMAL or MASTER REAL accounts.\"\"\"\n\n    accounts: List[_FutuAccount] = []\n    seen_ids = set()\n    requested_acc_id = _configured_account_id()\n    security_firm = _configured_security_firm(api)\n    context = None\n    try:\n        context = api.OpenSecTradeContext(\n            host=host,\n            port=port,\n            filter_trdmarket=api.TrdMarket.NONE,\n            security_firm=security_firm,\n        )\n        ret, data = context.get_acc_list()\n        if ret != api.RET_OK:\n            raise FutuPortfolioError(f\"查询 Futu 真实账户失败: {data}\")\n        for row in _iter_rows(data, \"Futu 账户查询\"):\n            if _enum_text(row.get(\"trd_env\")) != \"REAL\":\n                continue\n            if _enum_text(row.get(\"acc_status\")) != \"ACTIVE\":\n                continue\n            if _enum_text(row.get(\"acc_role\")) not in _SUPPORTED_ACCOUNT_ROLES:\n                continue\n            raw_acc_id = row.get(\"acc_id\")\n            try:\n                acc_id = int(raw_acc_id)\n                exact_integer = isinstance(raw_acc_id, str) or bool(\n                    raw_acc_id == acc_id\n                )\n            except (TypeError, ValueError, OverflowError) as exc:\n                raise FutuPortfolioError(\n                    \"Futu 账户查询返回了无效账户 ID\"\n                ) from exc\n            if isinstance(raw_acc_id, bool) or not exact_integer or acc_id <= 0:","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/brokers/futu/portfolio.py#L164-L200","documentation":"FutuPortfolioError raised in _discover_real_accounts (src/brokers/futu/portfolio.py:182) when OpenSecTradeContext.get_acc_list() returns ret != RET_OK. In the Futu SDK convention (ret, data), a non-zero ret means the request failed and 'data' carries the error string; that string is embedded in this exception.","triggerScenarios":"OpenD gateway not running or unreachable at FUTU_OPEND_HOST:PORT; OpenD logged out of the Futu account; the connected OpenD has no trading (SecTrade) capability enabled; invalid security_firm for the connection; OpenD version too old for the pinned SDK.","commonSituations":"OpenD not started on the deployment machine; firewall blocking the port in Docker/remote setups; OpenD session expired and needs re-login; FUTU_SECURITY_FIRM mismatched with the actual logged-in broker.","solutions":["Confirm OpenD is running and reachable: nc -vz <host> 11111 (or telnet), and check the OpenD UI/log for login state.","Read the embedded '{data}' text — the SDK's error string usually names the exact cause (connect failure, not logged in, no permission).","Verify OpenD is logged into the Futu account with trading enabled, and that its version is compatible with futu-api==10.8.6808.","Match FUTU_SECURITY_FIRM to the actual account or leave it at NONE for auto-detection."],"exampleFix":"# before: assume success\nret, data = ctx.get_acc_list()\n\n# after: fail fast with the SDK's reason surfaced\nret, data = ctx.get_acc_list()\nif ret != RET_OK:\n    raise RuntimeError(f\"get_acc_list failed: {data}\")","handlingStrategy":"retry","validationCode":"import socket\n\ndef opend_reachable(host: str, port: int, timeout: float = 2.0) -> bool:\n    try:\n        with socket.create_connection((host, port), timeout=timeout):\n            return True\n    except OSError:\n        return False","typeGuard":null,"tryCatchPattern":"from src.brokers.futu.portfolio import FutuPortfolioError\ntry:\n    accounts = discover(api, host, port)\nexcept FutuPortfolioError as exc:\n    if '查询 Futu 真实账户失败' in str(exc):\n        log.error('OpenD get_acc_list failed: %s', exc)\n        # inspect message: login/permission vs connectivity before retrying\n    raise","preventionTips":["Health-check OpenD connectivity (socket probe on host:port) before broker calls.","Keep OpenD logged in and trading-enabled; monitor its session state.","Match OpenD and futu-api versions per Futu's compatibility matrix."],"tags":["futu","opend","network","authentication"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}