QuantumLearner commited on
Commit
6a81e88
·
verified ·
1 Parent(s): d648881

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +412 -269
app.py CHANGED
@@ -35,11 +35,9 @@ with st.sidebar.expander("How to Use:", expanded=False):
35
  # Function to fetch data
36
  @st.cache_data
37
  def get_data(ticker, start_date, end_date):
38
- # Use auto_adjust=True to get adjusted price data (so "Close" is correct)
39
- data = yf.download(ticker, start=start_date, end=end_date, auto_adjust=True)
40
- # If a multi-index is returned (e.g. multiple tickers), drop the extra level
41
  if isinstance(data.columns, pd.MultiIndex):
42
- data.columns = data.columns.get_level_values(1)
43
  if data.empty:
44
  raise ValueError(f"No data retrieved for {ticker}")
45
  if len(data) < 512: # Ensure enough data for largest possible Rainbow MA period
@@ -136,80 +134,102 @@ def calculate_harmonic_moving_average(prices, period):
136
  # End Point Moving Average (EPMA) Function
137
  def calculate_EPMA(prices, period):
138
  epma_values = []
 
139
  for i in range(period - 1, len(prices)):
140
  x = np.arange(period)
141
  y = prices[i-period+1:i+1]
 
142
  slope, intercept = np.polyfit(x, y, 1)
143
  epma = slope * (period - 1) + intercept
 
144
  epma_values.append(epma)
145
- return [None]*(period-1) + epma_values # Pad with None for alignment
146
 
147
- # Jurik Moving Average (JMA) and other MA functions remain unchanged...
148
- # (All other moving average functions are defined below exactly as before)
149
 
 
150
  def calculate_CMA(prices):
151
  cumsum = np.cumsum(prices)
152
  cma = cumsum / (np.arange(len(prices)) + 1)
153
  return cma
154
 
 
 
155
  def parabolic_weighted_moving_average(prices, n=14):
156
  weights = np.array([(n-i)**2 for i in range(n)])
157
  return np.convolve(prices, weights/weights.sum(), mode='valid')
158
 
 
159
  def REMA(prices, alpha=0.1, lambda_=0.1):
160
  rema = [prices[0]]
161
  penalty = 0
 
162
  for t in range(1, len(prices)):
163
  second_derivative = prices[t] - 2 * prices[t-1] + prices[t-2] if t-2 >= 0 else 0
164
  penalty = lambda_ * second_derivative
165
  current_rema = alpha * prices[t] + (1 - alpha) * rema[-1] - penalty
166
  rema.append(current_rema)
 
167
  return rema
168
 
 
169
  def weighted_moving_average(data, periods):
170
  weights = np.arange(1, periods + 1)
171
  wma = data.rolling(periods).apply(lambda x: np.dot(x, weights) / weights.sum(), raw=True)
172
  return wma
173
 
 
174
  def hull_moving_average(data, periods):
175
  wma_half_period = weighted_moving_average(data, int(periods / 2))
176
  wma_full_period = weighted_moving_average(data, periods)
177
  hma = weighted_moving_average(2 * wma_half_period - wma_full_period, int(np.sqrt(periods)))
178
  return hma
179
 
 
180
  def harmonic_moving_average(data, period):
181
  def harmonic_mean(prices):
182
  return period / np.sum(1.0 / prices)
 
183
  hma_values = []
184
  for i in range(period - 1, len(data)):
185
  hma_values.append(harmonic_mean(data[i - period + 1:i + 1]))
 
186
  return [np.nan] * (period - 1) + hma_values
187
 
 
188
  def calculate_FRAMA(data, batch=10):
189
  InputPrice = data['Close'].values
190
  Length = len(InputPrice)
191
  Filt = np.array(InputPrice)
 
192
  for i in range(2 * batch, Length):
193
  v1 = InputPrice[i-2*batch:i - batch]
194
  v2 = InputPrice[i - batch:i]
 
195
  H1 = np.max(v1)
196
  L1 = np.min(v1)
197
  N1 = (H1 - L1) / batch
 
198
  H2 = np.max(v2)
199
  L2 = np.min(v2)
200
  N2 = (H2 - L2) / batch
 
201
  H = np.max([H1, H2])
202
  L = np.min([L1, L2])
203
  N3 = (H - L) / (2 * batch)
 
204
  Dimen = 0
205
  if N1 > 0 and N2 > 0 and N3 > 0:
206
  Dimen = (np.log(N1 + N2) - np.log(N3)) / np.log(2)
 
207
  alpha = np.exp(-4.6 * Dimen - 1)
208
  alpha = np.clip(alpha, 0.1, 1)
 
209
  Filt[i] = alpha * InputPrice[i] + (1 - alpha) * Filt[i-1]
 
210
  data['FRAMA'] = Filt
211
  return data
212
 
 
213
  def calculate_EMA(prices, period):
214
  alpha = 2 / (period + 1)
215
  EMA = [prices[0]]
@@ -217,62 +237,81 @@ def calculate_EMA(prices, period):
217
  EMA.append((price - EMA[-1]) * alpha + EMA[-1])
218
  return EMA
219
 
 
220
  def calculate_ZLEMA(prices, period):
221
  lag = period // 2
222
  adjusted_prices = [2 * prices[i] - (prices[i - lag] if i >= lag else prices[0]) for i in range(len(prices))]
223
  ZLEMA = calculate_EMA(adjusted_prices, period)
224
  return ZLEMA
225
 
 
226
  def calculate_CMO(prices, period):
227
  deltas = np.diff(prices)
228
  sum_gains = np.cumsum(np.where(deltas >= 0, deltas, 0))
229
  sum_losses = np.abs(np.cumsum(np.where(deltas < 0, deltas, 0)))
 
230
  cmo = 100 * (sum_gains - sum_losses) / (sum_gains + sum_losses)
231
- return np.insert(cmo, 0, 0)
232
 
 
233
  def calculate_VIDYA(prices, period):
234
  cmo_values = calculate_CMO(prices, period)
235
  vidya = [prices[0]]
 
236
  for i in range(1, len(prices)):
237
- alpha = abs(cmo_values[i]) / 100
238
  vidya.append((1 - alpha) * vidya[-1] + alpha * prices[i])
 
239
  return vidya
240
 
 
241
  def calculate_ALMA(prices, period, offset=0.85, sigma=6):
242
  m = np.floor(offset * (period - 1))
243
  s = period / sigma
244
  alma = []
 
245
  for i in range(period - 1, len(prices)):
246
  weights = [np.exp(- (j - m)**2 / (2 * s * s)) for j in range(period)]
247
  sum_weights = sum(weights)
248
  normalized_weights = [w/sum_weights for w in weights]
 
249
  window = prices[i-period+1:i+1]
250
  alma_value = sum([normalized_weights[j] * window[j] for j in range(period)])
251
  alma.append(alma_value)
252
- return [None]*(period-1) + alma
253
 
 
 
 
254
  def adaptive_period_moving_average(prices, min_period=5, max_period=30):
255
  atr = np.zeros_like(prices)
256
  adjusted_periods = np.zeros_like(prices)
257
- moving_averages = np.full_like(prices, np.nan)
 
258
  for i in range(1, len(prices)):
259
  atr[i] = atr[i-1] + (abs(prices[i] - prices[i-1]) - atr[i-1]) / 14
 
260
  min_volatility = atr[1:i+1].min()
261
  max_volatility = atr[1:i+1].max()
 
262
  if max_volatility == min_volatility:
263
  adjusted_period = min_period
264
  else:
265
  adjusted_period = int(((max_period - min_period) / (max_volatility - min_volatility)) * (atr[i] - min_volatility) + min_period)
 
266
  adjusted_periods[i] = adjusted_period
 
267
  if i >= adjusted_period:
268
  moving_averages[i] = np.mean(prices[i-adjusted_period+1:i+1])
 
269
  return moving_averages
270
 
 
271
  def calculate_rainbow_ema(data, lookback_periods):
272
  for lookback in lookback_periods:
273
  data[f'EMA{lookback}'] = data['Close'].ewm(span=lookback).mean()
274
  return data
275
 
 
276
  def wilders_moving_average(prices, period):
277
  wilder = [prices[0]]
278
  for price in prices[1:]:
@@ -280,42 +319,52 @@ def wilders_moving_average(prices, period):
280
  wilder.append(wilder_value)
281
  return wilder
282
 
 
283
  def calculate_SMMA(prices, n):
284
- SMMA = [np.nan] * (n-1)
285
  SMMA.append(sum(prices[:n]) / n)
286
  for i in range(n, len(prices)):
287
  smma_value = (SMMA[-1] * (n - 1) + prices[i]) / n
288
  SMMA.append(smma_value)
289
  return SMMA
290
 
 
291
  def calculate_LSMA(prices, period):
292
  n = period
293
  x = np.array(range(1, n+1))
 
294
  LSMA = []
295
  for i in range(len(prices) - period + 1):
296
  y = prices[i:i+period]
297
  m = (n*np.sum(x*y) - np.sum(x)*np.sum(y)) / (n*np.sum(x**2) - np.sum(x)**2)
298
  c = (np.sum(y) - m*np.sum(x)) / n
299
- LSMA.append(m * n + c)
 
 
300
  LSMA = [np.nan] * (period-1) + LSMA
301
  return LSMA
302
 
 
303
  def calculate_MMA(prices, period):
304
- MMA = [sum(prices[:period]) / period]
305
  for t in range(period, len(prices)):
306
  MMA.append((prices[t] + (period - 1) * MMA[-1]) / period)
307
- return [None]*(period-1) + MMA
308
 
 
309
  def calculate_SinWMA(prices, period):
310
  weights = [np.sin(np.pi * i / (period + 1)) for i in range(1, period+1)]
311
  sum_weights = sum(weights)
312
  normalized_weights = [w/sum_weights for w in weights]
 
313
  SinWMA = []
314
  for t in range(period - 1, len(prices)):
315
  window = prices[t-period+1:t+1]
316
  SinWMA.append(sum([normalized_weights[i] * window[i] for i in range(period)]))
317
- return [None]*(period-1) + SinWMA
318
 
 
 
 
319
  def calculate_MedMA(prices, window):
320
  medians = []
321
  for i in range(len(prices)):
@@ -326,6 +375,7 @@ def calculate_MedMA(prices, window):
326
  medians.append(median)
327
  return medians
328
 
 
329
  def calculate_GMA(prices, window):
330
  gm_avg = []
331
  for i in range(len(prices)):
@@ -337,6 +387,7 @@ def calculate_GMA(prices, window):
337
  gm_avg.append(gma_value)
338
  return gm_avg
339
 
 
340
  def calculate_eVWMA(prices, volumes, window):
341
  evwma_values = []
342
  for i in range(len(prices)):
@@ -351,6 +402,7 @@ def calculate_eVWMA(prices, volumes, window):
351
  evwma_values.append(evwma)
352
  return evwma_values
353
 
 
354
  def calculate_mcginley_dynamic(prices, n):
