@@ -75,24 +75,39 @@ fn calc_macd_line(data: &[f64], fast_period: usize, slow_period: usize) -> Vec<O
7575}
7676
7777fn calc_macd_signal ( macd_line : & [ Option < f64 > ] , signal_period : usize ) -> Vec < Option < f64 > > {
78- let mut signal_line: Vec < Option < f64 > > = vec ! [ None ; macd_line. len( ) ] ;
79- let null_count = macd_line. iter ( ) . take_while ( |& & x| x. is_none ( ) ) . count ( ) ;
80- let macd_values: Vec < f64 > = macd_line
81- . iter ( )
82- . skip ( null_count)
83- . filter_map ( |& x| x)
84- . collect ( ) ;
85- let ema_values = ema ( & macd_values, signal_period) ;
78+ let mut signal_line = vec ! [ None ; macd_line. len( ) ] ;
79+ let Some ( first_valid_idx) = macd_line. iter ( ) . position ( |value| value. is_some ( ) ) else {
80+ return signal_line;
81+ } ;
82+
83+ let valid_len = macd_line. len ( ) - first_valid_idx;
84+ if signal_period == 0 || valid_len < signal_period {
85+ return signal_line;
86+ }
8687
87- for i in 0 ..ema_values. len ( ) {
88- if let Some ( ema_value) = ema_values[ i] {
89- signal_line[ i + null_count] = Some ( ema_value) ;
90- }
88+ let first_signal_idx = first_valid_idx + signal_period - 1 ;
89+ let mut signal = mean_macd_window ( macd_line, first_valid_idx, signal_period) ;
90+ let alpha = 2.0 / ( signal_period as f64 + 1.0 ) ;
91+
92+ signal_line[ first_signal_idx] = Some ( signal) ;
93+
94+ for ( idx, value) in macd_line. iter ( ) . enumerate ( ) . skip ( first_signal_idx + 1 ) {
95+ let macd = value. expect ( "macd_line becomes contiguous after the first valid value" ) ;
96+ signal = alpha * macd + ( 1.0 - alpha) * signal;
97+ signal_line[ idx] = Some ( signal) ;
9198 }
9299
93100 signal_line
94101}
95102
103+ fn mean_macd_window ( macd_line : & [ Option < f64 > ] , start_idx : usize , period : usize ) -> f64 {
104+ macd_line[ start_idx..start_idx + period]
105+ . iter ( )
106+ . map ( |value| value. expect ( "initial signal window must be fully populated" ) )
107+ . sum :: < f64 > ( )
108+ / period as f64
109+ }
110+
96111#[ cfg( test) ]
97112mod tests {
98113 use super :: * ;
0 commit comments