diff --git a/docs/HTML/DataFrame.html b/docs/HTML/DataFrame.html index 12e3c3af..5f6a1ca6 100644 --- a/docs/HTML/DataFrame.html +++ b/docs/HTML/DataFrame.html @@ -697,6 +697,10 @@

API Reference with code samples

struct ClipVisitor{} + + struct EhlersBandPassFilterVisitor{} + + struct EhlersHighPassFilterVisitor{} diff --git a/docs/HTML/EhlersHighPassFilterVisitor.html b/docs/HTML/EhlersHighPassFilterVisitor.html index fe2a1f27..67217226 100644 --- a/docs/HTML/EhlersHighPassFilterVisitor.html +++ b/docs/HTML/EhlersHighPassFilterVisitor.html @@ -56,7 +56,7 @@ This is a "single action visitor", meaning it is passed the whole data vector in one call and you must use the single_act_visit() interface.

This is a transformer visitor. It means the column(s) passed to this visitor is not read-only and its values will change

- This functor class applies Ehlers' high pass smoothing filter to the input. Ehlers suggested a way to improve trend identification using high-pass filters. The basic smoothers like SMA , low-pass filters, have considerable lag in their display. Mr. Ehlers applied the high-pass filter and subtracted the high-pass filter output from the time series input. Doing these steps he removed high-frequency short-wavelength components (the ones causing the wiggles) from the time series.

+ This functor class applies Ehlers' high-pass smoothing filter to the input. Ehlers suggested a way to improve trend identification using high-pass filters. The basic smoothers like SMA , low-pass filters, have considerable lag in their display. Mr. Ehlers applied the high-pass filter and subtracted the high-pass filter output from the time series input. Doing these steps he removed high-frequency short-wavelength components (the ones causing the wiggles) from the time series.

     explicit
     EhlersHighPassFilterVisitor(value_type period = 20);
@@ -69,6 +69,45 @@
       
     
 
+
+
+
+
+
+
+
+
+
+    
+       
+        
#include <DataFrame/DataFrameTransformVisitors.h>
+
+template<typename T, typename I = unsigned long>
+struct EhlersBandPassFilterVisitor;
+
+// -------------------------------------
+
+template<typename T, typename I = unsigned long>
+using ebpf_v = EhlersBandPassFilterVisitor<T, I>;
+        
+ + + This is a "single action visitor", meaning it is passed the whole data vector in one call and you must use the single_act_visit() interface.

+ This is a transformer visitor. It means the column(s) passed to this visitor is not read-only and its values will change

+ This functor class applies Ehlers' band-pass smoothing filter to the input. The band-pass indicator is an oscillator-type indicator. It makes full use of the digital computational power of your computer and therefore is superior to conventional oscillators such as the relative strength index (RSI) or the stochastic indicator when the market is in a cycle mode. If you were to stop and think about what an oscillator does, you would conclude that it performs two functions: it detrends the price, and it does some smoothing.