355
  MD = [prices[0]]
356
  for i in range(1, len(prices)):
@@ -358,35 +410,47 @@ def calculate_mcginley_dynamic(prices, n):
358
  MD.append(md_value)
359
  return MD
360
 
 
361
  from datetime import datetime
 
362
  def calculate_AMA(prices, anchor_date, data):
 
363
  anchor_date = pd.to_datetime(anchor_date)
 
364
  try:
365
  anchor_idx = data.index.get_loc(anchor_date)
366
  except KeyError:
 
367
  anchor_date = data.index[data.index.get_loc(anchor_date, method='nearest')]
368
  anchor_idx = data.index.get_loc(anchor_date)
 
369
  AMA = []
 
370
  for i in range(len(prices)):
371
  if i < anchor_idx:
372
  AMA.append(None)
373
  else:
374
  AMA.append(sum(prices[anchor_idx:i+1]) / (i - anchor_idx + 1))
 
375
  return AMA
376
 
 
377
  def filtered_moving_average(prices, n=14):
 
378
  w = np.ones(n) / n
379
  return np.convolve(prices, w, mode='valid')
380
 
381
  # Sidebar for user inputs
382
  st.sidebar.header("Select Parameters")
383
 
 
384
  ticker_symbol = st.sidebar.text_input(
385
  "Ticker or Crypto Pair",
386
  value=st.session_state.get('ticker_symbol', 'BTC-USD'),
387
  help="Enter the ticker symbol (e.g., AAPL for Apple) or Cryptocurrency Pair (e.g. BTC-USD)."
388
  )
