@@ -1628,11 +1628,6 @@ class AlphaDebiasEMA
16281628 m_adjust = adjust;
16291629 reset ();
16301630 }
1631-
1632- AlphaDebiasEMA ( AlphaDebiasEMA && rhs ) = default ;
1633-
1634- AlphaDebiasEMA & operator =( AlphaDebiasEMA && rhs ) = default ;
1635-
16361631
16371632 void add ( double x )
16381633 {
@@ -1724,31 +1719,64 @@ class AlphaDebiasEMA
17241719};
17251720
17261721class HalflifeEMA
1722+ {
1723+ public:
1724+ HalflifeEMA () = default ;
1725+
1726+ HalflifeEMA ( TimeDelta halflife, DateTime start, bool )
1727+ {
1728+ m_decay_factor = log ( 0.5 ) / halflife.asNanoseconds ();
1729+ reset ();
1730+ }
1731+
1732+ void add ( double x, DateTime now )
1733+ {
1734+ if ( unlikely ( m_last_tick.isNone () ) )
1735+ m_ema = x;
1736+ else
1737+ {
1738+ double decay = 1 - exp ( m_decay_factor * ( now - m_last_tick ).asNanoseconds () );
1739+ m_ema += decay * ( x - m_ema );
1740+ }
1741+ m_last_tick = now;
1742+ }
1743+
1744+ void reset ()
1745+ {
1746+ m_ema = std::numeric_limits<double >::quiet_NaN ();
1747+ m_last_tick = DateTime::NONE ();
1748+ }
1749+
1750+ double compute () const
1751+ {
1752+ return m_ema;
1753+ }
1754+
1755+ private:
1756+ double m_ema;
1757+ double m_decay_factor;
1758+ DateTime m_last_tick;
1759+ };
1760+
1761+ class AdjustedHalflifeEMA
17271762{
17281763 public:
1729- HalflifeEMA () = default ;
1764+ AdjustedHalflifeEMA () = default ;
17301765
1731- HalflifeEMA ( TimeDelta halflife, DateTime start )
1766+ AdjustedHalflifeEMA ( TimeDelta halflife, DateTime start, bool )
17321767 {
17331768 m_decay_factor = log ( 0.5 ) / halflife.asNanoseconds ();
17341769 m_last_tick = start;
17351770 reset ();
17361771 }
17371772
1738- HalflifeEMA ( HalflifeEMA && rhs ) = default ;
1739-
1740- HalflifeEMA & operator =( HalflifeEMA && rhs ) = default ;
1741-
17421773 void add ( double x, DateTime now )
17431774 {
1744- if ( likely ( !isnan ( x ) ) )
1745- {
1746- TimeDelta delta_t = now - m_last_tick;
1747- double decay = exp ( m_decay_factor * delta_t .asNanoseconds () );
1748- m_ema = decay * m_ema + x;
1749- m_norm = decay * m_norm + 1.0 ;
1750- m_last_tick = now;
1751- }
1775+ TimeDelta delta_t = now - m_last_tick;
1776+ double decay = exp ( m_decay_factor * delta_t .asNanoseconds () );
1777+ m_ema = decay * m_ema + x;
1778+ m_norm = decay * m_norm + 1.0 ;
1779+ m_last_tick = now;
17521780 }
17531781
17541782 void reset ()
@@ -1758,7 +1786,7 @@ class HalflifeEMA
17581786
17591787 double compute () const
17601788 {
1761- return m_ema / m_norm;
1789+ return likely ( m_norm > 0 ) ? ( m_ema / m_norm ) : std::numeric_limits< double >:: quiet_NaN () ;
17621790 }
17631791
17641792 private:
@@ -1767,35 +1795,37 @@ class HalflifeEMA
17671795 double m_norm;
17681796 double m_decay_factor;
17691797 DateTime m_last_tick;
1770-
17711798};
17721799
17731800class HalflifeDebiasEMA
17741801{
17751802 public:
17761803 HalflifeDebiasEMA () = default ;
17771804
1778- HalflifeDebiasEMA ( TimeDelta halflife, DateTime start )
1805+ HalflifeDebiasEMA ( TimeDelta halflife, DateTime start, bool adjust )
17791806 {
1780- m_decay_factor = log ( 0.5 ) / halflife.asNanoseconds ();
1807+ m_decay = log ( 0.5 ) / halflife.asNanoseconds ();
17811808 m_last_tick = start;
1809+ m_adjust = adjust;
17821810 reset ();
17831811 }
17841812
1785- HalflifeDebiasEMA ( HalflifeDebiasEMA && rhs ) = default ;
1786-
1787- HalflifeDebiasEMA & operator =( HalflifeDebiasEMA && rhs ) = default ;
1788-
17891813 void add ( double x, DateTime now )
17901814 {
1791- if ( likely ( !isnan ( x ) ) )
1792- {
1793- TimeDelta delta_t = now - m_last_tick;
1794- double decay = exp ( m_decay_factor * delta_t .asNanoseconds () );
1795- m_sqsum = decay * decay * m_sqsum + 1.0 ;
1796- m_wsum = decay * m_wsum + 1.0 ;
1797- m_last_tick = now;
1798- }
1815+ TimeDelta delta_t = now - m_last_tick;
1816+ double decay_factor = exp ( m_decay * delta_t .asNanoseconds () );
1817+ m_sqsum *= decay_factor * decay_factor;
1818+ m_wsum *= decay_factor;
1819+
1820+ double w0;
1821+ if ( m_adjust )
1822+ w0 = 1.0 ;
1823+ else
1824+ w0 = 1 - m_decay;
1825+ m_sqsum += w0 * w0;
1826+ m_wsum += w0;
1827+
1828+ m_last_tick = now;
17991829 }
18001830
18011831 void reset ()
@@ -1816,7 +1846,8 @@ class HalflifeDebiasEMA
18161846
18171847 double m_wsum;
18181848 double m_sqsum;
1819- double m_decay_factor;
1849+ double m_decay;
1850+ bool m_adjust;
18201851 DateTime m_last_tick;
18211852};
18221853
@@ -1841,10 +1872,22 @@ struct NanCheck
18411872 }
18421873};
18431874
1875+ template <typename T, typename ... Types>
1876+ struct is_any_of : std::false_type {};
1877+
1878+ template <typename T, typename First, typename ... Rest>
1879+ struct is_any_of <T, First, Rest...> { static constexpr bool value = std::is_same_v<T, First> || is_any_of<T, Rest...>::value; };
1880+
1881+ template <typename T, typename ... Types>
1882+ inline constexpr bool is_any_of_v = is_any_of<T, Types...>::value;
1883+
18441884// Validates min_data_points and takes care of NaN handling
18451885template <typename T>
18461886class DataValidator
18471887{
1888+ static constexpr bool PROCESS_NA = is_any_of_v<T, EMA , AdjustedEMA, AlphaDebiasEMA, Rank>;
1889+ static constexpr bool CONSIDER_NA = is_any_of_v<T, First, Last>;
1890+
18481891 public:
18491892 DataValidator () = default ;
18501893
@@ -1865,7 +1908,7 @@ class DataValidator
18651908 if ( isnan ( x ) )
18661909 {
18671910 m_nans++;
1868- if ( m_process_na || ( m_consider_na && !m_igna ) )
1911+ if ( PROCESS_NA || ( CONSIDER_NA && !m_igna ) )
18691912 m_stat.add ( x );
18701913 }
18711914 else
@@ -1893,7 +1936,7 @@ class DataValidator
18931936 if ( NanCheck::any_nan ( args...) )
18941937 {
18951938 m_nans--;
1896- if ( m_process_na || ( m_consider_na && !m_igna ) )
1939+ if ( PROCESS_NA || ( CONSIDER_NA && !m_igna ) )
18971940 m_stat.remove ( args... );
18981941 }
18991942 else
@@ -1906,7 +1949,7 @@ class DataValidator
19061949 template <typename ...V>
19071950 double compute ( V... args )
19081951 {
1909- if ( ( !m_igna && (m_nans > 0 && !m_consider_na ) ) || m_points < m_mdp )
1952+ if ( ( !m_igna && (m_nans > 0 && !CONSIDER_NA ) ) || m_points < m_mdp )
19101953 return std::numeric_limits<double >::quiet_NaN ();
19111954
19121955 return m_stat.compute ( args... );
@@ -1933,9 +1976,6 @@ class DataValidator
19331976 int64_t m_mdp = 0 ;
19341977 bool m_igna = false ;
19351978 T m_stat;
1936- static constexpr bool m_process_na = ( std::is_same<T,EMA >::value || std::is_same<T,AdjustedEMA>::value || std::is_same<T,AlphaDebiasEMA>::value
1937- || std::is_same<T,HalflifeEMA>::value || std::is_same<T,HalflifeDebiasEMA>::value || std::is_same<T,Rank>::value );
1938- static constexpr bool m_consider_na = ( std::is_same<T,First>::value || std::is_same<T,Last>::value );
19391979};
19401980
19411981
0 commit comments