+
+    explicit
+    EhlersBandPassFilterVisitor(value_type period = 20,
+                                value_type bandwidth = 0.3);
+        
+
+ + + T: Column data type.
+ I: Index type. + + +
static void test_EhlersHighPassFilterVisitor()  {
diff --git a/include/DataFrame/DataFrameStatsVisitors.h b/include/DataFrame/DataFrameStatsVisitors.h
index 6c69290c..676cb854 100644
--- a/include/DataFrame/DataFrameStatsVisitors.h
+++ b/include/DataFrame/DataFrameStatsVisitors.h
@@ -44,7 +44,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include 
 #ifndef M_PI
 #  define M_PI 3.14159265358979323846264338327950288
-#endif
+#endif // M_PI
 #include 
 #include 
 #include 
@@ -60,7 +60,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // 2PI
 //
-#define TAU 6.28318530717958647692528676655900576
+#ifndef TAU
+#  define TAU 6.28318530717958647692528676655900576
+#endif // TAU
 
 // ----------------------------------------------------------------------------
 
diff --git a/include/DataFrame/DataFrameTransformVisitors.h b/include/DataFrame/DataFrameTransformVisitors.h
index f35801b6..01a85626 100644
--- a/include/DataFrame/DataFrameTransformVisitors.h
+++ b/include/DataFrame/DataFrameTransformVisitors.h
@@ -65,6 +65,12 @@ struct  EhlersHighPassFilterVisitor  {
 
         GET_COL_SIZE
 
+#ifdef HMDF_SANITY_EXCEPTIONS
+        if (col_s < 3)
+            throw DataFrameError("EhlersHighPassFilterVisitor: "
+                                 "column size must be > 2");
+#endif // HMDF_SANITY_EXCEPTIONS
+
         const value_type    ang = TAU / period_;
         const value_type    ang_cos = std::cos(ang);
         const value_type    alpha =
@@ -101,6 +107,59 @@ using ehpf_v = EhlersHighPassFilterVisitor;
 
 // ----------------------------------------------------------------------------
 
+template
+struct  EhlersBandPassFilterVisitor  {
+
+    DEFINE_VISIT_BASIC_TYPES_4
+
+    template 
+    inline void
+    operator() (K idx_begin, K idx_end, H column_begin, H column_end) {
+
+        GET_COL_SIZE
+
+#ifdef HMDF_SANITY_EXCEPTIONS
+        if (col_s < 10)
+            throw DataFrameError("EhlersBandPassFilterVisitor: "
+                                 "column size must be > 9");
+#endif // HMDF_SANITY_EXCEPTIONS
+
+        const value_type        beta = std::cos(TAU / period_);
+        const value_type        gamma = T(1) / std::cos(TAU * bandw_ / period_);
+        const value_type        alpha =
+            gamma - std::sqrt(gamma * gamma - T(1));
+        const value_type        f1 = T(0.5) * (T(1) - alpha);
+        const value_type        f2 = beta * (T(1) + alpha);
+        std::vector filter(col_s, T(0));
+
+        filter[2] = f1 * (*(column_begin + 2) - *(column_begin));
+        for (size_type i = 3; i < col_s; ++i)
+            filter[i] = f1 * (*(column_begin + i) - *(column_begin + (i - 2))) +
+                        f2 * filter[i - 1] - alpha * filter[i - 2];
+        for (size_type i = 0; i < col_s; ++i)
+            *(column_begin + i) -= filter[i];
+    }
+
+    inline void pre ()  {  }
+    inline void post ()  {  }
+    inline result_type get_result () const  { return (0); }
+
+    explicit
+    EhlersBandPassFilterVisitor(value_type period = 20,
+                                value_type bandwidth = 0.3)
+        : period_(period), bandw_(bandwidth)  {  }
+
+private:
+
+    const value_type    period_;
+    const value_type    bandw_;
+};
+
+template
+using ebpf_v = EhlersBandPassFilterVisitor;
+
+// ----------------------------------------------------------------------------
+
 template
 struct  ClipVisitor  {
 
diff --git a/test/dataframe_tester_3.cc b/test/dataframe_tester_3.cc
index 3d500378..a951f5b7 100644
--- a/test/dataframe_tester_3.cc
+++ b/test/dataframe_tester_3.cc
@@ -3732,6 +3732,45 @@ static void test_EhlersHighPassFilterVisitor()  {
 
 // ----------------------------------------------------------------------------
 
+static void test_EhlersBandPassFilterVisitor()  {
+
+    std::cout << "\nTesting EhlersBandPassFilterVisitor{ } ..." << std::endl;
+
+    typedef StdDataFrame64 StrDataFrame;
+
+    StrDataFrame    df;
+
+    try  {
+        df.read("SHORT_IBM.csv", io_format::csv2);
+        df.load_column("Smooth Close",
+                               { df.get_column("IBM_Close").begin(),
+                                 df.get_column("IBM_Close").end() });
+
+        ebpf_v ebpf(14, 0.8);
+
+        df.single_act_visit("Smooth Close", ebpf);
+
+        const auto  &smooth_close = df.get_column("Smooth Close");
+
+        assert(smooth_close.size() == 1721);
+        assert(std::abs(smooth_close[0] - 185.53) < 0.001);
+        assert(std::abs(smooth_close[1] - 186.64) < 0.001);
+        assert(std::abs(smooth_close[2] - 185.928) < 0.001);
+        assert(std::abs(smooth_close[19] - 180.851) < 0.001);
+        assert(std::abs(smooth_close[20] - 178.903) < 0.001);
+        assert(std::abs(smooth_close[24] - 174.9) < 0.001);
+        assert(std::abs(smooth_close[25] - 176.41) < 0.001);
+        assert(std::abs(smooth_close[1720] - 113.541) < 0.001);
+        assert(std::abs(smooth_close[1712] - 119.954) < 0.001);
+        assert(std::abs(smooth_close[1707] - 123.239) < 0.001);
+    }
+    catch (const DataFrameError &ex)  {
+        std::cout << ex.what() << std::endl;
+    }
+}
+
+// ----------------------------------------------------------------------------
+
 int main(int, char *[]) {
 
     MyDataFrame::set_optimum_thread_level();
@@ -3810,6 +3849,7 @@ int main(int, char *[]) {
     test_client_csv_read_test();
     test_PeaksAndValleysVisitor();
     test_EhlersHighPassFilterVisitor();
+    test_EhlersBandPassFilterVisitor();
 
     return (0);
 }