389
 
 
390
  start_date = st.sidebar.date_input(
391
  "Start Date",
392
  value=st.session_state.get('start_date', pd.to_datetime("2020-01-01")),
@@ -398,8 +462,10 @@ end_date = st.sidebar.date_input(
398
  help="Select the end date for fetching the stock data."
399
  )
400
 
 
401
  if st.sidebar.button('Fetch Data'):
402
  try:
 
403
  if (
404
  ticker_symbol != st.session_state.get('ticker_symbol') or
405
  start_date != st.session_state.get('start_date') or
@@ -415,9 +481,11 @@ if st.sidebar.button('Fetch Data'):
415
  except Exception as e:
416
  st.error(f"An error occurred while fetching data: {e}")
417
 
 
418
  if 'data' in st.session_state:
419
  data = st.session_state['data']
420
 
 
421
  with st.sidebar.expander("Simple Moving Average", expanded=False):
422
  use_sma = st.checkbox(
423
  'Simple Moving Average (SMA)',
@@ -433,6 +501,7 @@ if 'data' in st.session_state:
433
  help="Specify the period (in days) for the SMA."
434
  )
435
 
 
436
  with st.sidebar.expander("Exponential Moving Average (EMA)", expanded=False):
437
  use_ema = st.checkbox(
438
  'Enable EMA',
@@ -448,6 +517,7 @@ if 'data' in st.session_state:
448
  help="Specify the period (in days) for the EMA."
449
  )
450
 
 
451
  with st.sidebar.expander("Weighted Moving Average (WMA)", expanded=False):
452
  use_wma = st.checkbox(
453
  'Enable WMA',
@@ -463,6 +533,7 @@ if 'data' in st.session_state:
463
  help="Specify the period (in days) for the WMA."
464
  )
465
 
 
466
  with st.sidebar.expander("Double Exponential Moving Average (DEMA)", expanded=False):
467
  use_dema = st.checkbox(
468
  'Enable DEMA',
@@ -478,6 +549,7 @@ if 'data' in st.session_state:
478
  help="Specify the period (in days) for the DEMA."
479
  )
480
 
 
481
  with st.sidebar.expander("Triple Exponential Moving Average (TEMA)", expanded=False):
482
  use_tema = st.checkbox(
483
  'Enable TEMA',
@@ -493,6 +565,7 @@ if 'data' in st.session_state:
493
  help="Specify the period (in days) for the TEMA."
494
  )
495
 
 
496
  with st.sidebar.expander("Volume-Adjusted Moving Average (VAMA)", expanded=False):
497
  use_vama = st.checkbox(
498
  'Enable VAMA',
@@ -508,6 +581,7 @@ if 'data' in st.session_state:
508
  help="Specify the period (in days) for the VAMA."
509
  )
510
 
 
511
  with st.sidebar.expander("Kaufman Adaptive Moving Average (KAMA)", expanded=False):
512
  use_kama = st.checkbox(
513
  'Enable KAMA',
@@ -539,6 +613,7 @@ if 'data' in st.session_state:
539
  help="Specify the slowest smoothing constant period."
540
  )
541
 
 
542
  with st.sidebar.expander("Triangular Moving Average (TMA)", expanded=False):
543
  use_tma = st.checkbox(
544
  'Enable TMA',
@@ -553,7 +628,8 @@ if 'data' in st.session_state:
553
  disabled=not use_tma,
554
  help="Specify the period (in days) for the TMA."
555
  )
556
-
 
557
  with st.sidebar.expander("Hull Moving Average (HMA)", expanded=False):
558
  use_hull_ma = st.checkbox(
559
  'Enable HMA',
@@ -569,6 +645,7 @@ if 'data' in st.session_state:
569
  help="Specify the period (in days) for the Hull Moving Average."
570
  )
571
 
 
572
  with st.sidebar.expander("Harmonic Moving Average (HMA)", expanded=False):
573
  use_harmonic_ma = st.checkbox(
574
  'Enable HMA',
@@ -584,6 +661,7 @@ if 'data' in st.session_state:
584
  help="Specify the period (in days) for the Harmonic Moving Average."
585
  )
586
 
 
587
  with st.sidebar.expander("Fractal Adaptive Moving Average (FRAMA)", expanded=False):
588
  use_frama = st.checkbox(
589
  'Enable FRAMA',
@@ -599,6 +677,7 @@ if 'data' in st.session_state:
599
  help="Specify the batch size for FRAMA calculation."
600
  )
601
 
 
602
  with st.sidebar.expander("Zero Lag Exponential Moving Average (ZLEMA)", expanded=False):
603
  use_zlema = st.checkbox(
604
  'Enable ZLEMA',
@@ -614,6 +693,7 @@ if 'data' in st.session_state:
614
  help="Specify the period (in days) for the ZLEMA."
615
  )
616
 
 
617
  with st.sidebar.expander("Variable Index Dynamic Average (VIDYA)", expanded=False):
618
  use_vidya = st.checkbox(
619
  'Enable VIDYA',
@@ -629,6 +709,7 @@ if 'data' in st.session_state:
629
  help="Specify the period (in days) for the VIDYA."
630
  )
631
 
 
632
  with st.sidebar.expander("Arnaud Legoux Moving Average (ALMA)", expanded=False):
633
  use_alma = st.checkbox(
634
  'Enable ALMA',
@@ -661,6 +742,7 @@ if 'data' in st.session_state:
661
  help="Specify the sigma for the ALMA."
662
  )
663
 
 
664
  with st.sidebar.expander("MESA Adaptive Moving Average (MAMA) & FAMA", expanded=False):
665
  use_mama_fama = st.checkbox(
666
  'Enable MAMA & FAMA',
@@ -686,6 +768,7 @@ if 'data' in st.session_state:
686
  help="Specify the slow limit for MAMA (0 to 1)."
687
  )
688
 
 
689
  with st.sidebar.expander("Adaptive Period Moving Average (APMA)", expanded=False):
690
  use_apma = st.checkbox(
691
  'Enable APMA',
@@ -709,6 +792,7 @@ if 'data' in st.session_state:
709
  help="Specify the maximum period for the APMA."
710
  )
711
 
 
712
  with st.sidebar.expander("Rainbow Moving Average (EMA)", expanded=False):
713
  use_rainbow_ema = st.checkbox(
714
  'Enable Rainbow EMA',
@@ -723,6 +807,7 @@ if 'data' in st.session_state:
723
  help="Select multiple lookback periods for the Rainbow EMA."
724
  )
725
 
 
726
  with st.sidebar.expander("Wilders Moving Average (Wilder's MA)", expanded=False):
727
  use_wilders_ma = st.checkbox(
728
  'Enable Wilders MA',
@@ -738,6 +823,7 @@ if 'data' in st.session_state:
738
  help="Specify the period (in days) for Wilder's Moving Average."
739
  )
740
 
 
741
  with st.sidebar.expander("Smoothed Moving Average (SMMA)", expanded=False):
742
  use_smma = st.checkbox(
743
  'Enable SMMA',
@@ -753,6 +839,7 @@ if 'data' in st.session_state:
753
  help="Specify the period (in days) for the SMMA."
754
  )
755
 
 
756
  with st.sidebar.expander("Guppy Multiple Moving Average (GMMA)", expanded=False):
757
  use_gmma = st.checkbox(
758
  'Enable GMMA',
@@ -774,6 +861,7 @@ if 'data' in st.session_state:
774
  help="Select the long-term periods for GMMA."
775
  )
776
 
 
777
  with st.sidebar.expander("Least Squares Moving Average (LSMA)", expanded=False):
778
  use_lsma = st.checkbox(
779
  'Enable LSMA',
@@ -789,6 +877,7 @@ if 'data' in st.session_state:
789
  help="Specify the period (in days) for the LSMA."
790
  )
791
 
 
792
  with st.sidebar.expander("Welch's Moving Average (MMA)", expanded=False):
793
  use_mma = st.checkbox(
794
  'Enable MMA',
@@ -804,6 +893,7 @@ if 'data' in st.session_state:
804
  help="Specify the period (in days) for the MMA."
805
  )
806
 
 
807
  with st.sidebar.expander("Sin-weighted Moving Average (SinWMA)", expanded=False):
808
  use_sinwma = st.checkbox(
809
  'Enable SinWMA',
@@ -819,6 +909,7 @@ if 'data' in st.session_state:
819
  help="Specify the period (in days) for the SinWMA."
820
  )
821
 
 
822
  with st.sidebar.expander("Median Moving Average (MedMA)", expanded=False):
823
  use_medma = st.checkbox(
824
  'Enable MedMA',
@@ -834,6 +925,7 @@ if 'data' in st.session_state:
834
  help="Specify the period (in days) for the MedMA."
835
  )
836
 
 
837
  with st.sidebar.expander("Geometric Moving Average (GMA)", expanded=False):
838
  use_gma = st.checkbox(
839
  'Enable GMA',
@@ -849,6 +941,7 @@ if 'data' in st.session_state:
849
  help="Specify the period (in days) for the GMA."
850
  )
851
 
 
852
  with st.sidebar.expander("Elastic Volume Weighted Moving Average (eVWMA)", expanded=False):
853
  use_evwma = st.checkbox(
854
  'Enable eVWMA',
@@ -863,7 +956,8 @@ if 'data' in st.session_state:
863
  disabled=not use_evwma,
864
  help="Specify the period (in days) for the eVWMA."
865
  )
866
-
 
867
  with st.sidebar.expander("Regularized Exponential Moving Average (REMA)", expanded=False):
868
  use_rema = st.checkbox(
869
  'Enable REMA',
@@ -889,6 +983,7 @@ if 'data' in st.session_state:
889
  help="Specify the lambda value for the REMA (0 to 1)."
890
  )
891
 
 
892
  with st.sidebar.expander("Parabolic Weighted Moving Average (PWMA)", expanded=False):
893
  use_pwma = st.checkbox(
894
  'Enable PWMA',
@@ -904,6 +999,7 @@ if 'data' in st.session_state:
904
  help="Specify the period (in days) for the PWMA."
905
  )
906
 
 
907
  with st.sidebar.expander("Jurik Moving Average (JMA)", expanded=False):
908
  use_jma = st.checkbox(
909
  'Enable JMA',
@@ -928,6 +1024,7 @@ if 'data' in st.session_state:
928
  help="Specify the phase for the JMA (-100 to 100)."
929
  )
930
 
 
931
  with st.sidebar.expander("End Point Moving Average (EPMA)", expanded=False):
932
  use_epma = st.checkbox(
933
  'Enable EPMA',
@@ -943,14 +1040,16 @@ if 'data' in st.session_state:
943
  help="Specify the period (in days) for the EPMA."
944
  )
945
 
 
946
  with st.sidebar.expander("Chande Moving Average (CMA)", expanded=False):
947
  use_cma = st.checkbox(
948
  'Enable CMA',
949
  value=st.session_state.get('use_cma', False),
950
  help="Select to apply Chande Moving Average (CMA) to the stock price."
951
  )
952
- cma_period = len(data['Close']) # Automatically use full length
953
 
 
954
  with st.sidebar.expander("McGinley Dynamic", expanded=False):
955
  use_mcginley_dynamic = st.checkbox(
956
  'Enable McGinley Dynamic',
@@ -966,6 +1065,7 @@ if 'data' in st.session_state:
966
  help="Specify the period (in days) for the McGinley Dynamic."
967
  )
968
 
 
969
  with st.sidebar.expander("Filtered Moving Average (FMA)", expanded=False):
970
  use_fma = st.checkbox(
971
  'Enable FMA',
@@ -981,263 +1081,306 @@ if 'data' in st.session_state:
981
  help="Specify the period (in days) for the FMA."
982
  )
983
 
 
984
  show_grid = st.sidebar.checkbox(
985
  "Show Grid",
986
  value=True,
987
  help="Toggle to show or hide the grid on the plot."
988
  )
989
 
 
990
  if st.sidebar.button('Run Analysis'):
991
- st.session_state['use_sma'] = use_sma
992
- st.session_state['sma_period'] = sma_period
993
- st.session_state['use_ema'] = use_ema
994
- st.session_state['ema_period'] = ema_period
995
- st.session_state['use_wma'] = use_wma
996
- st.session_state['wma_period'] = wma_period
997
- st.session_state['use_dema'] = use_dema
998
- st.session_state['dema_period'] = dema_period
999
- st.session_state['use_tema'] = use_tema
1000
- st.session_state['tema_period'] = tema_period
1001
- st.session_state['use_vama'] = use_vama
1002
- st.session_state['vama_period'] = vama_period
1003
- st.session_state['use_kama'] = use_kama
1004
- st.session_state['kama_period'] = kama_period
1005
- st.session_state['fastest_period'] = fastest_period
1006
- st.session_state['slowest_period'] = slowest_period
1007
- st.session_state['use_tma'] = use_tma
1008
- st.session_state['tma_period'] = tma_period
1009
- st.session_state['use_hull_ma'] = use_hull_ma
1010
- st.session_state['hull_ma_period'] = hull_ma_period
1011
- st.session_state['use_harmonic_ma'] = use_harmonic_ma
1012
- st.session_state['harmonic_ma_period'] = harmonic_ma_period
1013
- st.session_state['use_frama'] = use_frama
1014
- st.session_state['frama_batch'] = frama_batch
1015
- st.session_state['use_zlema'] = use_zlema
1016
- st.session_state['zlema_period'] = zlema_period
1017
- st.session_state['use_vidya'] = use_vidya
1018
- st.session_state['vidya_period'] = vidya_period
1019
- st.session_state['use_alma'] = use_alma
1020
- st.session_state['alma_period'] = alma_period
1021
- st.session_state['alma_offset'] = alma_offset
1022
- st.session_state['alma_sigma'] = alma_sigma
1023
- st.session_state['use_mama_fama'] = use_mama_fama
1024
- st.session_state['mama_fast_limit'] = mama_fast_limit
1025
- st.session_state['mama_slow_limit'] = mama_slow_limit
1026
- st.session_state['use_apma'] = use_apma
1027
- st.session_state['apma_min_period'] = apma_min_period
1028
- st.session_state['apma_max_period'] = apma_max_period
1029
- st.session_state['use_rainbow_ema'] = use_rainbow_ema
1030
- st.session_state['rainbow_lookback_periods'] = rainbow_lookback_periods
1031
- st.session_state['use_wilders_ma'] = use_wilders_ma
1032
- st.session_state['wilders_ma_period'] = wilders_ma_period
1033
- st.session_state['use_smma'] = use_smma
1034
- st.session_state['smma_period'] = smma_period
1035
- st.session_state['use_gmma'] = use_gmma
1036
- st.session_state['gmma_short_periods'] = gmma_short_periods
1037
- st.session_state['gmma_long_periods'] = gmma_long_periods
1038
- st.session_state['use_lsma'] = use_lsma
1039
- st.session_state['lsma_period'] = lsma_period
1040
- st.session_state['use_mma'] = use_mma
1041
- st.session_state['mma_period'] = mma_period
1042
- st.session_state['use_sinwma'] = use_sinwma
1043
- st.session_state['sinwma_period'] = sinwma_period
1044
- st.session_state['use_medma'] = use_medma
1045
- st.session_state['medma_period'] = medma_period
1046
- st.session_state['use_gma'] = use_gma
1047
- st.session_state['gma_period'] = gma_period
1048
- st.session_state['use_evwma'] = use_evwma
1049
- st.session_state['evwma_period'] = evwma_period
1050
- st.session_state['use_rema'] = use_rema
1051
- st.session_state['rema_alpha'] = rema_alpha
1052
- st.session_state['rema_lambda'] = rema_lambda
1053
- st.session_state['use_pwma'] = use_pwma
1054
- st.session_state['pwma_period'] = pwma_period
1055
- st.session_state['use_jma'] = use_jma
1056
- st.session_state['jma_period'] = jma_period
1057
- st.session_state['jma_phase'] = jma_phase
1058
- st.session_state['use_epma'] = use_epma
1059
- st.session_state['epma_period'] = epma_period
1060
- st.session_state['use_cma'] = use_cma
1061
- st.session_state['use_mcginley_dynamic'] = use_mcginley_dynamic
1062
- st.session_state['mcginley_dynamic_period'] = mcginley_dynamic_period
1063
- st.session_state['use_fma'] = use_fma
1064
- st.session_state['fma_period'] = fma_period
1065
-
1066
- fig = go.Figure(data=st.session_state['price_plot'].data)
1067
-
1068
- if use_jma:
1069
- st.session_state['JMA'] = jma(data['Close'], length=jma_period, phase=jma_phase)
1070
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['JMA'], mode='lines', name=f'JMA (n={jma_period}, phase={jma_phase})', line=dict(dash='dash', color='green')))
1071
-
1072
- if use_epma:
1073
- st.session_state['EPMA'] = calculate_EPMA(data['Close'].tolist(), epma_period)
1074
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['EPMA'], mode='lines', name=f'EPMA (n={epma_period})', line=dict(dash='dash', color='blue')))
1075
-
1076
- if use_cma:
1077
- st.session_state['CMA'] = calculate_CMA(data['Close'])
1078
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['CMA'], mode='lines', name=f'CMA', line=dict(dash='dash', color='blue')))
1079
-
1080
- if use_mcginley_dynamic:
1081
- st.session_state['McGinley_Dynamic'] = calculate_mcginley_dynamic(data['Close'].tolist(), mcginley_dynamic_period)
1082
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['McGinley_Dynamic'], mode='lines', name=f'McGinley Dynamic (n={mcginley_dynamic_period})', line=dict(dash='dash', color='orange')))
1083
-
1084
- if use_fma:
1085
- st.session_state['FMA'] = filtered_moving_average(data['Close'].values, fma_period)
1086
- fig.add_trace(go.Scatter(x=data.index, y=np.concatenate([np.array([np.nan]*(fma_period-1)), st.session_state['FMA']]), mode='lines', name=f'Filtered MA (n={fma_period})', line=dict(dash='dash', color='green')))
1087
-
1088
- if use_sma:
1089
- st.session_state['SMA'] = data['Close'].rolling(window=sma_period).mean()
1090
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['SMA'], mode='lines', name=f'{sma_period}-Day SMA', line=dict(dash='dash')))
1091
-
1092
- if use_ema:
1093
- st.session_state['EMA'] = data['Close'].ewm(span=ema_period, adjust=False).mean()
1094
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['EMA'], mode='lines', name=f'{ema_period}-Day EMA', line=dict(dash='dash', color='green')))
1095
-
1096
- if use_wma:
1097
- weights = np.arange(1, wma_period + 1)
1098
- st.session_state['WMA'] = data['Close'].rolling(window=wma_period).apply(lambda prices: np.dot(prices, weights)/weights.sum(), raw=True)
1099
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['WMA'], mode='lines', name=f'{wma_period}-Day WMA', line=dict(dash='dash', color='orange')))
1100
-
1101
- if use_dema:
1102
- data['EMA'] = data['Close'].ewm(span=dema_period, adjust=False).mean()
1103
- data['EMA2'] = data['EMA'].ewm(span=dema_period, adjust=False).mean()
1104
- st.session_state['DEMA'] = 2 * data['EMA'] - data['EMA2']
1105
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['DEMA'], mode='lines', name=f'{dema_period}-Day DEMA', line=dict(dash='dash', color='red')))
1106
-
1107
- if use_tema:
1108
- data['EMA'] = data['Close'].ewm(span=tema_period, adjust=False).mean()
1109
- data['EMA2'] = data['EMA'].ewm(span=tema_period, adjust=False).mean()
1110
- data['EMA3'] = data['EMA2'].ewm(span=tema_period, adjust=False).mean()
1111
- st.session_state['TEMA'] = 3 * data['EMA'] - 3 * data['EMA2'] + data['EMA3']
1112
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['TEMA'], mode='lines', name=f'{tema_period}-Day TEMA', line=dict(dash='dash', color='purple')))
1113
-
1114
- if use_vama:
1115
- data['Volume_Price'] = data['Close'] * data['Volume']
1116
- st.session_state['VAMA'] = data['Volume_Price'].rolling(window=vama_period).sum() / data['Volume'].rolling(window=vama_period).sum()
1117
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['VAMA'], mode='lines', name=f'{vama_period}-Day VAMA', line=dict(dash='dash', color='orange')))
1118
-
1119
- if use_kama:
1120
- fastest_SC = 2 / (fastest_period + 1)
1121
- slowest_SC = 2 / (slowest_period + 1)
1122
- data['Change'] = abs(data['Close'] - data['Close'].shift(kama_period))
1123
- data['Volatility'] = data['Close'].diff().abs().rolling(window=kama_period).sum()
1124
- data['ER'] = data['Change'] / data['Volatility']
1125
- data['SC'] = (data['ER'] * (fastest_SC - slowest_SC) + slowest_SC)**2
1126
- data['KAMA'] = data['Close'].copy()
1127
- for i in range(kama_period, len(data)):
1128
- data['KAMA'].iloc[i] = data['KAMA'].iloc[i-1] + data['SC'].iloc[i] * (data['Close'].iloc[i] - data['KAMA'].iloc[i-1])
1129
- st.session_state['KAMA'] = data['KAMA']
1130
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['KAMA'], mode='lines', name=f'KAMA (n={kama_period})', line=dict(dash='dash', color='green')))
1131
-
1132
- if use_tma:
1133
- half_n = (tma_period + 1) // 2
1134
- data['Half_SMA'] = data['Close'].rolling(window=half_n).mean()
1135
- st.session_state['TMA'] = data['Half_SMA'].rolling(window=half_n).mean()
1136
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['TMA'], mode='lines', name=f'TMA (n={tma_period})', line=dict(dash='dash', color='red')))
1137
-
1138
- if use_hull_ma:
1139
- st.session_state['Hull_MA'] = hull_moving_average(data['Close'], hull_ma_period)
1140
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['Hull_MA'], mode='lines', name=f'Hull MA (n={hull_ma_period})', line=dict(dash='dash', color='green')))
1141
-
1142
- if use_harmonic_ma:
1143
- st.session_state['Harmonic_MA'] = calculate_harmonic_moving_average(data['Close'].values, harmonic_ma_period)
1144
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['Harmonic_MA'], mode='lines', name=f'Harmonic MA (n={harmonic_ma_period})', line=dict(dash='dash', color='purple')))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1145
 
