From 0c436571bb9f21b6295f8ffc0af666aa5717864a Mon Sep 17 00:00:00 2001 From: Hossein Moein Date: Tue, 2 May 2023 13:59:41 -0400 Subject: [PATCH] Implemented EaseOfMovementVisitor visitor --- docs/HTML/DataFrame.html | 4 + docs/HTML/EaseOfMovementVisitor.html | 119 ++++++++++++++++++ .../DataFrame/DataFrameFinancialVisitors.h | 70 +++++++++++ test/dataframe_tester_3.cc | 34 +++++ 4 files changed, 227 insertions(+) create mode 100644 docs/HTML/EaseOfMovementVisitor.html diff --git a/docs/HTML/DataFrame.html b/docs/HTML/DataFrame.html index 363b99355..75723a39f 100644 --- a/docs/HTML/DataFrame.html +++ b/docs/HTML/DataFrame.html @@ -947,6 +947,10 @@

Table of Functionalities — with Code Samples struct DrawdownVisitor{ } + + struct EaseOfMovementVisitor{ } + + struct EBSineWaveVisitor{ } diff --git a/docs/HTML/EaseOfMovementVisitor.html b/docs/HTML/EaseOfMovementVisitor.html new file mode 100644 index 000000000..f4b176565 --- /dev/null +++ b/docs/HTML/EaseOfMovementVisitor.html @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + +
Signature Description Parameters
+
#include <DataFrame/DataFrameFinancialVisitors.h>
+
+template<typename T, typename I = unsigned long,
+         std::size_t A = 0>
+struct EaseOfMovementVisitor;
+
+// -------------------------------------
+
+template<typename T, typename I = unsigned long,
+         std::size_t A = 0>
+using eom_v = EaseOfMovementVisitor<T, I, A>;
+        
+
+ 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 visitor calculates the Ease Of Movement (EOM) indicator. It requires 4 input columns in order of low price, high price, close price, volume.
+ Richard Arms' Ease of Movement indicator is a technical study that attempts to quantify a mix of momentum and volume information into one value. The intent is to use this value to discern whether prices are able to rise, or fall, with little resistance in the directional movement.
+ When the indicator creates output values above zero and rising, this suggests that the price is increasing on low volume, while falling negative values suggest that the price is dropping on low volume.
+ +
+    explicit
+    EaseOfMovementVisitor(size_t roll_period = 14,
+                          value_type vol_divisor = 100,000,000);
+
+    roll_period: The averaging period
+    vol_divisor: Scale equals 1,000 to 1,000,000,000 depending on
+                 the average daily volume of the stock.
+                 The more heavily traded the stock, the higher the scale
+                 should be to keep the indicator value in single or double digits
+        
+
+
+ T: Column data type
+ I: Index type
+ A: Memory alignment boundary for vectors. Default is system default alignment
+
+ +
static void test_EaseOfMovementVisitor()  {
+
+    std::cout << "\nTesting EaseOfMovementVisitor{  } ..." << std::endl;
+
+    typedef StdDataFrame64<std::string> StrDataFrame;
+
+    StrDataFrame    df;
+
+    try  {
+        df.read("data/SHORT_IBM.csv", io_format::csv2);
+
+        eom_v<double, std::string>  eom;
+
+        df.single_act_visit<double, double, double, long>("IBM_Low", "IBM_High", "IBM_Close", "IBM_Volume", eom);
+
+        assert(eom.get_result().size() == 1721);
+        assert(std::isnan(eom.get_result()[0]));
+        assert(std::isnan(eom.get_result()[12]));
+        assert(std::abs(eom.get_result()[14] - -0.9462) < 0.0001);
+        assert(std::abs(eom.get_result()[16] - -11.3211) < 0.0001);
+        assert(std::abs(eom.get_result()[25] - -29.6584) < 0.0001);
+        assert(std::abs(eom.get_result()[1720] - -36.4666) < 0.0001);
+        assert(std::abs(eom.get_result()[1712] - -12.0302) < 0.0001);
+        assert(std::abs(eom.get_result()[1707] - -1.0561) < 0.0001);
+    }
+    catch (const DataFrameError &ex)  {
+        std::cout << ex.what() << std::endl;
+    }
+}
+
+ + C++ DataFrame + + + + + diff --git a/include/DataFrame/DataFrameFinancialVisitors.h b/include/DataFrame/DataFrameFinancialVisitors.h index 09a974459..92fefbdb2 100644 --- a/include/DataFrame/DataFrameFinancialVisitors.h +++ b/include/DataFrame/DataFrameFinancialVisitors.h @@ -5647,6 +5647,76 @@ struct EldersForceIndexVisitor { template using efi_v = EldersForceIndexVisitor; +// ---------------------------------------------------------------------------- + +template::value, T>::type> +struct EaseOfMovementVisitor { + + DEFINE_VISIT_BASIC_TYPES_3 + + template + inline void + operator() (const K &idx_begin, const K &idx_end, + const H &low_begin, const H &low_end, + const H &high_begin, const H &high_end, + const H &close_begin, const H &close_end, + const V &volume_begin, const V &volume_end) { + + const size_type col_s = std::distance(close_begin, close_end); + + assert((col_s == size_type(std::distance(low_begin, low_end)))); + assert((col_s == size_type(std::distance(high_begin, high_end)))); + assert((col_s == size_type(std::distance(volume_begin, volume_end)))); + assert(roll_period_ < col_s); + + result_type result; + constexpr value_type two = 2; + + result.reserve(col_s); + result.push_back(std::numeric_limits::quiet_NaN()); + for (size_type i { 1 }; i < col_s; ++i) { + const value_type low = *(low_begin + i); + const value_type high = *(high_begin + i); + const value_type hl_range = high - low; + const value_type distance = + ((high + low) / two) - + ((*(high_begin + (i - 1)) + *(low_begin + (i - 1))) / two); + const value_type box_ratio = + (*(volume_begin + i) / vol_div_) / hl_range; + + result.push_back(distance / box_ratio); + } + + SimpleRollAdopter, T, I, A> savg + { MeanVisitor(), roll_period_ } ; + + savg.pre(); + savg (idx_begin, idx_end, result.begin(), result.end()); + savg.post(); + + result_ = std::move(savg.get_result()); + } + + DEFINE_PRE_POST + DEFINE_RESULT + + explicit + EaseOfMovementVisitor(size_type roll_period = 14, + value_type vol_divisor = 100000000) + : roll_period_(roll_period), vol_div_(vol_divisor) { } + +private: + + result_type result_ { }; + const size_type roll_period_; + const value_type vol_div_; +}; + +template +using eom_v = EaseOfMovementVisitor; + } // namespace hmdf // ---------------------------------------------------------------------------- diff --git a/test/dataframe_tester_3.cc b/test/dataframe_tester_3.cc index 817b2d346..aef7b9c9f 100644 --- a/test/dataframe_tester_3.cc +++ b/test/dataframe_tester_3.cc @@ -2128,6 +2128,39 @@ static void test_EldersForceIndexVisitor() { // ----------------------------------------------------------------------------- +static void test_EaseOfMovementVisitor() { + + std::cout << "\nTesting EaseOfMovementVisitor{ } ..." << std::endl; + + typedef StdDataFrame64 StrDataFrame; + + StrDataFrame df; + + try { + df.read("data/SHORT_IBM.csv", io_format::csv2); + + eom_v eom; + + df.single_act_visit + ("IBM_Low", "IBM_High", "IBM_Close", "IBM_Volume", eom); + + assert(eom.get_result().size() == 1721); + assert(std::isnan(eom.get_result()[0])); + assert(std::isnan(eom.get_result()[12])); + assert(std::abs(eom.get_result()[14] - -0.9462) < 0.0001); + assert(std::abs(eom.get_result()[16] - -11.3211) < 0.0001); + assert(std::abs(eom.get_result()[25] - -29.6584) < 0.0001); + assert(std::abs(eom.get_result()[1720] - -36.4666) < 0.0001); + assert(std::abs(eom.get_result()[1712] - -12.0302) < 0.0001); + assert(std::abs(eom.get_result()[1707] - -1.0561) < 0.0001); + } + catch (const DataFrameError &ex) { + std::cout << ex.what() << std::endl; + } +} + +// ----------------------------------------------------------------------------- + int main(int, char *[]) { test_groupby_edge(); @@ -2173,6 +2206,7 @@ int main(int, char *[]) { test_PolicyLearningLossVisitor(); test_LossFunctionVisitor(); test_EldersForceIndexVisitor(); + test_EaseOfMovementVisitor(); return (0); }