@@ -346,9 +346,11 @@ def WMA(self, idx, period=17):
346346 return self .window
347347
348348 # Calculate a Hull Moving Average (HMA) using the existing WMA
349- # Problem Child.
350349
351- def HMA (self , idx , period = 21 ):
350+ # The default is WMA, but by using a column, I can give ANY moving average
351+ # to HMA or even change the WMA parameters externally.
352+
353+ def HMA (self , wmaIDX , wma2IDX , period = 21 ):
352354 """
353355 Calculate the Hull Moving Average (HMA) for the series at column `idx`.
354356
@@ -374,21 +376,21 @@ def HMA(self, idx, period=21):
374376 """
375377
376378 # Step 0: Ensure enough historical data
377- closes = [row [idx ] for row in self .window [- period :] if len (row )> idx and row [idx ] is not None ]
378- if len (closes ) < period :
379+ if len (self .window )< period + 1 :
379380 self .AddColumn (None )
380381 self .AddColumn (None )
382+ return self .window
383+
384+ if len (self .window [- 1 ])< wmaIDX + 1 or len (self .window [- 1 ])< wma2IDX + 1 :
381385 self .AddColumn (None )
382386 self .AddColumn (None )
383387 return self .window
384388
385- # Step 1: WMA(period/2)
386- self .WMA (idx , period // 2 )
387- wma_half = self .window [- 1 ][- 1 ]
389+ # Step 1: WMA(period)
390+ wma_full = self .window [- 1 ][wmaIDX ]
388391
389- # Step 2: WMA(period)
390- self .WMA (idx , period )
391- wma_full = self .window [- 1 ][- 1 ]
392+ # Step 2: WMA(period/2)
393+ wma_half = self .window [- 1 ][wma2IDX ]
392394
393395 # Check validity
394396 if wma_half is None or wma_full is None :
@@ -402,8 +404,7 @@ def HMA(self, idx, period=21):
402404
403405 # Step 4: WMA(synthetic, sqrt(period))
404406 sqrt_period = max (1 , int (period ** 0.5 ))
405- synthetic_idx = len (self .window [- 1 ]) - 1
406- self .WMA (synthetic_idx , sqrt_period ) # HMA value, last column
407+ self .AddColumn (sqrt_period )
407408
408409 return self .window
409410
@@ -758,14 +759,18 @@ def MACD(self, idxFAST, idxSLOW, period=9, signal_func=None):
758759
759760 # Ensure enough history
760761 if len (self .window ) < 1 or len (self .window [- 1 ]) <= max (idxFAST , idxSLOW ):
761- self .window [- 1 ].extend ([None , None , None ])
762+ self .AddColumn (None )
763+ self .AddColumn (None )
764+ self .AddColumn (None )
762765 return self .window
763766
764767 fast = self .window [- 1 ][idxFAST ]
765768 slow = self .window [- 1 ][idxSLOW ]
766769
767770 if fast is None or slow is None :
768- self .window [- 1 ].extend ([None , None , None ])
771+ self .AddColumn (None )
772+ self .AddColumn (None )
773+ self .AddColumn (None )
769774 return self .window
770775
771776 # MACD line
@@ -814,20 +819,20 @@ def ATR(self, high_idx=1, low_idx=2, close_idx=4, period=14, malen=14, smooth_fu
814819
815820 # Ensure at least one previous candle exists
816821 if len (self .window ) < 2 :
817- self .window [- 1 ].extend ([None , None ])
822+ self .AddColumn (None )
823+ self .AddColumn (None )
818824 return self .window
819825
820826 row = self .window [- 1 ]
821827 prev_row = self .window [- 2 ]
822828
823829 # Check for missing data
824- if (len (row ) <= max (high_idx , low_idx , close_idx ) or
825- len (prev_row ) <= close_idx or
826- row [high_idx ] is None or
827- row [low_idx ] is None or
828- row [close_idx ] is None or
829- prev_row [close_idx ] is None ):
830- self .window [- 1 ].extend ([None , None ])
830+ if (len (row ) <= max (high_idx , low_idx , close_idx )
831+ or len (prev_row ) <= close_idx or row [high_idx ] is None
832+ or row [low_idx ] is None or row [close_idx ] is None
833+ or prev_row [close_idx ] is None ):
834+ self .AddColumn (None )
835+ self .AddColumn (None )
831836 return self .window
832837
833838 # Calculate True Range (TR)
@@ -876,7 +881,9 @@ def Stochastic(self, high_idx, low_idx, close_idx, k_period=14, k_smooth=3, d_sm
876881
877882 n = len (self .window )
878883 if n < k_period :
879- self .window [- 1 ].extend ([None , None , None ])
884+ self .AddColumn (None )
885+ self .AddColumn (None )
886+ self .AddColumn (None )
880887 return self .window
881888
882889 # Extract last k_period highs, lows, closes
@@ -885,7 +892,9 @@ def Stochastic(self, high_idx, low_idx, close_idx, k_period=14, k_smooth=3, d_sm
885892 closes = [row [close_idx ] for row in self .window [- k_period :] if len (row ) > close_idx and row [close_idx ] is not None ]
886893
887894 if len (highs ) < k_period or len (lows ) < k_period or len (closes ) < k_period :
888- self .window [- 1 ].extend ([None , None ,None ])
895+ self .AddColumn (None )
896+ self .AddColumn (None )
897+ self .AddColumn (None )
889898 return self .window
890899
891900 high_max = max (highs )
0 commit comments