eshan6704 commited on
Commit
ec552e6
·
verified ·
1 Parent(s): 91fe931

Update indicators.py

Browse files
Files changed (1) hide show
  1. indicators.py +110 -186
indicators.py CHANGED
@@ -1,215 +1,139 @@
1
- # indicators.py
2
  import pandas as pd
3
  import numpy as np
4
 
5
  # Try TA-Lib
6
  try:
7
  import talib
8
- TALIB = True
9
  except:
10
- TALIB = False
11
 
12
 
13
- # ============================================================
14
- # BASIC INDICATORS (SMA, EMA, ATR)
15
- # ============================================================
16
-
17
- def sma(series, period):
18
- return series.rolling(period).mean()
19
-
20
-
21
- def ema(series, period):
22
- return series.ewm(span=period, adjust=False).mean()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
 
24
 
25
- def atr(high, low, close, period=14):
26
- if TALIB and hasattr(talib, "ATR"):
27
- return talib.ATR(high, low, close, timeperiod=period)
28
- else:
29
- tr1 = high - low
30
- tr2 = (high - close.shift()).abs()
31
- tr3 = (low - close.shift()).abs()
32
- tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
33
- return tr.rolling(period).mean()
34
-
35
-
36
- # ============================================================
37
- # SUPERTREND — TradingView Perfect Replication
38
- # ============================================================
39
-
40
- def supertrend(df, period=10, multiplier=3):
41
- """
42
- Returns:
43
- ST: SuperTrend line
44
- DIR: Trend direction (True = Uptrend, False = Downtrend)
45
- """
46
- high = df['High']
47
- low = df['Low']
48
- close = df['Close']
49
-
50
- # ATR
51
- atr_val = atr(high, low, close, period)
52
-
53
- # Basic bands
54
- hl2 = (high + low) / 2
55
- upperband = hl2 + multiplier * atr_val
56
- lowerband = hl2 - multiplier * atr_val
57
-
58
- final_upper = upperband.copy()
59
- final_lower = lowerband.copy()
60
 
61
- for i in range(1, len(df)):
62
- # Final upper band
63
- if upperband.iloc[i] < final_upper.iloc[i - 1] or close.iloc[i - 1] > final_upper.iloc[i - 1]:
64
- final_upper.iloc[i] = upperband.iloc[i]
65
- else:
66
- final_upper.iloc[i] = final_upper.iloc[i - 1]
 
 
 
67
 
68
- # Final lower band
69
- if lowerband.iloc[i] > final_lower.iloc[i - 1] or close.iloc[i - 1] < final_lower.iloc[i - 1]:
70
- final_lower.iloc[i] = lowerband.iloc[i]
71
- else:
72
- final_lower.iloc[i] = final_lower.iloc[i - 1]
73
 
74
- # Supertrend
75
  st = pd.Series(index=df.index)
76
- dir_up = pd.Series(index=df.index, dtype=bool)
77
 
78
- for i in range(1, len(df)):
79
- if close.iloc[i] > final_upper.iloc[i - 1]:
80
- dir_up.iloc[i] = True
81
- elif close.iloc[i] < final_lower.iloc[i - 1]:
82
- dir_up.iloc[i] = False
83
  else:
84
- dir_up.iloc[i] = dir_up.iloc[i - 1]
85
-
86
- st.iloc[i] = final_lower.iloc[i] if dir_up.iloc[i] else final_upper.iloc[i]
87
-
88
- return st, dir_up
89
-
90
-
91
- # ============================================================
92
- # KELTNER CHANNEL — (EMA ± ATR * Mult)
93
- # ============================================================
94
-
95
- def keltner_channel(df, ema_period=20, atr_period=10, mult=2):
96
- close = df['Close']
97
- upper = ema(close, ema_period) + mult * atr(df['High'], df['Low'], df['Close'], atr_period)
98
- lower = ema(close, ema_period) - mult * atr(df['High'], df['Low'], df['Close'], atr_period)
99
- mid = ema(close, ema_period)
100
- return mid, upper, lower
101
-
102
-
103
- # ============================================================
104
- # ZIGZAG — PERCENT BASED
105
- # ============================================================
106
-
107
- def zigzag(series, pct=5):
108
- """
109
- Returns ZigZag turning points based on percentage move.
110
- """
111
- zz = pd.Series(index=series.index, dtype=float)
112
- last_pivot_price = series.iloc[0]
113
- last_pivot_idx = series.index[0]
114
- trend = 0 # +1 up, -1 down
115
-
116
- for i in range(1, len(series)):
117
- change = (series.iloc[i] - last_pivot_price) / last_pivot_price * 100
118
-
119
- if trend >= 0 and change <= -pct:
120
- zz.iloc[i] = series.iloc[i]
121
- last_pivot_price = series.iloc[i]
122
- trend = -1
123
-
124
- elif trend <= 0 and change >= pct:
125
- zz.iloc[i] = series.iloc[i]
126
- last_pivot_price = series.iloc[i]
127
- trend = +1
128
-
129
- return zz
130
 
 
131
 
