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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +34 -176
app.py CHANGED
@@ -35,9 +35,11 @@ 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
- 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,102 +136,80 @@ def calculate_harmonic_moving_average(prices, 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,81 +217,62 @@ def calculate_EMA(prices, period):
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,52 +280,42 @@ def wilders_moving_average(prices, period):
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,7 +326,6 @@ def calculate_MedMA(prices, window):
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,7 +337,6 @@ def calculate_GMA(prices, window):
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,7 +351,6 @@ def calculate_eVWMA(prices, volumes, window):
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,47 +358,35 @@ def calculate_mcginley_dynamic(prices, n):
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,10 +398,8 @@ end_date = st.sidebar.date_input(
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,19 +415,15 @@ if st.sidebar.button('Fetch Data'):
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
- # SMA with tooltip
490
  with st.sidebar.expander("Simple Moving Average", expanded=False):
491
  use_sma = st.checkbox(
492
  'Simple Moving Average (SMA)',
493
  value=st.session_state.get('use_sma', False),
494
  help="Select to apply Simple Moving Average (SMA) to the stock price."
495
  )
496
-
497
  sma_period = st.number_input(
498
  'SMA Period',
499
  min_value=1,
@@ -503,7 +433,6 @@ if 'data' in st.session_state:
503
  help="Specify the period (in days) for the SMA."
504
  )
505
 
506
- # EMA with tooltip
507
  with st.sidebar.expander("Exponential Moving Average (EMA)", expanded=False):
508
  use_ema = st.checkbox(
509
  'Enable EMA',
@@ -519,7 +448,6 @@ if 'data' in st.session_state:
519
  help="Specify the period (in days) for the EMA."
520
  )
521
 
522
- # WMA with tooltip
523
  with st.sidebar.expander("Weighted Moving Average (WMA)", expanded=False):
524
  use_wma = st.checkbox(
525
  'Enable WMA',
@@ -535,7 +463,6 @@ if 'data' in st.session_state:
535
  help="Specify the period (in days) for the WMA."
536
  )
537
 
538
- # DEMA with tooltip
539
  with st.sidebar.expander("Double Exponential Moving Average (DEMA)", expanded=False):
540
  use_dema = st.checkbox(
541
  'Enable DEMA',
@@ -551,7 +478,6 @@ if 'data' in st.session_state:
551
  help="Specify the period (in days) for the DEMA."
552
  )
553
 
554
- # TEMA with tooltip
555
  with st.sidebar.expander("Triple Exponential Moving Average (TEMA)", expanded=False):
556
  use_tema = st.checkbox(
557
  'Enable TEMA',
@@ -567,7 +493,6 @@ if 'data' in st.session_state:
567
  help="Specify the period (in days) for the TEMA."
568
  )
569
 
570
- # VAMA with tooltip
571
  with st.sidebar.expander("Volume-Adjusted Moving Average (VAMA)", expanded=False):
572
  use_vama = st.checkbox(
573
  'Enable VAMA',
@@ -583,7 +508,6 @@ if 'data' in st.session_state:
583
  help="Specify the period (in days) for the VAMA."
584
  )
585
 
586
- # KAMA with tooltip
587
  with st.sidebar.expander("Kaufman Adaptive Moving Average (KAMA)", expanded=False):
588
  use_kama = st.checkbox(
589
  'Enable KAMA',
@@ -615,7 +539,6 @@ if 'data' in st.session_state:
615
  help="Specify the slowest smoothing constant period."
616
  )
617
 
618
- # TMA with tooltip
619
  with st.sidebar.expander("Triangular Moving Average (TMA)", expanded=False):
620
  use_tma = st.checkbox(
621
  'Enable TMA',
@@ -630,8 +553,7 @@ if 'data' in st.session_state:
630
  disabled=not use_tma,
631
  help="Specify the period (in days) for the TMA."
632
  )
633
-
634
- # Hull MA with tooltip
635
  with st.sidebar.expander("Hull Moving Average (HMA)", expanded=False):
636
  use_hull_ma = st.checkbox(
637
  'Enable HMA',
@@ -647,7 +569,6 @@ if 'data' in st.session_state:
647
  help="Specify the period (in days) for the Hull Moving Average."
648
  )
649
 
650
- # Harmonic MA with tooltip
651
  with st.sidebar.expander("Harmonic Moving Average (HMA)", expanded=False):
652
  use_harmonic_ma = st.checkbox(
653
  'Enable HMA',
@@ -663,7 +584,6 @@ if 'data' in st.session_state:
663
  help="Specify the period (in days) for the Harmonic Moving Average."
664
  )
665
 
666
- # FRAMA with tooltip
667
  with st.sidebar.expander("Fractal Adaptive Moving Average (FRAMA)", expanded=False):
668
  use_frama = st.checkbox(
669
  'Enable FRAMA',
@@ -679,7 +599,6 @@ if 'data' in st.session_state:
679
  help="Specify the batch size for FRAMA calculation."
680
  )
681
 
682
- # ZLEMA with tooltip
683
  with st.sidebar.expander("Zero Lag Exponential Moving Average (ZLEMA)", expanded=False):
684
  use_zlema = st.checkbox(
685
  'Enable ZLEMA',
@@ -695,7 +614,6 @@ if 'data' in st.session_state:
695
  help="Specify the period (in days) for the ZLEMA."
696
  )
697
 
698
- # VIDYA with tooltip
699
  with st.sidebar.expander("Variable Index Dynamic Average (VIDYA)", expanded=False):
700
  use_vidya = st.checkbox(
701
  'Enable VIDYA',
@@ -711,7 +629,6 @@ if 'data' in st.session_state:
711
  help="Specify the period (in days) for the VIDYA."
712
  )
713
 
714
- # ALMA with tooltip
715
  with st.sidebar.expander("Arnaud Legoux Moving Average (ALMA)", expanded=False):
716
  use_alma = st.checkbox(
717
  'Enable ALMA',
@@ -744,7 +661,6 @@ if 'data' in st.session_state:
744
  help="Specify the sigma for the ALMA."
745
  )
746
 
747
- # MAMA and FAMA with tooltip
748
  with st.sidebar.expander("MESA Adaptive Moving Average (MAMA) & FAMA", expanded=False):
749
  use_mama_fama = st.checkbox(
750
  'Enable MAMA & FAMA',
@@ -770,7 +686,6 @@ if 'data' in st.session_state:
770
  help="Specify the slow limit for MAMA (0 to 1)."
771
  )
772
 
773
- # APMA with tooltip
774
  with st.sidebar.expander("Adaptive Period Moving Average (APMA)", expanded=False):
775
  use_apma = st.checkbox(
776
  'Enable APMA',
@@ -794,7 +709,6 @@ if 'data' in st.session_state:
794
  help="Specify the maximum period for the APMA."
795
  )
796
 
797
- # Rainbow EMA with tooltip
798
  with st.sidebar.expander("Rainbow Moving Average (EMA)", expanded=False):
799
  use_rainbow_ema = st.checkbox(
800
  'Enable Rainbow EMA',
@@ -809,7 +723,6 @@ if 'data' in st.session_state:
809
  help="Select multiple lookback periods for the Rainbow EMA."
810
  )
811
 
812
- # Wilders MA with tooltip
813
  with st.sidebar.expander("Wilders Moving Average (Wilder's MA)", expanded=False):
814
  use_wilders_ma = st.checkbox(
815
  'Enable Wilders MA',
@@ -825,7 +738,6 @@ if 'data' in st.session_state:
825
  help="Specify the period (in days) for Wilder's Moving Average."
826
  )
827
 
828
- # SMMA with tooltip
829
  with st.sidebar.expander("Smoothed Moving Average (SMMA)", expanded=False):
830
  use_smma = st.checkbox(
831
  'Enable SMMA',
@@ -841,7 +753,6 @@ if 'data' in st.session_state:
841
  help="Specify the period (in days) for the SMMA."
842
  )
843
 
844
- # GMMA with tooltip
845
  with st.sidebar.expander("Guppy Multiple Moving Average (GMMA)", expanded=False):
846
  use_gmma = st.checkbox(
847
  'Enable GMMA',
@@ -863,7 +774,6 @@ if 'data' in st.session_state:
863
  help="Select the long-term periods for GMMA."
864
  )
865
 
866
- # LSMA with tooltip
867
  with st.sidebar.expander("Least Squares Moving Average (LSMA)", expanded=False):
868
  use_lsma = st.checkbox(
869
  'Enable LSMA',
@@ -879,7 +789,6 @@ if 'data' in st.session_state:
879
  help="Specify the period (in days) for the LSMA."
880
  )
881
 
882
- # MMA (Welch's MMA) with tooltip
883
  with st.sidebar.expander("Welch's Moving Average (MMA)", expanded=False):
884
  use_mma = st.checkbox(
885
  'Enable MMA',
@@ -895,7 +804,6 @@ if 'data' in st.session_state:
895
  help="Specify the period (in days) for the MMA."
896
  )
897
 
898
- # SinWMA with tooltip
899
  with st.sidebar.expander("Sin-weighted Moving Average (SinWMA)", expanded=False):
900
  use_sinwma = st.checkbox(
901
  'Enable SinWMA',
@@ -911,7 +819,6 @@ if 'data' in st.session_state:
911
  help="Specify the period (in days) for the SinWMA."
912
  )
913
 
914
- # MedMA with tooltip
915
  with st.sidebar.expander("Median Moving Average (MedMA)", expanded=False):
916
  use_medma = st.checkbox(
917
  'Enable MedMA',
@@ -927,7 +834,6 @@ if 'data' in st.session_state:
927
  help="Specify the period (in days) for the MedMA."
928
  )
929
 
930
- # GMA with tooltip
931
  with st.sidebar.expander("Geometric Moving Average (GMA)", expanded=False):
932
  use_gma = st.checkbox(
933
  'Enable GMA',
@@ -943,7 +849,6 @@ if 'data' in st.session_state:
943
  help="Specify the period (in days) for the GMA."
944
  )
945
 
946
- # eVWMA with tooltip
947
  with st.sidebar.expander("Elastic Volume Weighted Moving Average (eVWMA)", expanded=False):
948
  use_evwma = st.checkbox(
949
  'Enable eVWMA',
@@ -958,8 +863,7 @@ if 'data' in st.session_state:
958
  disabled=not use_evwma,
959
  help="Specify the period (in days) for the eVWMA."
960
  )
961
-
962
- # REMA with tooltip
963
  with st.sidebar.expander("Regularized Exponential Moving Average (REMA)", expanded=False):
964
  use_rema = st.checkbox(
965
  'Enable REMA',
@@ -985,7 +889,6 @@ if 'data' in st.session_state:
985
  help="Specify the lambda value for the REMA (0 to 1)."
986
  )
987
 
988
- # PWMA with tooltip
989
  with st.sidebar.expander("Parabolic Weighted Moving Average (PWMA)", expanded=False):
990
  use_pwma = st.checkbox(
991
  'Enable PWMA',
@@ -1001,7 +904,6 @@ if 'data' in st.session_state:
1001
  help="Specify the period (in days) for the PWMA."
1002
  )
1003
 
1004
- # JMA with tooltip
1005
  with st.sidebar.expander("Jurik Moving Average (JMA)", expanded=False):
1006
  use_jma = st.checkbox(
1007
  'Enable JMA',
@@ -1026,7 +928,6 @@ if 'data' in st.session_state:
1026
  help="Specify the phase for the JMA (-100 to 100)."
1027
  )
1028
 
1029
- # EPMA with tooltip
1030
  with st.sidebar.expander("End Point Moving Average (EPMA)", expanded=False):
1031
  use_epma = st.checkbox(
1032
  'Enable EPMA',
@@ -1042,16 +943,14 @@ if 'data' in st.session_state:
1042
  help="Specify the period (in days) for the EPMA."
1043
  )
1044
 
1045
- # CMA with tooltip
1046
  with st.sidebar.expander("Chande Moving Average (CMA)", expanded=False):
1047
  use_cma = st.checkbox(
1048
  'Enable CMA',
1049
  value=st.session_state.get('use_cma', False),
1050
  help="Select to apply Chande Moving Average (CMA) to the stock price."
1051
  )
1052
- cma_period = len(data['Close']) # This does not require user input.
1053
 
1054
- # McGinley Dynamic with tooltip
1055
  with st.sidebar.expander("McGinley Dynamic", expanded=False):
1056
  use_mcginley_dynamic = st.checkbox(
1057
  'Enable McGinley Dynamic',
@@ -1067,7 +966,6 @@ if 'data' in st.session_state:
1067
  help="Specify the period (in days) for the McGinley Dynamic."
1068
  )
1069
 
1070
- # Filtered Moving Average (FMA) with tooltip
1071
  with st.sidebar.expander("Filtered Moving Average (FMA)", expanded=False):
1072
  use_fma = st.checkbox(
1073
  'Enable FMA',
@@ -1083,16 +981,13 @@ if 'data' in st.session_state:
1083
  help="Specify the period (in days) for the FMA."
1084
  )
1085
 
1086
- # Grid toggle with tooltip
1087
  show_grid = st.sidebar.checkbox(
1088
  "Show Grid",
1089
  value=True,
1090
  help="Toggle to show or hide the grid on the plot."
1091
  )
1092
 
1093
- # Run button to apply moving averages
1094
  if st.sidebar.button('Run Analysis'):
1095
- # Save the moving average settings to session state
1096
  st.session_state['use_sma'] = use_sma
1097
  st.session_state['sma_period'] = sma_period
1098
  st.session_state['use_ema'] = use_ema
@@ -1168,58 +1063,47 @@ if 'data' in st.session_state:
1168
  st.session_state['use_fma'] = use_fma
1169
  st.session_state['fma_period'] = fma_period
1170
 
1171
- # Start with the base price plot
1172
  fig = go.Figure(data=st.session_state['price_plot'].data)
1173
 
1174
- # Add JMA if selected
1175
  if use_jma:
1176
  st.session_state['JMA'] = jma(data['Close'], length=jma_period, phase=jma_phase)
1177
  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')))
1178
 
1179
- # Add EPMA if selected
1180
  if use_epma:
1181
  st.session_state['EPMA'] = calculate_EPMA(data['Close'].tolist(), epma_period)
1182
  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')))
1183
 
1184
- # Add CMA if selected
1185
  if use_cma:
1186
  st.session_state['CMA'] = calculate_CMA(data['Close'])
1187
  fig.add_trace(go.Scatter(x=data.index, y=st.session_state['CMA'], mode='lines', name=f'CMA', line=dict(dash='dash', color='blue')))
1188
 
1189
- # Add McGinley Dynamic if selected
1190
  if use_mcginley_dynamic:
1191
  st.session_state['McGinley_Dynamic'] = calculate_mcginley_dynamic(data['Close'].tolist(), mcginley_dynamic_period)
1192
  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')))
1193
 
1194
- # Add FMA if selected
1195
  if use_fma:
1196
  st.session_state['FMA'] = filtered_moving_average(data['Close'].values, fma_period)
1197
  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')))
1198
 
1199
- # Add SMA if selected
1200
  if use_sma:
1201
  st.session_state['SMA'] = data['Close'].rolling(window=sma_period).mean()
1202
  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')))
1203
 
1204
- # Add EMA if selected
1205
  if use_ema:
1206
  st.session_state['EMA'] = data['Close'].ewm(span=ema_period, adjust=False).mean()
1207
  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')))
1208
 
1209
- # Add WMA if selected
1210
  if use_wma:
1211
  weights = np.arange(1, wma_period + 1)
1212
  st.session_state['WMA'] = data['Close'].rolling(window=wma_period).apply(lambda prices: np.dot(prices, weights)/weights.sum(), raw=True)
1213
  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')))
1214
 
1215
- # Add DEMA if selected
1216
  if use_dema:
1217
  data['EMA'] = data['Close'].ewm(span=dema_period, adjust=False).mean()
1218
  data['EMA2'] = data['EMA'].ewm(span=dema_period, adjust=False).mean()
1219
  st.session_state['DEMA'] = 2 * data['EMA'] - data['EMA2']
1220
  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')))
1221
-
1222
- # Add TEMA if selected
1223
  if use_tema:
1224
  data['EMA'] = data['Close'].ewm(span=tema_period, adjust=False).mean()
1225
  data['EMA2'] = data['EMA'].ewm(span=tema_period, adjust=False).mean()
@@ -1227,13 +1111,11 @@ if 'data' in st.session_state:
1227
  st.session_state['TEMA'] = 3 * data['EMA'] - 3 * data['EMA2'] + data['EMA3']
1228
  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')))
1229
 
1230
- # Add VAMA if selected
1231
  if use_vama:
1232
  data['Volume_Price'] = data['Close'] * data['Volume']
1233
  st.session_state['VAMA'] = data['Volume_Price'].rolling(window=vama_period).sum() / data['Volume'].rolling(window=vama_period).sum()
1234
  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')))
1235
 
1236
- # Add KAMA if selected
1237
  if use_kama:
1238
  fastest_SC = 2 / (fastest_period + 1)
1239
  slowest_SC = 2 / (slowest_period + 1)
@@ -1246,75 +1128,62 @@ if 'data' in st.session_state:
1246
  data['KAMA'].iloc[i] = data['KAMA'].iloc[i-1] + data['SC'].iloc[i] * (data['Close'].iloc[i] - data['KAMA'].iloc[i-1])
1247
  st.session_state['KAMA'] = data['KAMA']
1248
  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')))
1249
-
1250
- # Add TMA if selected
1251
  if use_tma:
1252
  half_n = (tma_period + 1) // 2
1253
  data['Half_SMA'] = data['Close'].rolling(window=half_n).mean()
1254
  st.session_state['TMA'] = data['Half_SMA'].rolling(window=half_n).mean()
1255
  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')))
1256
-
1257
- # Add Hull MA if selected
1258
  if use_hull_ma:
1259
  st.session_state['Hull_MA'] = hull_moving_average(data['Close'], hull_ma_period)
1260
  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')))
1261
-
1262
- # Add Harmonic MA if selected
1263
  if use_harmonic_ma:
1264
  st.session_state['Harmonic_MA'] = calculate_harmonic_moving_average(data['Close'].values, harmonic_ma_period)
1265
  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')))
1266
-
1267
- # Add FRAMA if selected
1268
  if use_frama:
1269
  st.session_state['FRAMA'] = calculate_FRAMA(data, batch=frama_batch)['FRAMA']
1270
  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')))
1271
 
1272
- # Add ZLEMA if selected
1273
  if use_zlema:
1274
  st.session_state['ZLEMA'] = calculate_ZLEMA(data['Close'].tolist(), zlema_period)
1275
  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')))
1276
 
1277
- # Add VIDYA if selected
1278
  if use_vidya:
1279
  st.session_state['VIDYA'] = calculate_VIDYA(data['Close'].tolist(), vidya_period)
1280
  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')))
1281
-
1282
- # Add ALMA if selected
1283
  if use_alma:
1284
  st.session_state['ALMA'] = calculate_ALMA(data['Close'].tolist(), alma_period, offset=alma_offset, sigma=alma_sigma)
1285
  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')))
1286
-
1287
- # Add MAMA and FAMA if selected
1288
  if use_mama_fama:
1289
  data['MAMA'], data['FAMA'] = talib.MAMA(data['Close'].values, fastlimit=mama_fast_limit, slowlimit=mama_slow_limit)
1290
  st.session_state['MAMA'] = data['MAMA']
1291
  st.session_state['FAMA'] = data['FAMA']
1292
  fig.add_trace(go.Scatter(x=data.index, y=st.session_state['MAMA'], mode='lines', name=f'MAMA', line=dict(dash='dash', color='blue')))
1293
  fig.add_trace(go.Scatter(x=data.index, y=st.session_state['FAMA'], mode='lines', name=f'FAMA', line=dict(dash='dash', color='red')))
1294
-
1295
- # Add APMA if selected
1296
  if use_apma:
1297
  st.session_state['APMA'] = adaptive_period_moving_average(data['Close'].values, min_period=apma_min_period, max_period=apma_max_period)
1298
  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')))
1299
 
1300
- # Add Rainbow EMA if selected
1301
  if use_rainbow_ema:
1302
  data = calculate_rainbow_ema(data, rainbow_lookback_periods)
1303
  colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet', 'black','gray','brown']
1304
  for i, lookback in enumerate(rainbow_lookback_periods):
1305
  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)])))
