Skip to content

Commit

Permalink
Implemented EhlersBandPassFilterVisitor visitor
Browse files Browse the repository at this point in the history
  • Loading branch information
hosseinmoein committed May 9, 2024
1 parent ec22ade commit 77b8f9c
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 3 deletions.
4 changes: 4 additions & 0 deletions docs/HTML/DataFrame.html
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,10 @@ <H2><font color="blue">API Reference with code samples</font></H2>
<td title="Clips column data to limits">struct <a href="https://htmlpreview.github.io/?https://github.com/hosseinmoein/DataFrame/blob/master/docs/HTML/ClipVisitor.html">ClipVisitor</a>{}</td>
</tr>

<tr class="item" onmouseover="this.style.backgroundColor='#ffff66';" onmouseout="this.style.backgroundColor='#d4e3e5';">
<td title="Applies Ehlers' smoothing band pass filter">struct <a href="https://htmlpreview.github.io/?https://github.com/hosseinmoein/DataFrame/blob/master/docs/HTML/EhlersHighPassFilterVisitor.html">EhlersBandPassFilterVisitor</a>{}</td>
</tr>

<tr class="item" onmouseover="this.style.backgroundColor='#ffff66';" onmouseout="this.style.backgroundColor='#d4e3e5';">
<td title="Applies Ehlers' smoothing high pass filter">struct <a href="https://htmlpreview.github.io/?https://github.com/hosseinmoein/DataFrame/blob/master/docs/HTML/EhlersHighPassFilterVisitor.html">EhlersHighPassFilterVisitor</a>{}</td>
</tr>
Expand Down
41 changes: 40 additions & 1 deletion docs/HTML/EhlersHighPassFilterVisitor.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
<td>
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.<BR><BR>
This is a transformer visitor. It means the column(s) passed to this visitor is not read-only and its values will change<BR><BR>
This functor class applies Ehlers' <I>high pass</I> 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.<BR><BR>
This functor class applies Ehlers' <I>high-pass</I> 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.<BR><BR>
<I><PRE>
explicit
EhlersHighPassFilterVisitor(value_type period = 20);
Expand All @@ -69,6 +69,45 @@
</td>
</tr>










<tr bgcolor="Azure">
<td bgcolor="blue"> <font color="white">
<PRE><B>#include &lt;DataFrame/DataFrameTransformVisitors.h&gt;

template&lt;typename T, typename I = unsigned long&gt;
struct EhlersBandPassFilterVisitor;

// -------------------------------------

template&lt;typename T, typename I = unsigned long&gt;
using ebpf_v = EhlersBandPassFilterVisitor&lt;T, I&gt;;
</B></PRE></font>
</td>
<td>
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.<BR><BR>
This is a transformer visitor. It means the column(s) passed to this visitor is not read-only and its values will change<BR><BR>
This functor class applies Ehlers' <I>band-pass</I> 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.<BR><BR>
<I><PRE>
explicit
EhlersBandPassFilterVisitor(value_type period = 20,
value_type bandwidth = 0.3);
</PRE>
</I>
</td>
<td width="30%">
<B>T</B>: Column data type.<BR>
<B>I</B>: Index type.
</td>
</tr>

</table>

<pre class="code_syntax" style="color:#000000;background:#ffffff00;"><span class="line_wrapper"><span style="color:#800000; font-weight:bold; ">static</span> <span style="color:#800000; font-weight:bold; ">void</span> test_EhlersHighPassFilterVisitor<span style="color:#808030; ">(</span><span style="color:#808030; ">)</span> <span style="color:#800080; ">{</span></span>
Expand Down
6 changes: 4 additions & 2 deletions include/DataFrame/DataFrameStatsVisitors.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <cmath>
#ifndef M_PI
# define M_PI 3.14159265358979323846264338327950288
#endif
#endif // M_PI
#include <cstddef>
#include <functional>
#include <future>
Expand All @@ -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

// ----------------------------------------------------------------------------

Expand Down
59 changes: 59 additions & 0 deletions include/DataFrame/DataFrameTransformVisitors.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -101,6 +107,59 @@ using ehpf_v = EhlersHighPassFilterVisitor<T, I>;

// ----------------------------------------------------------------------------

template<arithmetic T, typename I = unsigned long>
struct EhlersBandPassFilterVisitor {

DEFINE_VISIT_BASIC_TYPES_4

template <forward_iterator K, forward_iterator H>
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<value_type> 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<arithmetic T, typename I = unsigned long>
using ebpf_v = EhlersBandPassFilterVisitor<T, I>;

// ----------------------------------------------------------------------------

template<typename T, typename I = unsigned long>
struct ClipVisitor {

Expand Down
40 changes: 40 additions & 0 deletions test/dataframe_tester_3.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3732,6 +3732,45 @@ static void test_EhlersHighPassFilterVisitor() {

// ----------------------------------------------------------------------------

static void test_EhlersBandPassFilterVisitor() {

std::cout << "\nTesting EhlersBandPassFilterVisitor{ } ..." << std::endl;

typedef StdDataFrame64<std::string> StrDataFrame;

StrDataFrame df;

try {
df.read("SHORT_IBM.csv", io_format::csv2);
df.load_column<double>("Smooth Close",
{ df.get_column<double>("IBM_Close").begin(),
df.get_column<double>("IBM_Close").end() });

ebpf_v<double, std::string> ebpf(14, 0.8);

df.single_act_visit<double>("Smooth Close", ebpf);

const auto &smooth_close = df.get_column<double>("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();
Expand Down Expand Up @@ -3810,6 +3849,7 @@ int main(int, char *[]) {
test_client_csv_read_test();
test_PeaksAndValleysVisitor();
test_EhlersHighPassFilterVisitor();
test_EhlersBandPassFilterVisitor();

return (0);
}
Expand Down

0 comments on commit 77b8f9c

Please sign in to comment.