132
- # ============================================================
133
- # SWING HIGH / SWING LOW
134
- # ============================================================
135
 
136
- def swing_high_low(df, window=5):
137
- """
138
- Identifies swing high/low using window method.
139
- For window=5, center index is 2 (2 left, 2 right)
140
- """
141
- highs = df['High']
142
- lows = df['Low']
143
- idx = df.index
144
 
145
- swing_high = pd.Series(np.nan, index=idx)
146
- swing_low = pd.Series(np.nan, index=idx)
147
 
148
- half = window // 2
149
 
150
- for i in range(half, len(df) - half):
151
- segment_high = highs[i - half: i + half + 1]
152
- segment_low = lows[i - half: i + half + 1]
153
 
154
- if highs.iloc[i] == segment_high.max():
155
- swing_high.iloc[i] = highs.iloc[i]
 
 
 
 
156
 
157
- if lows.iloc[i] == segment_low.min():
158
- swing_low.iloc[i] = lows.iloc[i]
 
 
 
159
 
160
- return swing_high, swing_low
161
 
162
 
163
- # ============================================================
164
- # RSI FALLBACK
165
- # ============================================================
 
 
 
166
 
167
- def rsi(series, period=14):
168
- if TALIB and hasattr(talib, "RSI"):
169
- return talib.RSI(series, timeperiod=period)
170
- else:
171
- delta = series.diff()
172
- up = delta.clip(lower=0)
173
- down = -delta.clip(upper=0)
174
- ema_up = up.ewm(span=period).mean()
175
- ema_down = down.ewm(span=period).mean()
176
- rs = ema_up / ema_down
177
- return 100 - (100 / (1 + rs))
178
-
179
-
180
- # ============================================================
181
- # MACD FALLBACK
182
- # ============================================================
183
-
184
- def macd(series, fast=12, slow=26, signal=9):
185
- if TALIB and hasattr(talib, "MACD"):
186
- macd_line, macd_signal, macd_hist = talib.MACD(series, fastperiod=fast, slowperiod=slow, signalperiod=signal)
187
- return macd_line, macd_signal, macd_hist
188
- else:
189
- ema_fast = ema(series, fast)
190
- ema_slow = ema(series, slow)
191
- macd_line = ema_fast - ema_slow
192
- macd_signal = ema(macd_line, signal)
193
- macd_hist = macd_line - macd_signal
194
- return macd_line, macd_signal, macd_hist
195
-
196
-
197
- # ============================================================
198
- # STOCHASTIC FALLBACK
199
- # ============================================================
200
-
201
- def stochastic(df, k_period=14, d_period=3):
202
- if TALIB and hasattr(talib, "STOCH"):
203
- k, d = talib.STOCH(
204
- df['High'], df['Low'], df['Close'],
205
- fastk_period=k_period,
206
- slowk_period=d_period, slowk_matype=0,
207
- slowd_period=d_period, slowd_matype=0
208
- )
209
- return k, d
210
- else:
211
- low_min = df['Low'].rolling(k_period).min()
212
- high_max = df['High'].rolling(k_period).max()
213
- k = (df['Close'] - low_min) * 100 / (high_max - low_min)
214
- d = k.rolling(d_period).mean()
215
- return k, d
 
1
+ # indicator.py
2
  import pandas as pd
3
  import numpy as np
4
 
5
  # Try TA-Lib
6
  try:
7
  import talib
8
+ TALIB_AVAILABLE = True
9
  except:
10
+ TALIB_AVAILABLE = False
11
 
12
 
