GoshawkVortexAI commited on
Commit
baa4e7d
·
verified ·
1 Parent(s): bf65fb5

Update volume_analyze.py

Browse files
Files changed (1) hide show
  1. volume_analyze.py +104 -0
volume_analyze.py CHANGED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ from typing import Dict, Any
4
+ from config import (
5
+ VOLUME_SPIKE_MULTIPLIER,
6
+ VOLUME_MA_PERIOD,
7
+ CLIMAX_VOLUME_MULTIPLIER,
8
+ )
9
+
10
+
11
+ def compute_volume_ma(df: pd.DataFrame, period: int = VOLUME_MA_PERIOD) -> pd.Series:
12
+ return df["volume"].rolling(period).mean()
13
+
14
+
15
+ def detect_volume_spike(df: pd.DataFrame, period: int = VOLUME_MA_PERIOD) -> pd.Series:
16
+ vol_ma = compute_volume_ma(df, period)
17
+ return df["volume"] > (vol_ma * VOLUME_SPIKE_MULTIPLIER)
18
+
19
+
20
+ def detect_climax_volume(df: pd.DataFrame, period: int = VOLUME_MA_PERIOD) -> pd.Series:
21
+ vol_ma = compute_volume_ma(df, period)
22
+ return df["volume"] > (vol_ma * CLIMAX_VOLUME_MULTIPLIER)
23
+
24
+
25
+ def compute_breakout_confirmation(
26
+ df: pd.DataFrame, lookback: int = VOLUME_MA_PERIOD
27
+ ) -> pd.Series:
28
+ price_high = df["close"].rolling(lookback).max().shift(1)
29
+ price_low = df["close"].rolling(lookback).min().shift(1)
30
+ breakout_up = df["close"] > price_high
31
+ breakout_down = df["close"] < price_low
32
+ vol_spike = detect_volume_spike(df)
33
+ confirmed_up = breakout_up & vol_spike
34
+ confirmed_down = breakout_down & vol_spike
35
+ confirmation = pd.Series(0, index=df.index)
36
+ confirmation[confirmed_up] = 1
37
+ confirmation[confirmed_down] = -1
38
+ return confirmation
39
+
40
+
41
+ def compute_obv(df: pd.DataFrame) -> pd.Series:
42
+ direction = np.sign(df["close"].diff())
43
+ direction.iloc[0] = 0
44
+ obv = (df["volume"] * direction).cumsum()
45
+ return obv
46
+
47
+
48
+ def compute_volume_delta_approx(df: pd.DataFrame) -> pd.Series:
49
+ body = df["close"] - df["open"]
50
+ wick_range = (df["high"] - df["low"]).replace(0, np.nan)
51
+ buy_ratio = (body / wick_range).clip(0, 1).fillna(0.5)
52
+ buy_volume = df["volume"] * buy_ratio
53
+ sell_volume = df["volume"] * (1 - buy_ratio)
54
+ delta = buy_volume - sell_volume
55
+ return delta
56
+
57
+
58
+ def analyze_volume(df: pd.DataFrame) -> Dict[str, Any]:
59
+ vol_ma = compute_volume_ma(df, VOLUME_MA_PERIOD)
60
+ spike = detect_volume_spike(df, VOLUME_MA_PERIOD)
61
+ climax = detect_climax_volume(df, VOLUME_MA_PERIOD)
62
+ breakout = compute_breakout_confirmation(df, VOLUME_MA_PERIOD)
63
+ obv = compute_obv(df)
64
+ delta = compute_volume_delta_approx(df)
65
+
66
+ last_vol = df["volume"].iloc[-1]
67
+ last_vol_ma = vol_ma.iloc[-1]
68
+ last_spike = spike.iloc[-1]
69
+ last_climax = climax.iloc[-1]
70
+ last_breakout = breakout.iloc[-1]
71
+
72
+ vol_ratio = last_vol / last_vol_ma if last_vol_ma > 0 else 1.0
73
+
74
+ obv_slope = (obv.iloc[-1] - obv.iloc[-5]) / (obv.iloc[-5] + 1e-10)
75
+ delta_sum = delta.iloc[-5:].sum()
76
+
77
+ if last_climax:
78
+ volume_score = 0.4
79
+ elif last_spike and last_breakout != 0:
80
+ volume_score = 1.0
81
+ elif last_spike:
82
+ volume_score = 0.7
83
+ elif vol_ratio > 1.2:
84
+ volume_score = 0.5
85
+ elif vol_ratio > 0.8:
86
+ volume_score = 0.3
87
+ else:
88
+ volume_score = 0.1
89
+
90
+ obv_bonus = 0.1 if obv_slope > 0 else -0.1
91
+ volume_score = float(np.clip(volume_score + obv_bonus, 0.0, 1.0))
92
+
93
+ return {
94
+ "vol_ratio": vol_ratio,
95
+ "spike": bool(last_spike),
96
+ "climax": bool(last_climax),
97
+ "breakout": int(last_breakout),
98
+ "obv_slope": obv_slope,
99
+ "delta_sum": delta_sum,
100
+ "volume_score": volume_score,
101
+ "spike_series": spike,
102
+ "climax_series": climax,
103
+ "breakout_series": breakout,
104
+ }