1146
- if use_frama:
1147
- st.session_state['FRAMA'] = calculate_FRAMA(data, batch=frama_batch)['FRAMA']
1148
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['FRAMA'], mode='lines', name=f'FRAMA (batch={frama_batch})', line=dict(dash='dash', color='green')))
1149
-
1150
- if use_zlema:
1151
- st.session_state['ZLEMA'] = calculate_ZLEMA(data['Close'].tolist(), zlema_period)
1152
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['ZLEMA'], mode='lines', name=f'ZLEMA (n={zlema_period})', line=dict(dash='dash', color='red')))
1153
-
1154
- if use_vidya:
1155
- st.session_state['VIDYA'] = calculate_VIDYA(data['Close'].tolist(), vidya_period)
1156
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['VIDYA'], mode='lines', name=f'VIDYA (n={vidya_period})', line=dict(dash='dash', color='blue')))
1157
-
1158
- if use_alma:
1159
- st.session_state['ALMA'] = calculate_ALMA(data['Close'].tolist(), alma_period, offset=alma_offset, sigma=alma_sigma)
1160
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['ALMA'], mode='lines', name=f'ALMA (n={alma_period})', line=dict(dash='dash', color='purple')))
1161
-
1162
- if use_mama_fama:
1163
- data['MAMA'], data['FAMA'] = talib.MAMA(data['Close'].values, fastlimit=mama_fast_limit, slowlimit=mama_slow_limit)
1164
- st.session_state['MAMA'] = data['MAMA']
1165
- st.session_state['FAMA'] = data['FAMA']
1166
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['MAMA'], mode='lines', name=f'MAMA', line=dict(dash='dash', color='blue')))
1167
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['FAMA'], mode='lines', name=f'FAMA', line=dict(dash='dash', color='red')))
1168
-
1169
- if use_apma:
1170
- st.session_state['APMA'] = adaptive_period_moving_average(data['Close'].values, min_period=apma_min_period, max_period=apma_max_period)
1171
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['APMA'], mode='lines', name=f'APMA (min={apma_min_period}, max={apma_max_period})', line=dict(dash='dash', color='red')))
1172
-
1173
- if use_rainbow_ema:
1174
- data = calculate_rainbow_ema(data, rainbow_lookback_periods)
1175
- colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet', 'black','gray','brown']
1176
- for i, lookback in enumerate(rainbow_lookback_periods):
1177
- fig.add_trace(go.Scatter(x=data.index, y=data[f'EMA{lookback}'], mode='lines', name=f'EMA {lookback}', line=dict(dash='solid', color=colors[i % len(colors)])))
1178
-
1179
- if use_wilders_ma:
1180
- st.session_state['Wilders_MA'] = wilders_moving_average(data['Close'].tolist(), wilders_ma_period)
1181
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['Wilders_MA'], mode='lines', name=f'Wilders MA (n={wilders_ma_period})', line=dict(dash='dash', color='red')))
1182
-
1183
- if use_smma:
1184
- st.session_state['SMMA'] = calculate_SMMA(data['Close'].tolist(), smma_period)
1185
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['SMMA'], mode='lines', name=f'SMMA (n={smma_period})', line=dict(dash='dash', color='red')))
1186
-
1187
- if use_gmma:
1188
- close_prices = data['Close'].tolist()
1189
- for period in gmma_short_periods:
1190
- data[f'EMA_{period}'] = calculate_EMA(close_prices, period)
1191
- fig.add_trace(go.Scatter(x=data.index, y=data[f'EMA_{period}'], mode='lines', name=f'GMMA Short EMA {period}', line=dict(dash='solid')))
1192
- for period in gmma_long_periods:
1193
- data[f'EMA_{period}'] = calculate_EMA(close_prices, period)
1194
- fig.add_trace(go.Scatter(x=data.index, y=data[f'EMA_{period}'], mode='lines', name=f'GMMA Long EMA {period}', line=dict(dash='dash')))
1195
-
1196
- if use_lsma:
1197
- st.session_state['LSMA'] = calculate_LSMA(data['Close'].tolist(), lsma_period)
1198
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['LSMA'], mode='lines', name=f'LSMA (n={lsma_period})', line=dict(dash='dash', color='blue')))
1199
-
1200
- if use_mma:
1201
- st.session_state['MMA'] = calculate_MMA(data['Close'].tolist(), mma_period)
1202
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['MMA'], mode='lines', name=f'MMA (n={mma_period})', line=dict(dash='dash', color='blue')))
1203
-
1204
- if use_sinwma:
1205
- st.session_state['SinWMA'] = calculate_SinWMA(data['Close'].tolist(), sinwma_period)
1206
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['SinWMA'], mode='lines', name=f'SinWMA (n={sinwma_period})', line=dict(dash='dash', color='green')))
1207
-
1208
- if use_medma:
1209
- st.session_state['MedMA'] = calculate_MedMA(data['Close'].tolist(), medma_period)
1210
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['MedMA'], mode='lines', name=f'MedMA (n={medma_period})', line=dict(dash='dash', color='blue')))
1211
-
1212
- if use_gma:
1213
- st.session_state['GMA'] = calculate_GMA(data['Close'].tolist(), gma_period)
1214
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['GMA'], mode='lines', name=f'GMA (n={gma_period})', line=dict(dash='dash', color='green')))
1215
-
1216
- if use_evwma:
1217
- st.session_state['eVWMA'] = calculate_eVWMA(data['Close'], data['Volume'], evwma_period)
1218
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['eVWMA'], mode='lines', name=f'eVWMA (n={evwma_period})', line=dict(dash='dash', color='blue')))
1219
-
1220
- if use_rema:
1221
- st.session_state['REMA'] = REMA(data['Close'], alpha=rema_alpha, lambda_=rema_lambda)
1222
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['REMA'], mode='lines', name=f'REMA (alpha={rema_alpha}, lambda={rema_lambda})', line=dict(dash='dash', color='red')))
1223
-
1224
- if use_pwma:
1225
- pwma_values = parabolic_weighted_moving_average(data['Close'].values, pwma_period)
1226
- st.session_state['PWMA'] = np.concatenate([np.array([np.nan]*(pwma_period-1)), pwma_values])
1227
- fig.add_trace(go.Scatter(x=data.index, y=st.session_state['PWMA'], mode='lines', name=f'PWMA (n={pwma_period})', line=dict(dash='dash', color='red')))
1228
-
1229
- fig.update_layout(
1230
- title=f'{ticker_symbol} Stock Price with Moving Averages',
1231
- xaxis_title='Date',
1232
- yaxis_title='Stock Price',
1233
- legend_title='Indicators',
1234
- template='plotly_white',
1235
- xaxis=dict(showgrid=show_grid),
1236
- yaxis=dict(showgrid=show_grid)
1237
- )
1238
-
1239
- st.session_state['current_fig'] = fig
1240
 
 
1241
  if 'current_fig' in st.session_state:
1242
  st.plotly_chart(st.session_state['current_fig'], use_container_width=True)
1243
 