13
+ # ==============================
14
+ # MACD
15
+ # ==============================
16
+ def calc_macd(df):
17
+ if TALIB_AVAILABLE:
18
+ macd, signal, hist = talib.MACD(df["Close"])
19
+ else:
20
+ ema12 = df["Close"].ewm(span=12).mean()
21
+ ema26 = df["Close"].ewm(span=26).mean()
22
+ macd = ema12 - ema26
23
+ signal = macd.ewm(span=9).mean()
24
+ hist = macd - signal
25
+
26
+ return pd.DataFrame({
27
+ "MACD": macd,
28
+ "Signal": signal,
29
+ "Histogram": hist
30
+ })
31
+
32
+
33
+ # ==============================
34
+ # RSI
35
+ # ==============================
36
+ def calc_rsi(df):
37
+ if TALIB_AVAILABLE:
38
+ rsi = talib.RSI(df["Close"], timeperiod=14)
39
+ else:
40
+ delta = df["Close"].diff()
41
+ gain = (delta.where(delta > 0, 0)).rolling(14).mean()
42
+ loss = (-delta.where(delta < 0, 0)).rolling(14).mean()
43
+ rs = gain / loss
44
+ rsi = 100 - (100 / (1 + rs))
45
 
46
+ return pd.DataFrame({"RSI": rsi})
47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
+ # ==============================
50
+ # Supertrend (Custom)
51
+ # ==============================
52
+ def calc_supertrend(df, period=10, multiplier=3):
53
+ hl2 = (df["High"] + df["Low"]) / 2
54
+ tr1 = df["High"] - df["Low"]
55
+ tr2 = abs(df["High"] - df["Close"].shift())
56
+ tr3 = abs(df["Low"] - df["Close"].shift())
57
+ tr = tr1.combine(tr2, max).combine(tr3, max)
58
 
59
+ atr = tr.rolling(period).mean()
60
+ upperband = hl2 + multiplier * atr
61
+ lowerband = hl2 - multiplier * atr
 
 
62
 
 
63
  st = pd.Series(index=df.index)
64
+ direction = pd.Series(index=df.index)
65
 
66
+ for i in range(len(df)):
67
+ if i == 0:
68
+ st.iloc[i] = upperband.iloc[i]
69
+ direction.iloc[i] = 1
 
70
  else:
71
+ if df["Close"].iloc[i] > st.iloc[i - 1]:
72
+ st.iloc[i] = lowerband.iloc[i]
73
+ direction.iloc[i] = 1
74
+ else:
75
+ st.iloc[i] = upperband.iloc[i]
76
+ direction.iloc[i] = -1
77
+
78
+ return pd.DataFrame({
79
+ "Supertrend": st,
80
+ "Direction": direction
81
+ })
82
+
83
+
84
+ # ==============================
85
+ # Stochastic
86
+ # ==============================
87
+ def calc_stochastic(df):
88
+ if TALIB_AVAILABLE:
89
+ slowk, slowd = talib.STOCH(df["High"], df["Low"], df["Close"])
90
+ else:
91
+ low14 = df["Low"].rolling(14).min()
92
+ high14 = df["High"].rolling(14).max()
93
+ slowk = (df["Close"] - low14) * 100 / (high14 - low14)
94
+ slowd = slowk.rolling(3).mean()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
+ return pd.DataFrame({"STOCH_K": slowk, "STOCH_D": slowd})
97
 
 
 
 
98
 
99
+ # ==============================
100
+ # Keltner Channel
101
+ # ==============================
102
+ def calc_keltner(df):
103
+ typical = (df["High"] + df["Low"] + df["Close"]) / 3
104
+ ema = typical.ewm(span=20).mean()
105
+ atr = (df["High"] - df["Low"]).rolling(20).mean()
 
106
 
107
+ upper = ema + 2 * atr
108
+ lower = ema - 2 * atr
109
 
110
+ return pd.DataFrame({"KC_UP": upper, "KC_MID": ema, "KC_LOW": lower})
111
 
 
 
 
112
 
113
+ # ==============================
114
+ # ZigZag (simplified)
115
+ # ==============================
116
+ def calc_zigzag(df, pct=3):
117
+ zigzag = [np.nan] * len(df)
118
+ last_pivot = df["Close"].iloc[0]
119
 
120
+ for i in range(1, len(df)):
121
+ change = (df["Close"].iloc[i] - last_pivot) / last_pivot * 100
122
+ if abs(change) >= pct:
123
+ zigzag[i] = df["Close"].iloc[i]
124
+ last_pivot = df["Close"].iloc[i]
125
 
126
+ return pd.DataFrame({"ZIGZAG": zigzag})
127
 
128
 
129
+ # ==============================
130
+ # Swing High / Low
131
+ # ==============================
132
+ def calc_swings(df, period=5):
133
+ swing_high = df["High"].rolling(period).max()
134
+ swing_low = df["Low"].rolling(period).min()
135
 
136
+ return pd.DataFrame({
137
+ "SWING_HIGH": swing_high,
138
+ "SWING_LOW": swing_low
139
+ })