""" general_analysis Volume Profile (POC, VAH, VAL). """ from __future__ import annotations import numpy as np import pandas as pd from config import GA_VP_BINS, GA_VP_VALUE_AREA_PCT from deepcoin.analysis.general_analysis_core import ga_col def general_analysis_volume_profile( win: pd.DataFrame, bins: int | None = None, value_area_pct: float | None = None, ) -> dict[str, float | int]: """ lookback 구간 가격-거래량 분포에서 POC·VAH·VAL 계산. Args: win: OHLCV. bins: 가격 구간 수. value_area_pct: value area 누적 비율 (기본 70%). Returns: ga_vp_* 키 dict (접두사 없음). """ res: dict[str, float | int] = { "vp_poc": 0.0, "vp_vah": 0.0, "vp_val": 0.0, "vp_close_vs_poc_pct": 0.0, "vp_in_value_area": 0, } if bins is None: bins = GA_VP_BINS if value_area_pct is None: value_area_pct = GA_VP_VALUE_AREA_PCT if win is None or len(win) < 10 or "Volume" not in win.columns: return res h = win["High"].astype(float).values l = win["Low"].astype(float).values c = win["Close"].astype(float).values v = win["Volume"].astype(float).values tp = (h + l + c) / 3.0 lo, hi = float(l.min()), float(h.max()) if hi <= lo: return res edges = np.linspace(lo, hi, bins + 1) hist = np.zeros(bins, dtype=float) for i in range(len(tp)): idx = int(np.clip(np.digitize(tp[i], edges) - 1, 0, bins - 1)) hist[idx] += v[i] if hist.sum() <= 0: return res poc_idx = int(np.argmax(hist)) poc = float((edges[poc_idx] + edges[poc_idx + 1]) / 2) res["vp_poc"] = poc order = np.argsort(hist)[::-1] cum = 0.0 selected: list[int] = [] total = hist.sum() for idx in order: selected.append(int(idx)) cum += hist[idx] if cum >= total * value_area_pct: break sel_min, sel_max = min(selected), max(selected) res["vp_val"] = float(edges[sel_min]) res["vp_vah"] = float(edges[sel_max + 1]) res["vp_close_vs_poc_pct"] = float((c[-1] / poc - 1) * 100) if poc else 0.0 res["vp_in_value_area"] = int(res["vp_val"] <= c[-1] <= res["vp_vah"]) return res def general_analysis_volume_columns() -> list[str]: return ["vp_poc", "vp_vah", "vp_val", "vp_close_vs_poc_pct", "vp_in_value_area"] def general_analysis_volume_snapshot(win: pd.DataFrame) -> dict[str, object]: """Volume profile → ga_vp_*.""" return {ga_col(k): v for k, v in general_analysis_volume_profile(win).items()}