"""实例数据统计:复盘 KPI + 权益曲线 API,以及后台权益采样.""" from __future__ import annotations from typing import Any, Callable from flask import Flask, jsonify, request def install_instance_data_stats(app: Flask, app_module: Any) -> None: get_db: Callable = app_module.get_db login_required = app_module.login_required def _fetch_equity_snapshot() -> dict[str, Any]: from lib.instance.instance_cash_sample_lib import ( cash_usdt_from_balances, equity_usdt_from_snapshot, ) ex = getattr(app_module, "exchange_options", None) bal: dict[str, Any] = {} if ex is not None: try: from lib.exchange.okx_options_lib import fetch_options_balances bal = fetch_options_balances(ex, force=False) or {} except Exception: bal = {} cash = cash_usdt_from_balances(bal if isinstance(bal, dict) else None) positions: list[dict[str, Any]] = [] cfg = None try: cfg = app.extensions.get("options_cfg") except Exception: cfg = None if isinstance(cfg, dict) and cfg.get("enabled"): try: from lib.options.options_dashboard_lib import ( fetch_light_option_positions_for_dashboard, ) positions = fetch_light_option_positions_for_dashboard(cfg) or [] except Exception: positions = [] btc_px = eth_px = None if ex is not None: try: from lib.options.options_stats_lib import _underlying_index_usdt btc_px = _underlying_index_usdt(ex, "BTC") eth_px = _underlying_index_usdt(ex, "ETH") except Exception: btc_px = eth_px = None if (btc_px is None or eth_px is None) and positions: for p in positions: if not isinstance(p, dict): continue under = str(p.get("underlying") or "").upper() idx = None try: idx = float(p.get("idx_px") or p.get("index_px") or 0) except (TypeError, ValueError): idx = None if idx is None or idx <= 0: continue if under == "BTC" and btc_px is None: btc_px = idx elif under == "ETH" and eth_px is None: eth_px = idx equity = equity_usdt_from_snapshot( bal if isinstance(bal, dict) else None, positions, btc_px=btc_px, eth_px=eth_px, ) return {"cash_usdt": cash, "equity_usdt": equity} @app.route("/api/instance/cash_curve") @login_required def api_instance_cash_curve(): from lib.instance.instance_cash_sample_lib import ( query_cash_series_with_db, sample_once, ) try: sample_once(get_db, _fetch_equity_snapshot) except Exception: pass range_key = (request.args.get("range") or "7d").strip() conn = get_db() try: return jsonify(query_cash_series_with_db(conn, range_key=range_key)) except Exception as e: return jsonify({"ok": False, "msg": f"加载资金曲线失败: {e}"}), 500 finally: conn.close() try: from lib.instance.instance_cash_sample_lib import start_cash_sample_loop start_cash_sample_loop(get_db, _fetch_equity_snapshot) except Exception as e: print(f"[instance_cash_sample] start skipped: {e}", flush=True)