1306
 
1307
- # Add Wilders MA if selected
1308
  if use_wilders_ma:
1309
  st.session_state['Wilders_MA'] = wilders_moving_average(data['Close'].tolist(), wilders_ma_period)
1310
  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')))
1311
 
1312
- # Add SMMA if selected
1313
  if use_smma:
1314
  st.session_state['SMMA'] = calculate_SMMA(data['Close'].tolist(), smma_period)
1315
  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')))
1316
-
1317
- # Add GMMA if selected
1318
  if use_gmma:
1319
  close_prices = data['Close'].tolist()
1320
  for period in gmma_short_periods:
@@ -1323,49 +1192,40 @@ if 'data' in st.session_state:
1323
  for period in gmma_long_periods:
1324
  data[f'EMA_{period}'] = calculate_EMA(close_prices, period)
1325
  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')))
1326
-
1327
- # Add LSMA if selected
1328
  if use_lsma:
1329
  st.session_state['LSMA'] = calculate_LSMA(data['Close'].tolist(), lsma_period)
1330
  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')))
1331
-
1332
- # Add MMA (Welch's MMA) if selected
1333
  if use_mma:
1334
  st.session_state['MMA'] = calculate_MMA(data['Close'].tolist(), mma_period)
1335
  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')))
1336
 