@@ -1246,7 +1389,7 @@ st.markdown(
1246
  <style>
1247
  /* Adjust the width of the sidebar */
1248
  [data-testid="stSidebar"] {
1249
- width: 500px;
1250
  }
1251
  </style>
1252
  """,
@@ -1259,4 +1402,4 @@ hide_streamlit_style = """
1259
  footer {visibility: hidden;}
1260
  </style>
1261
  """
1262
- st.markdown(hide_streamlit_style, unsafe_allow_html=True)
 
35
  # Function to fetch data
36
  @st.cache_data
37
  def get_data(ticker, start_date, end_date):
38
+ data = yf.download(ticker, start=start_date, end=end_date, auto_adjust=False)
 
 
39
  if isinstance(data.columns, pd.MultiIndex):
40
+ data.columns = data.columns.get_level_values(0)
41
  if data.empty:
42
  raise ValueError(f"No data retrieved for {ticker}")
43
  if len(data) < 512: # Ensure enough data for largest possible Rainbow MA period
 
134
  # End Point Moving Average (EPMA) Function
135
  def calculate_EPMA(prices, period):
136
  epma_values = []
137
+
138
  for i in range(period - 1, len(prices)):
139
  x = np.arange(period)
140
  y = prices[i-period+1:i+1]
141
+
142
  slope, intercept = np.polyfit(x, y, 1)
143
  epma = slope * (period - 1) + intercept
144
+
145
  epma_values.append(epma)
 
146
 
147
+ return [None]*(period-1) + epma_values # Pad with None for alignment
 
148
 
149
+ # Chande Moving Average (CMA) Function
150
  def calculate_CMA(prices):
151
  cumsum = np.cumsum(prices)
152
  cma = cumsum / (np.arange(len(prices)) + 1)
153
  return cma
154
 
155
+ # Other Moving Average Methods
156
+ # Function to calculate Parabolic Weighted Moving Average (PWMA)
157
  def parabolic_weighted_moving_average(prices, n=14):
158
  weights = np.array([(n-i)**2 for i in range(n)])
159
  return np.convolve(prices, weights/weights.sum(), mode='valid')
160
 
161
+ # Function to calculate Regularized Exponential Moving Average (REMA)
162
  def REMA(prices, alpha=0.1, lambda_=0.1):
163
  rema = [prices[0]]
164
  penalty = 0
165
+
166
  for t in range(1, len(prices)):
167
  second_derivative = prices[t] - 2 * prices[t-1] + prices[t-2] if t-2 >= 0 else 0
168
  penalty = lambda_ * second_derivative
169
  current_rema = alpha * prices[t] + (1 - alpha) * rema[-1] - penalty
170
  rema.append(current_rema)
171
+
172
  return rema
173
 
174
+ # Function to calculate Weighted Moving Average (WMA)
175
  def weighted_moving_average(data, periods):
176
  weights = np.arange(1, periods + 1)
177
  wma = data.rolling(periods).apply(lambda x: np.dot(x, weights) / weights.sum(), raw=True)
178
  return wma
179
 
180
+ # Function to calculate Hull Moving Average (HMA)
181
  def hull_moving_average(data, periods):
182
  wma_half_period = weighted_moving_average(data, int(periods / 2))
183
  wma_full_period = weighted_moving_average(data, periods)
184
  hma = weighted_moving_average(2 * wma_half_period - wma_full_period, int(np.sqrt(periods)))
185
  return hma
186
 
187
+ # Function to calculate Harmonic Moving Average (HMA) to avoid conflict with Hull
188
  def harmonic_moving_average(data, period):
189
  def harmonic_mean(prices):
190
  return period / np.sum(1.0 / prices)
191
+
192
  hma_values = []
193
  for i in range(period - 1, len(data)):
194
  hma_values.append(harmonic_mean(data[i - period + 1:i + 1]))
195
+
196
  return [np.nan] * (period - 1) + hma_values
197
 
198
+ # Function to calculate Fractal Adaptive Moving Average (FRAMA)
199
  def calculate_FRAMA(data, batch=10):
200
  InputPrice = data['Close'].values
201
  Length = len(InputPrice)
202
  Filt = np.array(InputPrice)
203
+
204
  for i in range(2 * batch, Length):
205
  v1 = InputPrice[i-2*batch:i - batch]
206
  v2 = InputPrice[i - batch:i]
207
+
208
  H1 = np.max(v1)
209
  L1 = np.min(v1)
210
  N1 = (H1 - L1) / batch
211
+
212
  H2 = np.max(v2)
213
  L2 = np.min(v2)
214
  N2 = (H2 - L2) / batch
215
+
216
  H = np.max([H1, H2])
217
  L = np.min([L1, L2])
218
  N3 = (H - L) / (2 * batch)
219
+
220
  Dimen = 0
221
  if N1 > 0 and N2 > 0 and N3 > 0:
222
  Dimen = (np.log(N1 + N2) - np.log(N3)) / np.log(2)
223
+
224
  alpha = np.exp(-4.6 * Dimen - 1)
225
  alpha = np.clip(alpha, 0.1, 1)
226
+
227
  Filt[i] = alpha * InputPrice[i] + (1 - alpha) * Filt[i-1]
228
+
229
  data['FRAMA'] = Filt
230
  return data
231
 
232
+ # Function to calculate Exponential Moving Average (EMA)
233
  def calculate_EMA(prices, period):
234
  alpha = 2 / (period + 1)
235
  EMA = [prices[0]]
 
237
  EMA.append((price - EMA[-1]) * alpha + EMA[-1])
238
  return EMA
239
 
240
+ # Function to calculate Zero Lag Exponential Moving Average (ZLEMA)
241
  def calculate_ZLEMA(prices, period):
242
  lag = period // 2
243
  adjusted_prices = [2 * prices[i] - (prices[i - lag] if i >= lag else prices[0]) for i in range(len(prices))]
244
  ZLEMA = calculate_EMA(adjusted_prices, period)
245
  return ZLEMA
246
 
247
+ # Function to calculate Chande Momentum Oscillator (CMO)
248
  def calculate_CMO(prices, period):
249
  deltas = np.diff(prices)
250
  sum_gains = np.cumsum(np.where(deltas >= 0, deltas, 0))
251
  sum_losses = np.abs(np.cumsum(np.where(deltas < 0, deltas, 0)))
252
+
253
  cmo = 100 * (sum_gains - sum_losses) / (sum_gains + sum_losses)
254
+ return np.insert(cmo, 0, 0) # Add a zero at the beginning for alignment
255
 
256
+ # Function to calculate Variable Index Dynamic Average (VIDYA)
257
  def calculate_VIDYA(prices, period):
258
  cmo_values = calculate_CMO(prices, period)
259
  vidya = [prices[0]]
260
+
261
  for i in range(1, len(prices)):
262
+ alpha = abs(cmo_values[i]) / 100 # Normalize CMO to [0, 1]
263
  vidya.append((1 - alpha) * vidya[-1] + alpha * prices[i])
264
+
265
  return vidya
266
 
267
+ # Function to calculate Arnaud Legoux Moving Average (ALMA)
268
  def calculate_ALMA(prices, period, offset=0.85, sigma=6):
269
  m = np.floor(offset * (period - 1))
270
  s = period / sigma
271
  alma = []
272
+
273
  for i in range(period - 1, len(prices)):
274
  weights = [np.exp(- (j - m)**2 / (2 * s * s)) for j in range(period)]
275
  sum_weights = sum(weights)
276
  normalized_weights = [w/sum_weights for w in weights]
277
+
278
  window = prices[i-period+1:i+1]
279
  alma_value = sum([normalized_weights[j] * window[j] for j in range(period)])
280
  alma.append(alma_value)
 
281
 
282
+ return [None]*(period-1) + alma # Pad the beginning with None for alignment
283
+
284
+ # Function to calculate Adaptive Period Moving Average (APMA)
285
  def adaptive_period_moving_average(prices, min_period=5, max_period=30):
286
  atr = np.zeros_like(prices)
287
  adjusted_periods = np.zeros_like(prices)
288
+ moving_averages = np.full_like(prices, np.nan) # Initialize with NaN values
289
+
290
  for i in range(1, len(prices)):
291
  atr[i] = atr[i-1] + (abs(prices[i] - prices[i-1]) - atr[i-1]) / 14
292
+
293
  min_volatility = atr[1:i+1].min()
294
  max_volatility = atr[1:i+1].max()
295
+
296
  if max_volatility == min_volatility:
297
  adjusted_period = min_period
298
  else:
299
  adjusted_period = int(((max_period - min_period) / (max_volatility - min_volatility)) * (atr[i] - min_volatility) + min_period)
300
+
301
  adjusted_periods[i] = adjusted_period
302
+
303
  if i >= adjusted_period:
304
  moving_averages[i] = np.mean(prices[i-adjusted_period+1:i+1])
305
+
306
  return moving_averages
307
 
308
+ # Function to calculate Rainbow Moving Average (Rainbow EMA)
309
  def calculate_rainbow_ema(data, lookback_periods):
310
  for lookback in lookback_periods:
311
  data[f'EMA{lookback}'] = data['Close'].ewm(span=lookback).mean()
312
  return data
313
 
314
+ # Function to calculate Wilders Moving Average
315
  def wilders_moving_average(prices, period):
316
  wilder = [prices[0]]
317
  for price in prices[1:]:
 
319
  wilder.append(wilder_value)
320
  return wilder
321
 
322
+ # Function to calculate Smoothed Moving Average (SMMA)
323
  def calculate_SMMA(prices, n):
324
+ SMMA = [np.nan] * (n-1) # Fill the initial n-1 values with NaN
325
  SMMA.append(sum(prices[:n]) / n)
326
  for i in range(n, len(prices)):
327
  smma_value = (SMMA[-1] * (n - 1) + prices[i]) / n
328
  SMMA.append(smma_value)
329
  return SMMA
330
 
331
+ # Function to calculate Least Squares Moving Average (LSMA)
332
  def calculate_LSMA(prices, period):
333
  n = period
334
  x = np.array(range(1, n+1))
335
+
336
  LSMA = []
337
  for i in range(len(prices) - period + 1):
338
  y = prices[i:i+period]
339
  m = (n*np.sum(x*y) - np.sum(x)*np.sum(y)) / (n*np.sum(x**2) - np.sum(x)**2)
340
  c = (np.sum(y) - m*np.sum(x)) / n
341
+ LSMA.append(m * n + c) # The projected value at the end of the period
342
+
343
+ # Padding the beginning with NaNs for alignment
344
  LSMA = [np.nan] * (period-1) + LSMA
345
  return LSMA
346
 
347
+ # Function to calculate Welch's Moving Average (Modified Moving Average, MMA)
348
  def calculate_MMA(prices, period):
349
+ MMA = [sum(prices[:period]) / period] # Start with the SMA for the first value
350
  for t in range(period, len(prices)):
351
  MMA.append((prices[t] + (period - 1) * MMA[-1]) / period)
352
+ return [None]*(period-1) + MMA # Pad the beginning with None for alignment
353
 
354
+ # Function to calculate Sin-weighted Moving Average (SinWMA)
355
  def calculate_SinWMA(prices, period):
356
  weights = [np.sin(np.pi * i / (period + 1)) for i in range(1, period+1)]
357
  sum_weights = sum(weights)
358
  normalized_weights = [w/sum_weights for w in weights]
359
+
360
  SinWMA = []
361
  for t in range(period - 1, len(prices)):
362
  window = prices[t-period+1:t+1]
363
  SinWMA.append(sum([normalized_weights[i] * window[i] for i in range(period)]))
 
364
 
365
+ return [None]*(period-1) + SinWMA # Pad the beginning with None for alignment
366
+
367
+ # Function to calculate Median Moving Average (MedMA)
368
  def calculate_MedMA(prices, window):
369
  medians = []
370
  for i in range(len(prices)):
 
375
  medians.append(median)
376
  return medians
377
 
378
+ # Function to calculate Geometric Moving Average (GMA)
379
  def calculate_GMA(prices, window):
380
  gm_avg = []
381
  for i in range(len(prices)):
 
387
  gm_avg.append(gma_value)
388
  return gm_avg
389
 
390
+ # Function to calculate Elastic Volume Weighted Moving Average (eVWMA)
391
  def calculate_eVWMA(prices, volumes, window):
392
  evwma_values = []
393
  for i in range(len(prices)):
 
402
  evwma_values.append(evwma)
403
  return evwma_values
404
 
405
+ # Function to calculate McGinley Dynamic (MD)
406
  def calculate_mcginley_dynamic(prices, n):
407
  MD = [prices[0]]
408
  for i in range(1, len(prices)):
 
410
  MD.append(md_value)
411
  return MD
412
 
413
+ # Function to calculate Anchored Moving Average (AMA)
414
  from datetime import datetime
415
+
416
  def calculate_AMA(prices, anchor_date, data):
417
+ # Ensure the anchor_date is a pandas Timestamp
418
  anchor_date = pd.to_datetime(anchor_date)
419
+
420
  try:
421
  anchor_idx = data.index.get_loc(anchor_date)
422
  except KeyError:
423
+ # If the exact date is not found, find the nearest available date
424
  anchor_date = data.index[data.index.get_loc(anchor_date, method='nearest')]
425
  anchor_idx = data.index.get_loc(anchor_date)
426
+
427
  AMA = []
428
+
429
  for i in range(len(prices)):
430
  if i < anchor_idx:
431
  AMA.append(None)
432
  else:
433
  AMA.append(sum(prices[anchor_idx:i+1]) / (i - anchor_idx + 1))
434
+
435
  return AMA
436
 
437
+ # Function to calculate Filtered Moving Average (FMA)
438
  def filtered_moving_average(prices, n=14):
439
+ # Define filter weights (for simplicity, we'll use equal weights similar to SMA)
440
  w = np.ones(n) / n
441
  return np.convolve(prices, w, mode='valid')
442
 
443
  # Sidebar for user inputs
444
  st.sidebar.header("Select Parameters")
445
 
446
+ # Ticker input with tooltip
447
  ticker_symbol = st.sidebar.text_input(
448
  "Ticker or Crypto Pair",
449
  value=st.session_state.get('ticker_symbol', 'BTC-USD'),
450
  help="Enter the ticker symbol (e.g., AAPL for Apple) or Cryptocurrency Pair (e.g. BTC-USD)."
451
  )
452
 
453
+ # Date range inputs with tooltip
454
  start_date = st.sidebar.date_input(
455
  "Start Date",
456
  value=st.session_state.get('start_date', pd.to_datetime("2020-01-01")),
 
462
  help="Select the end date for fetching the stock data."
463
  )
464
 
465
+ # Fetch Data button
466
  if st.sidebar.button('Fetch Data'):
467
  try:
468
+ # Only fetch if the ticker or date range has changed
469
  if (
470
  ticker_symbol != st.session_state.get('ticker_symbol') or
471
  start_date != st.session_state.get('start_date') or
 
481
  except Exception as e:
482
  st.error(f"An error occurred while fetching data: {e}")
483
 
484
+ # Check if data is fetched and stored in session state
485
  if 'data' in st.session_state:
486
  data = st.session_state['data']
487
 
488
+ # Moving average method selection
489
  with st.sidebar.expander("Simple Moving Average", expanded=False):
490
  use_sma = st.checkbox(
491
  'Simple Moving Average (SMA)',
 
501
  help="Specify the period (in days) for the SMA."
502
  )
503
 
504
+ # EMA with tooltip
505
  with st.sidebar.expander("Exponential Moving Average (EMA)", expanded=False):
506
  use_ema = st.checkbox(
507
  'Enable EMA',
 
517
  help="Specify the period (in days) for the EMA."
518
  )
519
 
520
+ # WMA with tooltip
521
  with st.sidebar.expander("Weighted Moving Average (WMA)", expanded=False):
522
  use_wma = st.checkbox(
523
  'Enable WMA',
 
533
  help="Specify the period (in days) for the WMA."
534
  )
535
 
536
+ # DEMA with tooltip
537
  with st.sidebar.expander("Double Exponential Moving Average (DEMA)", expanded=False):
538
  use_dema = st.checkbox(
539
  'Enable DEMA',
 
549
  help="Specify the period (in days) for the DEMA."
550
  )
551
 
552
+ # TEMA with tooltip
553
  with st.sidebar.expander("Triple Exponential Moving Average (TEMA)", expanded=False):
554
  use_tema = st.checkbox(
555
  'Enable TEMA',
 
565
  help="Specify the period (in days) for the TEMA."
566
  )
567
 
568
+ # VAMA with tooltip
569
  with st.sidebar.expander("Volume-Adjusted Moving Average (VAMA)", expanded=False):
570
  use_vama = st.checkbox(
571
  'Enable VAMA',
 
581
  help="Specify the period (in days) for the VAMA."
582
  )
583
 
584
+ # KAMA with tooltip
585
  with st.sidebar.expander("Kaufman Adaptive Moving Average (KAMA)", expanded=False):
586
  use_kama = st.checkbox(
587
  'Enable KAMA',
 
613
  help="Specify the slowest smoothing constant period."
614
  )
615
 
616
+ # TMA with tooltip
617
  with st.sidebar.expander("Triangular Moving Average (TMA)", expanded=False):
618
  use_tma = st.checkbox(
619
  'Enable TMA',
 
628
  disabled=not use_tma,
629
  help="Specify the period (in days) for the TMA."
630
  )
631
+
632
+ # Hull MA with tooltip
633
  with st.sidebar.expander("Hull Moving Average (HMA)", expanded=False):
634
  use_hull_ma = st.checkbox(
635
  'Enable HMA',
 
645
  help="Specify the period (in days) for the Hull Moving Average."
646
  )
647
 
648
+ # Harmonic MA with tooltip
649
  with st.sidebar.expander("Harmonic Moving Average (HMA)", expanded=False):
650
  use_harmonic_ma = st.checkbox(
651
  'Enable HMA',
 
661
  help="Specify the period (in days) for the Harmonic Moving Average."
662
  )
663
 
664
+ # FRAMA with tooltip
665
  with st.sidebar.expander("Fractal Adaptive Moving Average (FRAMA)", expanded=False):
666
  use_frama = st.checkbox(
667
  'Enable FRAMA',
 
677
  help="Specify the batch size for FRAMA calculation."
678
  )
679
 
680
+ # ZLEMA with tooltip
681
  with st.sidebar.expander("Zero Lag Exponential Moving Average (ZLEMA)", expanded=False):
682
  use_zlema = st.checkbox(
683
  'Enable ZLEMA',
 
693
  help="Specify the period (in days) for the ZLEMA."
694
  )
695
 
696
+ # VIDYA with tooltip
697
  with st.sidebar.expander("Variable Index Dynamic Average (VIDYA)", expanded=False):
698
  use_vidya = st.checkbox(
699
  'Enable VIDYA',
 
709
  help="Specify the period (in days) for the VIDYA."
710
  )
711
 
712
+ # ALMA with tooltip
713
  with st.sidebar.expander("Arnaud Legoux Moving Average (ALMA)", expanded=False):
714
  use_alma = st.checkbox(
715
  'Enable ALMA',
 
742
  help="Specify the sigma for the ALMA."
743
  )
744
 
745
+ # MAMA and FAMA with tooltip
746
  with st.sidebar.expander("MESA Adaptive Moving Average (MAMA) & FAMA", expanded=False):
747
  use_mama_fama = st.checkbox(
748
  'Enable MAMA & FAMA',
 
768
  help="Specify the slow limit for MAMA (0 to 1)."
769
  )
770
 
771
+ # APMA with tooltip
772
  with st.sidebar.expander("Adaptive Period Moving Average (APMA)", expanded=False):
773
  use_apma = st.checkbox(
774
  'Enable APMA',
 
792
  help="Specify the maximum period for the APMA."
793
  )
794
 
795
+ # Rainbow EMA with tooltip
796
  with st.sidebar.expander("Rainbow Moving Average (EMA)", expanded=False):
797
  use_rainbow_ema = st.checkbox(
798
  'Enable Rainbow EMA',
 
807
  help="Select multiple lookback periods for the Rainbow EMA."
808
  )
809
 
810
+ # Wilders MA with tooltip
811
  with st.sidebar.expander("Wilders Moving Average (Wilder's MA)", expanded=False):
812
  use_wilders_ma = st.checkbox(
813
  'Enable Wilders MA',
 
823
  help="Specify the period (in days) for Wilder's Moving Average."
824
  )
825
 
826
+ # SMMA with tooltip
827
  with st.sidebar.expander("Smoothed Moving Average (SMMA)", expanded=False):
828
  use_smma = st.checkbox(
829
  'Enable SMMA',
 
839
  help="Specify the period (in days) for the SMMA."
840
  )
841
 
842
+ # GMMA with tooltip
843
  with st.sidebar.expander("Guppy Multiple Moving Average (GMMA)", expanded=False):
844
  use_gmma = st.checkbox(
845
  'Enable GMMA',
 
861
  help="Select the long-term periods for GMMA."
862
  )
863
 
864
+ # LSMA with tooltip
865
  with st.sidebar.expander("Least Squares Moving Average (LSMA)", expanded=False):
866
  use_lsma = st.checkbox(
867
  'Enable LSMA',
 
877
  help="Specify the period (in days) for the LSMA."
878
  )
879
 
880
+ # MMA (Welch's MMA) with tooltip
881
  with st.sidebar.expander("Welch's Moving Average (MMA)", expanded=False):
882
  use_mma = st.checkbox(
883
  'Enable MMA',
 
893
  help="Specify the period (in days) for the MMA."
894
  )
895
 
896
+ # SinWMA with tooltip
897
  with st.sidebar.expander("Sin-weighted Moving Average (SinWMA)", expanded=False):
898
  use_sinwma = st.checkbox(
899
  'Enable SinWMA',
 
909
  help="Specify the period (in days) for the SinWMA."
910
  )
911
 
912
+ # MedMA with tooltip
913
  with st.sidebar.expander("Median Moving Average (MedMA)", expanded=False):
914
  use_medma = st.checkbox(
915
  'Enable MedMA',
 
925
  help="Specify the period (in days) for the MedMA."
926
  )
927
 
928
+ # GMA with tooltip
929
  with st.sidebar.expander("Geometric Moving Average (GMA)", expanded=False):
930
  use_gma = st.checkbox(
931
  'Enable GMA',
 
941
  help="Specify the period (in days) for the GMA."
942
  )
943
 
944
+ # eVWMA with tooltip
945
  with st.sidebar.expander("Elastic Volume Weighted Moving Average (eVWMA)", expanded=False):
946
  use_evwma = st.checkbox(
947
  'Enable eVWMA',
 
956
  disabled=not use_evwma,
957
  help="Specify the period (in days) for the eVWMA."
958
  )
959
+
960
+ # REMA with tooltip
961
  with st.sidebar.expander("Regularized Exponential Moving Average (REMA)", expanded=False):
962
  use_rema = st.checkbox(
963
  'Enable REMA',
 
983
  help="Specify the lambda value for the REMA (0 to 1)."
984
  )
985
 
986
+ # PWMA with tooltip
987
  with st.sidebar.expander("Parabolic Weighted Moving Average (PWMA)", expanded=False):
988
  use_pwma = st.checkbox(
989
  'Enable PWMA',
 
999
  help="Specify the period (in days) for the PWMA."
1000
  )
1001
 
1002
+ # JMA with tooltip
1003
  with st.sidebar.expander("Jurik Moving Average (JMA)", expanded=False):
1004
  use_jma = st.checkbox(
1005
  'Enable JMA',
 
1024
  help="Specify the phase for the JMA (-100 to 100)."
1025
  )
1026
 
1027
+ # EPMA with tooltip
1028
  with st.sidebar.expander("End Point Moving Average (EPMA)", expanded=False):
1029
  use_epma = st.checkbox(
1030
  'Enable EPMA',
 
1040
  help="Specify the period (in days) for the EPMA."
1041
  )
1042
 
1043
+ # CMA with tooltip
1044
  with st.sidebar.expander("Chande Moving Average (CMA)", expanded=False):
1045
  use_cma = st.checkbox(
1046
  'Enable CMA',
1047
  value=st.session_state.get('use_cma', False),
1048
  help="Select to apply Chande Moving Average (CMA) to the stock price."
1049
  )
1050
+ cma_period = len(data['Close']) # This does not require user input.
1051
 
1052
+ # McGinley Dynamic with tooltip
1053
  with st.sidebar.expander("McGinley Dynamic", expanded=False):
1054
  use_mcginley_dynamic = st.checkbox(
1055
  'Enable McGinley Dynamic',
 
1065
  help="Specify the period (in days) for the McGinley Dynamic."
1066
  )
1067
 
1068
+ # Filtered Moving Average (FMA) with tooltip
1069
  with st.sidebar.expander("Filtered Moving Average (FMA)", expanded=False):
1070
  use_fma = st.checkbox(
1071
  'Enable FMA',
 
1081
  help="Specify the period (in days) for the FMA."
1082
  )
1083
 
1084
+ # Grid toggle with tooltip
1085
  show_grid = st.sidebar.checkbox(
1086
  "Show Grid",
1087
  value=True,
1088
  help="Toggle to show or hide the grid on the plot."
1089
  )
1090
 
1091
+ # Run button to apply moving averages
1092
  if st.sidebar.button('Run Analysis'):
1093
+ try:
1094
+ # Save the moving average settings to session state
1095
+ st.session_state['use_sma'] = use_sma
1096
+ st.session_state['sma_period'] = sma_period
1097
+ st.session_state['use_ema'] = use_ema
1098
+ st.session_state['ema_period'] = ema_period
1099
+ st.session_state['use_wma'] = use_wma
1100
+ st.session_state['wma_period'] = wma_period
1101
+ st.session_state['use_dema'] = use_dema
1102
+ st.session_state['dema_period'] = dema_period
1103
+ st.session_state['use_tema'] = use_tema
1104
+ st.session_state['tema_period'] = tema_period
1105
+ st.session_state['use_vama'] = use_vama
1106
+ st.session_state['vama_period'] = vama_period
1107
+ st.session_state['use_kama'] = use_kama
1108
+ st.session_state['kama_period'] = kama_period
1109
+ st.session_state['fastest_period'] = fastest_period
1110
+ st.session_state['slowest_period'] = slowest_period
1111
+ st.session_state['use_tma'] = use_tma
1112
+ st.session_state['tma_period'] = tma_period
1113
+ st.session_state['use_hull_ma'] = use_hull_ma
1114
+ st.session_state['hull_ma_period'] = hull_ma_period
1115
+ st.session_state['use_harmonic_ma'] = use_harmonic_ma
1116
+ st.session_state['harmonic_ma_period'] = harmonic_ma_period
1117
+ st.session_state['use_frama'] = use_frama
1118
+ st.session_state['frama_batch'] = frama_batch
1119
+ st.session_state['use_zlema'] = use_zlema
1120
+ st.session_state['zlema_period'] = zlema_period
1121
+ st.session_state['use_vidya'] = use_vidya
1122
+ st.session_state['vidya_period'] = vidya_period
1123
+ st.session_state['use_alma'] = use_alma
1124
+ st.session_state['alma_period'] = alma_period
1125
+ st.session_state['alma_offset'] = alma_offset
1126
+ st.session_state['alma_sigma'] = alma_sigma
1127
+ st.session_state['use_mama_fama'] = use_mama_fama
1128
+ st.session_state['mama_fast_limit'] = mama_fast_limit
1129
+ st.session_state['mama_slow_limit'] = mama_slow_limit
1130
+ st.session_state['use_apma'] = use_apma
1131
+ st.session_state['apma_min_period'] = apma_min_period
1132
+ st.session_state['apma_max_period'] = apma_max_period
1133
+ st.session_state['use_rainbow_ema'] = use_rainbow_ema
1134
+ st.session_state['rainbow_lookback_periods'] = rainbow_lookback_periods
1135
+ st.session_state['use_wilders_ma'] = use_wilders_ma
1136
+ st.session_state['wilders_ma_period'] = wilders_ma_period
1137
+ st.session_state['use_smma'] = use_smma
1138
+ st.session_state['smma_period'] = smma_period
1139
+ st.session_state['use_gmma'] = use_gmma
1140
+ st.session_state['gmma_short_periods'] = gmma_short_periods
1141
+ st.session_state['gmma_long_periods'] = gmma_long_periods
1142
+ st.session_state['use_lsma'] = use_lsma
1143
+ st.session_state['lsma_period'] = lsma_period
1144
+ st.session_state['use_mma'] = use_mma
1145
+ st.session_state['mma_period'] = mma_period
1146
+ st.session_state['use_sinwma'] = use_sinwma
1147
+ st.session_state['sinwma_period'] = sinwma_period
1148
+ st.session_state['use_medma'] = use_medma
1149
+ st.session_state['medma_period'] = medma_period
1150
+ st.session_state['use_gma'] = use_gma
1151
+ st.session_state['gma_period'] = gma_period
1152
+ st.session_state['use_evwma'] = use_evwma
1153
+ st.session_state['evwma_period'] = evwma_period
1154
+ st.session_state['use_rema'] = use_rema
1155
+ st.session_state['rema_alpha'] = rema_alpha
1156
+ st.session_state['rema_lambda'] = rema_lambda
1157
+ st.session_state['use_pwma'] = use_pwma
1158
+ st.session_state['pwma_period'] = pwma_period
1159
+ st.session_state['use_jma'] = use_jma
1160
+ st.session_state['jma_period'] = jma_period
1161
+ st.session_state['jma_phase'] = jma_phase
1162
+ st.session_state['use_epma'] = use_epma
1163
+ st.session_state['epma_period'] = epma_period
1164
+ st.session_state['use_cma'] = use_cma
1165
+ st.session_state['use_mcginley_dynamic'] = use_mcginley_dynamic
1166
+ st.session_state['mcginley_dynamic_period'] = mcginley_dynamic_period
1167
+ st.session_state['use_fma'] = use_fma
1168
+ st.session_state['fma_period'] = fma_period
1169
+
1170
+ # Start with the base price plot
1171
+ fig = go.Figure(data=st.session_state['price_plot'].data)
1172
+
1173
+ # Add JMA if selected
1174
+ if use_jma:
1175
+ st.session_state['JMA'] = jma(data['Close'], length=jma_period, phase=jma_phase)
1176
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['JMA'], mode='lines', name=f'JMA (n={jma_period}, phase={jma_phase})', line=dict(dash='dash', color='green')))
1177
+
1178
+ # Add EPMA if selected
1179
+ if use_epma:
1180
+ st.session_state['EPMA'] = calculate_EPMA(data['Close'].tolist(), epma_period)
1181
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['EPMA'], mode='lines', name=f'EPMA (n={epma_period})', line=dict(dash='dash', color='blue')))
1182
+
1183
+ # Add CMA if selected
1184
+ if use_cma:
1185
+ st.session_state['CMA'] = calculate_CMA(data['Close'])
1186
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['CMA'], mode='lines', name=f'CMA', line=dict(dash='dash', color='blue')))
1187
+
1188
+ # Add McGinley Dynamic if selected
1189
+ if use_mcginley_dynamic:
1190
+ st.session_state['McGinley_Dynamic'] = calculate_mcginley_dynamic(data['Close'].tolist(), mcginley_dynamic_period)
1191
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['McGinley_Dynamic'], mode='lines', name=f'McGinley Dynamic (n={mcginley_dynamic_period})', line=dict(dash='dash', color='orange')))
1192
+
1193
+ # Add FMA if selected
1194
+ if use_fma:
1195
+ st.session_state['FMA'] = filtered_moving_average(data['Close'].values, fma_period)
1196
+ fig.add_trace(go.Scatter(x=data.index, y=np.concatenate([np.array([np.nan]*(fma_period-1)), st.session_state['FMA']]), mode='lines', name=f'Filtered MA (n={fma_period})', line=dict(dash='dash', color='green')))
1197
+
1198
+ # Add SMA if selected
1199
+ if use_sma:
1200
+ st.session_state['SMA'] = data['Close'].rolling(window=sma_period).mean()
1201
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['SMA'], mode='lines', name=f'{sma_period}-Day SMA', line=dict(dash='dash')))
1202
+
1203
+ # Add EMA if selected
1204
+ if use_ema:
1205
+ st.session_state['EMA'] = data['Close'].ewm(span=ema_period, adjust=False).mean()
1206
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['EMA'], mode='lines', name=f'{ema_period}-Day EMA', line=dict(dash='dash', color='green')))
1207
+
1208
+ # Add WMA if selected
1209
+ if use_wma:
1210
+ weights = np.arange(1, wma_period + 1)
1211
+ st.session_state['WMA'] = data['Close'].rolling(window=wma_period).apply(lambda prices: np.dot(prices, weights)/weights.sum(), raw=True)
1212
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['WMA'], mode='lines', name=f'{wma_period}-Day WMA', line=dict(dash='dash', color='orange')))
1213
+
1214
+ # Add DEMA if selected
1215
+ if use_dema:
1216
+ data['EMA'] = data['Close'].ewm(span=dema_period, adjust=False).mean()
1217
+ data['EMA2'] = data['EMA'].ewm(span=dema_period, adjust=False).mean()
1218
+ st.session_state['DEMA'] = 2 * data['EMA'] - data['EMA2']
1219
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['DEMA'], mode='lines', name=f'{dema_period}-Day DEMA', line=dict(dash='dash', color='red')))
1220
+
1221
+ # Add TEMA if selected
1222
+ if use_tema:
1223
+ data['EMA'] = data['Close'].ewm(span=tema_period, adjust=False).mean()
1224
+ data['EMA2'] = data['EMA'].ewm(span=tema_period, adjust=False).mean()
1225
+ data['EMA3'] = data['EMA2'].ewm(span=tema_period, adjust=False).mean()
1226
+ st.session_state['TEMA'] = 3 * data['EMA'] - 3 * data['EMA2'] + data['EMA3']
1227
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['TEMA'], mode='lines', name=f'{tema_period}-Day TEMA', line=dict(dash='dash', color='purple')))
1228
+
1229
+ # Add VAMA if selected
1230
+ if use_vama:
1231
+ data['Volume_Price'] = data['Close'] * data['Volume']
1232
+ st.session_state['VAMA'] = data['Volume_Price'].rolling(window=vama_period).sum() / data['Volume'].rolling(window=vama_period).sum()
1233
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['VAMA'], mode='lines', name=f'{vama_period}-Day VAMA', line=dict(dash='dash', color='orange')))
1234
+
1235
+ # Add KAMA if selected
1236
+ if use_kama:
1237
+ fastest_SC = 2 / (fastest_period + 1)
1238
+ slowest_SC = 2 / (slowest_period + 1)
1239
+ data['Change'] = abs(data['Close'] - data['Close'].shift(kama_period))
1240
+ data['Volatility'] = data['Close'].diff().abs().rolling(window=kama_period).sum()
1241
+ data['ER'] = data['Change'] / data['Volatility']
1242
+ data['SC'] = (data['ER'] * (fastest_SC - slowest_SC) + slowest_SC)**2
1243
+ data['KAMA'] = data['Close'].copy()
1244
+ for i in range(kama_period, len(data)):
1245
+ data['KAMA'].iloc[i] = data['KAMA'].iloc[i-1] + data['SC'].iloc[i] * (data['Close'].iloc[i] - data['KAMA'].iloc[i-1])
1246
+ st.session_state['KAMA'] = data['KAMA']
1247
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['KAMA'], mode='lines', name=f'KAMA (n={kama_period})', line=dict(dash='dash', color='green')))
1248
+
1249
+ # Add TMA if selected
1250
+ if use_tma:
1251
+ half_n = (tma_period + 1) // 2
1252
+ data['Half_SMA'] = data['Close'].rolling(window=half_n).mean()
1253
+ st.session_state['TMA'] = data['Half_SMA'].rolling(window=half_n).mean()
1254
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['TMA'], mode='lines', name=f'TMA (n={tma_period})', line=dict(dash='dash', color='red')))
1255
+
1256
+ # Add Hull MA if selected
1257
+ if use_hull_ma:
1258
+ st.session_state['Hull_MA'] = hull_moving_average(data['Close'], hull_ma_period)
1259
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['Hull_MA'], mode='lines', name=f'Hull MA (n={hull_ma_period})', line=dict(dash='dash', color='green')))
1260
+
1261
+ # Add Harmonic MA if selected
1262
+ if use_harmonic_ma:
1263
+ st.session_state['Harmonic_MA'] = calculate_harmonic_moving_average(data['Close'].values, harmonic_ma_period)
1264
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['Harmonic_MA'], mode='lines', name=f'Harmonic MA (n={harmonic_ma_period})', line=dict(dash='dash', color='purple')))
1265
+
1266
+ # Add FRAMA if selected
1267
+ if use_frama:
1268
+ st.session_state['FRAMA'] = calculate_FRAMA(data, batch=frama_batch)['FRAMA']
1269
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['FRAMA'], mode='lines', name=f'FRAMA (batch={frama_batch})', line=dict(dash='dash', color='green')))
1270
+
1271
+ # Add ZLEMA if selected
1272
+ if use_zlema:
1273
+ st.session_state['ZLEMA'] = calculate_ZLEMA(data['Close'].tolist(), zlema_period)
1274
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['ZLEMA'], mode='lines', name=f'ZLEMA (n={zlema_period})', line=dict(dash='dash', color='red')))
1275
+
1276
+ # Add VIDYA if selected
1277
+ if use_vidya:
1278
+ st.session_state['VIDYA'] = calculate_VIDYA(data['Close'].tolist(), vidya_period)
1279
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['VIDYA'], mode='lines', name=f'VIDYA (n={vidya_period})', line=dict(dash='dash', color='blue')))
1280
+
1281
+ # Add ALMA if selected
1282
+ if use_alma:
1283
+ st.session_state['ALMA'] = calculate_ALMA(data['Close'].tolist(), alma_period, offset=alma_offset, sigma=alma_sigma)
1284
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['ALMA'], mode='lines', name=f'ALMA (n={alma_period})', line=dict(dash='dash', color='purple')))
1285
+
1286
+ # Add MAMA and FAMA if selected
1287
+ if use_mama_fama:
1288
+ data['MAMA'], data['FAMA'] = talib.MAMA(data['Close'].values, fastlimit=mama_fast_limit, slowlimit=mama_slow_limit)
1289
+ st.session_state['MAMA'] = data['MAMA']
1290
+ st.session_state['FAMA'] = data['FAMA']
1291
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['MAMA'], mode='lines', name=f'MAMA', line=dict(dash='dash', color='blue')))
1292
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['FAMA'], mode='lines', name=f'FAMA', line=dict(dash='dash', color='red')))
1293
+
1294
+ # Add APMA if selected
1295
+ if use_apma:
1296
+ st.session_state['APMA'] = adaptive_period_moving_average(data['Close'].values, min_period=apma_min_period, max_period=apma_max_period)
1297
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['APMA'], mode='lines', name=f'APMA (min={apma_min_period}, max={apma_max_period})', line=dict(dash='dash', color='red')))
1298
+
1299
+ # Add Rainbow EMA if selected
1300
+ if use_rainbow_ema:
1301
+ data = calculate_rainbow_ema(data, rainbow_lookback_periods)
1302
+ colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet', 'black','gray','brown']
1303
+ for i, lookback in enumerate(rainbow_lookback_periods):
1304
+ fig.add_trace(go.Scatter(x=data.index, y=data[f'EMA{lookback}'], mode='lines', name=f'EMA {lookback}', line=dict(dash='solid', color=colors[i % len(colors)])))
1305
+
1306
+ # Add Wilders MA if selected
1307
+ if use_wilders_ma:
1308
+ st.session_state['Wilders_MA'] = wilders_moving_average(data['Close'].tolist(), wilders_ma_period)
1309
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['Wilders_MA'], mode='lines', name=f'Wilders MA (n={wilders_ma_period})', line=dict(dash='dash', color='red')))
1310
+
1311
+ # Add SMMA if selected
1312
+ if use_smma:
1313
+ st.session_state['SMMA'] = calculate_SMMA(data['Close'].tolist(), smma_period)
1314
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['SMMA'], mode='lines', name=f'SMMA (n={smma_period})', line=dict(dash='dash', color='red')))
1315
+
1316
+ # Add GMMA if selected
1317
+ if use_gmma:
1318
+ close_prices = data['Close'].tolist()
1319
+ for period in gmma_short_periods:
1320
+ data[f'EMA_{period}'] = calculate_EMA(close_prices, period)
1321
+ fig.add_trace(go.Scatter(x=data.index, y=data[f'EMA_{period}'], mode='lines', name=f'GMMA Short EMA {period}', line=dict(dash='solid')))
1322
+ for period in gmma_long_periods:
1323
+ data[f'EMA_{period}'] = calculate_EMA(close_prices, period)
1324
+ fig.add_trace(go.Scatter(x=data.index, y=data[f'EMA_{period}'], mode='lines', name=f'GMMA Long EMA {period}', line=dict(dash='dash')))
1325
+
1326
+ # Add LSMA if selected
1327
+ if use_lsma:
1328
+ st.session_state['LSMA'] = calculate_LSMA(data['Close'].tolist(), lsma_period)
1329
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['LSMA'], mode='lines', name=f'LSMA (n={lsma_period})', line=dict(dash='dash', color='blue')))
1330
+
1331
+ # Add MMA (Welch's MMA) if selected
1332
+ if use_mma:
1333
+ st.session_state['MMA'] = calculate_MMA(data['Close'].tolist(), mma_period)
1334
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['MMA'], mode='lines', name=f'MMA (n={mma_period})', line=dict(dash='dash', color='blue')))
1335
+
1336
+ # Add SinWMA if selected
1337
+ if use_sinwma:
1338
+ st.session_state['SinWMA'] = calculate_SinWMA(data['Close'].tolist(), sinwma_period)
1339
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['SinWMA'], mode='lines', name=f'SinWMA (n={sinwma_period})', line=dict(dash='dash', color='green')))
1340
+
1341
+ # Add MedMA if selected
1342
+ if use_medma:
1343
+ st.session_state['MedMA'] = calculate_MedMA(data['Close'].tolist(), medma_period)
1344
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['MedMA'], mode='lines', name=f'MedMA (n={medma_period})', line=dict(dash='dash', color='blue')))
1345
+
1346
+ # Add GMA if selected
1347
+ if use_gma:
1348
+ st.session_state['GMA'] = calculate_GMA(data['Close'].tolist(), gma_period)
1349
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['GMA'], mode='lines', name=f'GMA (n={gma_period})', line=dict(dash='dash', color='green')))
1350
+
1351
+ # Add eVWMA if selected
1352
+ if use_evwma:
1353
+ st.session_state['eVWMA'] = calculate_eVWMA(data['Close'], data['Volume'], evwma_period)
1354
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['eVWMA'], mode='lines', name=f'eVWMA (n={evwma_period})', line=dict(dash='dash', color='blue')))
1355
+
1356
+ # Add REMA if selected
1357
+ if use_rema:
1358
+ st.session_state['REMA'] = REMA(data['Close'], alpha=rema_alpha, lambda_=rema_lambda)
1359
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['REMA'], mode='lines', name=f'REMA (alpha={rema_alpha}, lambda={rema_lambda})', line=dict(dash='dash', color='red')))
1360
+
1361
+ # Add PWMA if selected
1362
+ if use_pwma:
1363
+ pwma_values = parabolic_weighted_moving_average(data['Close'].values, pwma_period)
1364
+ st.session_state['PWMA'] = np.concatenate([np.array([np.nan]*(pwma_period-1)), pwma_values])
1365
+ fig.add_trace(go.Scatter(x=data.index, y=st.session_state['PWMA'], mode='lines', name=f'PWMA (n={pwma_period})', line=dict(dash='dash', color='red')))
1366
+
1367
+ # Update layout with grid toggle
1368
+ fig.update_layout(
1369
+ title=f'{ticker_symbol} Stock Price with Moving Averages',
1370
+ xaxis_title='Date',
1371
+ yaxis_title='Stock Price',
1372
+ legend_title='Indicators',
1373
+ template='plotly_white',
1374
+ xaxis=dict(showgrid=show_grid),
1375
+ yaxis=dict(showgrid=show_grid)
1376
+ )
1377
 
1378
+ # Store the updated figure in session state
1379
+ st.session_state['current_fig'] = fig
1380
+ except Exception as e:
1381
+ st.error(f"An error occurred while running analysis: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1382
 
1383
+ # Display the current figure, which remains unchanged until "Run" is clicked
1384
  if 'current_fig' in st.session_state:
1385
  st.plotly_chart(st.session_state['current_fig'], use_container_width=True)
1386
 
 
1389
  <style>
1390
  /* Adjust the width of the sidebar */
1391
  [data-testid="stSidebar"] {
1392
+ width: 500px; /* Change this value to set the width you want */
1393
  }
1394
  </style>
1395
  """,
 
1402
  footer {visibility: hidden;}
1403
  </style>
1404
  """
1405
+ st.markdown(hide_streamlit_style, unsafe_allow_html=True)