Coverage for src / monte_neo / indicators / technical_lib.py: 100%
51 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-28 16:27 +0200
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-28 16:27 +0200
1from __future__ import annotations
3import pandas as pd
6class TechnicalIndicators:
7 """Collection of technical indicator calculations."""
9 @staticmethod
10 def sma(data: pd.Series, period: int) -> pd.Series:
11 """Simple Moving Average."""
12 return data.rolling(window=int(period)).mean()
14 @staticmethod
15 def ema(data: pd.Series, period: int) -> pd.Series:
16 """Exponential Moving Average."""
17 return data.ewm(span=int(period), adjust=False).mean()
19 @staticmethod
20 def rsi(data: pd.Series, period: int = 14) -> pd.Series:
21 """Relative Strength Index."""
22 period = int(period)
23 delta = data.diff()
24 gain = (delta.where(delta > 0, 0)).rolling(period).mean()
25 loss = (-delta.where(delta < 0, 0)).rolling(period).mean()
27 rs = gain / loss
28 return 100 - (100 / (1 + rs))
30 @staticmethod
31 def macd(
32 data: pd.Series,
33 fast: int = 12,
34 slow: int = 26,
35 signal: int = 9,
36 ) -> tuple[pd.Series, pd.Series, pd.Series]:
37 """MACD indicator."""
38 fast_ema = data.ewm(span=int(fast), adjust=False).mean()
39 slow_ema = data.ewm(span=int(slow), adjust=False).mean()
40 macd_line = fast_ema - slow_ema
41 signal_line = macd_line.ewm(span=int(signal), adjust=False).mean()
42 histogram = macd_line - signal_line
43 return macd_line, signal_line, histogram
45 @staticmethod
46 def bollinger_bands(
47 data: pd.Series,
48 period: int = 20,
49 std_dev: float = 2.0,
50 ) -> tuple[pd.Series, pd.Series, pd.Series]:
51 """Bollinger Bands."""
52 middle = data.rolling(period).mean()
53 std = data.rolling(period).std()
54 upper = middle + (std * std_dev)
55 lower = middle - (std * std_dev)
56 return upper, middle, lower
58 @staticmethod
59 def atr(data: pd.DataFrame, period: int = 14) -> pd.Series:
60 """Average True Range."""
61 period = int(period)
62 high = data["high"]
63 low = data["low"]
64 close = data["close"]
66 tr1 = high - low
67 tr2 = abs(high - close.shift())
68 tr3 = abs(low - close.shift())
70 tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
71 return tr.rolling(period).mean()
73 @staticmethod
74 def stochastic(
75 data: pd.DataFrame,
76 k_period: int = 14,
77 d_period: int = 3,
78 ) -> tuple[pd.Series, pd.Series]:
79 """Stochastic Oscillator."""
80 k_period, d_period = int(k_period), int(d_period)
81 low_min = data["low"].rolling(k_period).min()
82 high_max = data["high"].rolling(k_period).max()
84 k = 100 * ((data["close"] - low_min) / (high_max - low_min))
85 d = k.rolling(d_period).mean()
86 return k, d