1337
- # Add SinWMA if selected
1338
  if use_sinwma:
1339
  st.session_state['SinWMA'] = calculate_SinWMA(data['Close'].tolist(), sinwma_period)
1340
  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')))
1341
 
1342
- # Add MedMA if selected
1343
  if use_medma:
1344
  st.session_state['MedMA'] = calculate_MedMA(data['Close'].tolist(), medma_period)
1345
  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')))
1346
-
1347
- # Add GMA if selected
1348
  if use_gma:
1349
  st.session_state['GMA'] = calculate_GMA(data['Close'].tolist(), gma_period)
1350
  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')))
1351
-
1352
- # Add eVWMA if selected
1353
  if use_evwma:
1354
  st.session_state['eVWMA'] = calculate_eVWMA(data['Close'], data['Volume'], evwma_period)
1355
  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')))
1356
 
1357
- # Add REMA if selected
1358
  if use_rema:
1359
  st.session_state['REMA'] = REMA(data['Close'], alpha=rema_alpha, lambda_=rema_lambda)
1360
  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')))
1361
 
1362
- # Add PWMA if selected
1363
  if use_pwma:
1364
  pwma_values = parabolic_weighted_moving_average(data['Close'].values, pwma_period)
1365
  st.session_state['PWMA'] = np.concatenate([np.array([np.nan]*(pwma_period-1)), pwma_values])
