Signature | Description | Parameters |
---|---|---|
#include <DataFrame/DataFrameFinancialVisitors.h> template<typename T, typename I = unsigned long, std::size_t A = 0> struct EldersThermometerVisitor; // ------------------------------------- template<typename T, typename I = unsigned long, std::size_t A = 0> using ether_v = EldersThermometerVisitor<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 Elder's Thermometer indicators. It requires 2 input columns in the order of low, high. Market temperature, introduced by Dr.Alexander Elder, helps differentiate between sleepy, quiet and hot market periods. Following is Mr.Elder's explanation on how to use this indicator (from his book "Come in to my Trading Room"): "When markets are quiet, the adjacent bars tend to overlap. The consensus of value is well established, and the crowd does little buying or selling outside of yesterday’s range. When highs and lows exceed their previous day’s values, they do so only by small margins. Market Thermometer falls and its EMA slants down, indicating a sleepy market. When a market begins to run, either up or down, its daily bars start pushing outside of the previous ranges. The histogram of Market Thermometer grows taller and crosses above its EMA, which soon turns up, confirming the new trend." Market Thermometer gives four trading signals, based on the relationship between its histogram and its moving average: 1) The best time to enter new positions is when Market Thermometer falls below its moving average. When Market Thermometer falls below its EMA, it indicates that the market is quiet. If your system flashes an entry signal, try to enter when the market is cooler than usual. When Market Thermometer rises above its moving average, it warns that the market is hot and slippage more likely. 2) Exit positions when Market Thermometer rises to triple the height of its moving average. A spike of Market Thermometer indicates a runaway move. When the crowd feels jarred by a sudden piece of news and surges, it is a good time to take profits. Panics tend to be short-lived, offering a brief opportunity to cash in. If the EMA of Market Thermometer stands at 5 cents, but the Thermometer itself shoots up to 15 cents, take profits. Test these values for the market you are trading. 3) Get ready for an explosive move if the Thermometer stays below its moving average for five to seven trading days. Quiet markets put amateurs to sleep. They become careless and stop watching prices. Volatility and volume fall, and professionals get a chance to run away with the market. Explosive moves often erupt from periods of inactivity. 4) Market Thermometer can help you set a profit target for the next trading day. If you are a short-term trader and are long, add the value of today’s Thermometer EMA to yesterday’s high and place a sell order there. If you are short, subtract the value of the Thermometer’s EMA from yesterday’s low and place an order to cover at that level." explicit EldersThermometerVisitor(size_t roll_period = 20, double buy_factor = 2, double sell_factor = 0.5); roll_period: The averaging period buy_factor: Multiplier for the buy signal sell_factor: Multiplier for the sell signalget_result() returns the thermometer vector. It has the same length as the input vectors get_result_ma() retruns the moving exponentially weighted average of the thermometer vector get_buy_signal() returns a boolean vector of buy signals get_sell_signal() returns a boolean vector of sell signals |
T: Column data type I: Index type A: Memory alignment boundary for vectors. Default is system default alignment |
static void test_EldersThermometerVisitor() { std::cout << "\nTesting EldersThermometerVisitor{ } ..." << std::endl; StrDataFrame df; try { df.read("data/SHORT_IBM.csv", io_format::csv2); ether_v<double, std::string> ether; df.single_act_visit<double, double>("IBM_Low", "IBM_High", ether); assert(ether.get_result().size() == 1721); assert(std::isnan(ether.get_result()[0])); assert(std::abs(ether.get_result()[13] - 7.12) < 0.0001); assert(std::abs(ether.get_result()[14] - 1.04) < 0.0001); assert(std::abs(ether.get_result()[18] - 0.27) < 0.0001); assert(std::abs(ether.get_result()[25] - 2.71) < 0.0001); assert(std::abs(ether.get_result()[1720] - 2.16) < 0.0001); assert(std::abs(ether.get_result()[1712] - 8.24) < 0.0001); assert(std::abs(ether.get_result()[1707] - 1.98) < 0.0001); assert(ether.get_result_ma().size() == 1721); assert(ether.get_result_ma()[0] == 0); assert(std::abs(ether.get_result_ma()[13] - 2.0858) < 0.0001); assert(std::abs(ether.get_result_ma()[14] - 1.9537) < 0.0001); assert(std::abs(ether.get_result_ma()[18] - 1.7528) < 0.0001); assert(std::abs(ether.get_result_ma()[25] - 1.7848) < 0.0001); assert(std::abs(ether.get_result_ma()[1720] - 2.558) < 0.0001); assert(std::abs(ether.get_result_ma()[1712] - 2.6612) < 0.0001); assert(std::abs(ether.get_result_ma()[1707] - 2.538) < 0.0001); assert(! ether.get_buy_signal()[0]); assert(! ether.get_buy_signal()[13]); assert(ether.get_buy_signal()[14]); assert(ether.get_buy_signal()[18]); assert(ether.get_buy_signal()[25]); assert(ether.get_buy_signal()[1720]); assert(! ether.get_buy_signal()[1712]); assert(ether.get_buy_signal()[1707]); assert(! ether.get_sell_signal()[0]); assert(ether.get_sell_signal()[13]); assert(ether.get_sell_signal()[14]); assert(! ether.get_sell_signal()[18]); assert(ether.get_sell_signal()[25]); assert(ether.get_sell_signal()[1720]); assert(ether.get_sell_signal()[1712]); assert(ether.get_sell_signal()[1707]); } catch (const DataFrameError &ex) { std::cout << ex.what() << std::endl; } }