1366
  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')))
1367
 
1368
- # Update layout with grid toggle
1369
  fig.update_layout(
1370
  title=f'{ticker_symbol} Stock Price with Moving Averages',
1371
  xaxis_title='Date',
@@ -1376,10 +1236,8 @@ if 'data' in st.session_state:
1376
  yaxis=dict(showgrid=show_grid)
1377
  )
1378
 
1379
- # Store the updated figure in session state
1380
  st.session_state['current_fig'] = fig
1381
 
1382
- # Display the current figure, which remains unchanged until "Run" is clicked
1383
  if 'current_fig' in st.session_state:
1384
  st.plotly_chart(st.session_state['current_fig'], use_container_width=True)
1385
 
@@ -1388,7 +1246,7 @@ st.markdown(
1388
  <style>
1389
  /* Adjust the width of the sidebar */
1390
  [data-testid="stSidebar"] {
1391
- width: 500px; /* Change this value to set the width you want */
1392
  }
1393
  </style>
1394
  """,
@@ -1401,4 +1259,4 @@ hide_streamlit_style = """
1401
  footer {visibility: hidden;}
1402
  </style>
1403
  """
1404
- 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
+ # 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
  # 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
  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
  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
  medians.append(median)
327
  return medians
328
 
 
329
  def calculate_GMA(prices, window):
330
  gm_avg = []
331
  for i in range(len(prices)):
 
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
  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
  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
  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
  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)',
424
  value=st.session_state.get('use_sma', False),
425
  help="Select to apply Simple Moving Average (SMA) to the stock price."
426
  )
 
427
  sma_period = st.number_input(
428
  'SMA Period',
429
  min_value=1,
 
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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
 
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()
 
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)
 
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:
 
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',
 
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
  <style>
1247
  /* Adjust the width of the sidebar */
1248
  [data-testid="stSidebar"] {
1249
+ width: 500px;
1250
  }
1251
  </style>
1252
  """,
 
1259
  footer {visibility: hidden;}
1260
  </style>
1261
  """
1262
+ st.markdown(hide_streamlit_style, unsafe_allow_html=True)