├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── code_blocks ├── check-lrma │ ├── check-lrma.cbp │ └── main.cpp ├── check-rshillma │ ├── check-rshillma.cbp │ └── main.cpp ├── check-td │ ├── check-td.cbp │ └── main.cpp ├── check_bb │ ├── check_bb.cbp │ └── main.cpp ├── check_crsi │ ├── check_crsi.cbp │ └── main.cpp ├── check_delay_line │ ├── check_delay_line.cbp │ └── main.cpp ├── check_fft │ ├── check_fft.cbp │ └── main.cpp ├── check_indicators │ ├── check_indicators.cbp │ └── main.cpp ├── check_maz │ ├── check_maz.cbp │ └── main.cpp ├── check_min_max │ ├── check_min_max.cbp │ └── main.cpp ├── check_min_max_difference │ ├── check_min_max_difference.cbp │ └── main.cpp ├── check_pri │ ├── check_pri.cbp │ └── main.cpp ├── check_sma │ ├── check_sma.cbp │ └── main.cpp ├── check_stochastics │ ├── check_stochastics.cbp │ └── main.cpp ├── check_sum │ ├── check_sum.cbp │ └── main.cpp ├── check_zscore │ ├── check_zscore.cbp │ └── main.cpp ├── checking_circular_buffer │ ├── checking_circular_buffer.cbp │ └── main.cpp ├── checking_delay_measurement │ ├── checking_delay_measurement.cbp │ └── main.cpp ├── checking_least_square_method │ ├── checking_least_square_method.cbp │ └── main.cpp ├── checking_normalization │ ├── checking_normalization.cbp │ └── main.cpp ├── checking_statistical_indicators │ ├── checking_statistical_indicators.cbp │ └── main.cpp ├── checking_statistics │ ├── checking_statistics.cbp │ └── main.cpp ├── cmp_min_max_witch_streaming_min_max │ ├── cmp_min_max_witch_streaming_min_max.cbp │ └── main.cpp └── test │ ├── atr.cpp │ ├── body_filter.cpp │ ├── cci.cpp │ ├── cluster_shaper.cpp │ ├── fractals.cpp │ ├── period_stats.cpp │ ├── ssa.cpp │ ├── super_trend.cpp │ ├── test.cbp │ └── trend_direction_force_index.cpp ├── doc └── example_0.png └── include ├── backtest └── xtechnical_winrate_statistics.hpp ├── indicators ├── ssa.hpp ├── xtechnical_atr.hpp ├── xtechnical_awesome_oscillator.hpp ├── xtechnical_body_filter.hpp ├── xtechnical_cci.hpp ├── xtechnical_cluster_shaper.hpp ├── xtechnical_crsi.hpp ├── xtechnical_delay_line.hpp ├── xtechnical_fast_min_max.hpp ├── xtechnical_fisher.hpp ├── xtechnical_fractals.hpp ├── xtechnical_fractals_level.hpp ├── xtechnical_period_stats.hpp ├── xtechnical_rsi.hpp ├── xtechnical_sma.hpp ├── xtechnical_super_trend.hpp └── xtechnical_true_range.hpp ├── math ├── xtechnical_compare.hpp ├── xtechnical_ordinary_least_squares.hpp └── xtechnical_smoothing.hpp ├── xtechnical_circular_buffer.hpp ├── xtechnical_circular_buffer.mqh ├── xtechnical_common.hpp ├── xtechnical_correlation.hpp ├── xtechnical_delay_meter.hpp ├── xtechnical_dft.hpp ├── xtechnical_indicators.hpp ├── xtechnical_moving_window.hpp ├── xtechnical_normalization.hpp ├── xtechnical_regression_analysis.hpp ├── xtechnical_sma.mqh ├── xtechnical_statistics.hpp └── xtechnical_streaming_min_max.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.depend 2 | *.layout 3 | *.o 4 | *testing/*/bin 5 | *code_blocks/*/bin 6 | 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/easy_plot_cpp"] 2 | path = lib/easy_plot_cpp 3 | url = https://github.com/NewYaroslav/easy_plot_cpp.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Yaroslav 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /code_blocks/check-lrma/check-lrma.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 41 | 42 | -------------------------------------------------------------------------------- /code_blocks/check-lrma/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | #include 4 | 5 | int main() { 6 | std::cout << "Hello world!" << std::endl; 7 | std::array test_data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; 8 | 9 | const size_t period = 4; 10 | xtechnical_indicators::LRMA iLRMA(period); 11 | 12 | for(size_t i = 0; i < test_data.size(); ++i) { 13 | iLRMA.update(test_data[i]); 14 | std::cout 15 | << "update " << test_data[i] 16 | << " get " << iLRMA.get() 17 | << std::endl; 18 | } 19 | 20 | /* проверяем методы тест */ 21 | std::cout << "test(20)" << std::endl; 22 | iLRMA.test(20); 23 | std::cout << "get " << iLRMA.get() << std::endl; 24 | 25 | 26 | std::cout << "test(21)" << std::endl; 27 | iLRMA.test(21); 28 | std::cout << "get " << iLRMA.get() << std::endl; 29 | 30 | std::cout << "test(10)" << std::endl; 31 | iLRMA.test(10); 32 | std::cout << "get " << iLRMA.get() << std::endl; 33 | 34 | for(size_t i = test_data.size() - 1; i > 0; --i) { 35 | iLRMA.update(test_data[i]); 36 | std::cout 37 | << "update " << test_data[i] 38 | << " get " << iLRMA.get() 39 | << std::endl; 40 | } 41 | 42 | for(size_t i = 0; i < test_data.size(); ++i) { 43 | iLRMA.update(test_data[i]); 44 | std::cout 45 | << "update " << test_data[i] 46 | << " get " << iLRMA.get() 47 | << std::endl; 48 | } 49 | 50 | std::system("pause"); 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /code_blocks/check-rshillma/check-rshillma.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 41 | 42 | -------------------------------------------------------------------------------- /code_blocks/check-rshillma/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | #include 4 | 5 | int main() { 6 | std::cout << "Hello world!" << std::endl; 7 | std::array test_data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; 8 | 9 | xtechnical_indicators::RSHILLMA, xtechnical_indicators::SMA> iRSHILLMA(5, 10, 100, 1.5); 10 | 11 | for(size_t j = 0; j < 100; ++j) 12 | for(size_t i = 0; i < test_data.size(); ++i) { 13 | iRSHILLMA.update(test_data[i]); 14 | } 15 | 16 | for(size_t i = 0; i < test_data.size(); ++i) { 17 | iRSHILLMA.update(test_data[i]); 18 | std::cout 19 | << "update " << test_data[i] 20 | << " get " << iRSHILLMA.get() 21 | << std::endl; 22 | } 23 | 24 | /* проверяем методы тест */ 25 | std::cout << "test(20)" << std::endl; 26 | iRSHILLMA.test(20); 27 | std::cout << "get " << iRSHILLMA.get() << std::endl; 28 | 29 | 30 | std::cout << "test(21)" << std::endl; 31 | iRSHILLMA.test(21); 32 | std::cout << "get " << iRSHILLMA.get() << std::endl; 33 | 34 | std::cout << "test(10)" << std::endl; 35 | iRSHILLMA.test(10); 36 | std::cout << "get " << iRSHILLMA.get() << std::endl; 37 | 38 | for(size_t i = test_data.size() - 1; i > 0; --i) { 39 | iRSHILLMA.update(test_data[i]); 40 | std::cout 41 | << "update " << test_data[i] 42 | << " get " << iRSHILLMA.get() 43 | << std::endl; 44 | } 45 | 46 | for(size_t i = 0; i < test_data.size(); ++i) { 47 | iRSHILLMA.update(test_data[i]); 48 | std::cout 49 | << "update " << test_data[i] 50 | << " get " << iRSHILLMA.get() 51 | << std::endl; 52 | } 53 | 54 | std::system("pause"); 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /code_blocks/check-td/check-td.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 38 | 39 | -------------------------------------------------------------------------------- /code_blocks/check-td/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | #include "../../include/backtest/xtechnical_winrate_statistics.hpp" 4 | #include 5 | 6 | int main() { 7 | std::cout << "Hello world!" << std::endl; 8 | std::array test_data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; 9 | 10 | const size_t period = 2; 11 | xtechnical::TrendDirectionForceIndex> trend(period); 12 | 13 | for(size_t i = 0; i < test_data.size(); ++i) { 14 | trend.update(test_data[i]); 15 | std::cout 16 | << "update " << test_data[i] 17 | << " get " << trend.get() 18 | << std::endl; 19 | } 20 | 21 | /* проверяем методы тест */ 22 | std::cout << "test(20)" << std::endl; 23 | trend.test(20); 24 | std::cout << "get " << trend.get() << std::endl; 25 | 26 | 27 | std::cout << "test(21)" << std::endl; 28 | trend.test(21); 29 | std::cout << "get " << trend.get() << std::endl; 30 | 31 | std::cout << "test(10)" << std::endl; 32 | trend.test(10); 33 | std::cout << "get " << trend.get() << std::endl; 34 | 35 | for(size_t i = test_data.size() - 1; i > 0; --i) { 36 | trend.update(test_data[i]); 37 | std::cout 38 | << "update " << test_data[i] 39 | << " get " << trend.get() 40 | << std::endl; 41 | } 42 | 43 | for(size_t i = 0; i < test_data.size(); ++i) { 44 | trend.update(test_data[i]); 45 | std::cout 46 | << "update " << test_data[i] 47 | << " get " << trend.get() 48 | << std::endl; 49 | } 50 | 51 | std::system("pause"); 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /code_blocks/check_bb/check_bb.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 44 | 45 | -------------------------------------------------------------------------------- /code_blocks/check_bb/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "xtechnical_indicators.hpp" 4 | #include "xtechnical_normalization.hpp" 5 | 6 | using namespace std; 7 | 8 | int main() { 9 | cout << "Hello world!" << endl; 10 | std::array test_data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; 11 | xtechnical_indicators::BollingerBands> bb(3,2,0); 12 | for(size_t i = 0; i < test_data.size(); ++i) { 13 | bb.update(test_data[i]); 14 | std::cout 15 | << "update " << test_data[i] 16 | << " tl " << bb.get_tl() 17 | << " ml " << bb.get_ml() 18 | << " bl " << bb.get_bl() 19 | << std::endl; 20 | } 21 | for(size_t i = 0; i < test_data.size(); ++i) { 22 | bb.test(test_data[i]); 23 | std::cout 24 | << "test " << test_data[i] 25 | << " tl " << bb.get_tl() 26 | << " ml " << bb.get_ml() 27 | << " bl " << bb.get_bl() 28 | << std::endl; 29 | } 30 | for(size_t i = 0; i < test_data.size(); ++i) { 31 | bb.update(test_data[i]); 32 | std::cout 33 | << "update " << test_data[i] 34 | << " tl " << bb.get_tl() 35 | << " ml " << bb.get_ml() 36 | << " bl " << bb.get_bl() 37 | << std::endl; 38 | } 39 | bb.clear(); 40 | for(size_t i = 0; i < test_data.size(); ++i) { 41 | bb.update(test_data[i]); 42 | std::cout 43 | << "update " << test_data[i] 44 | << " tl " << bb.get_tl() 45 | << " ml " << bb.get_ml() 46 | << " bl " << bb.get_bl() 47 | << std::endl; 48 | } 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /code_blocks/check_crsi/check_crsi.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 45 | 46 | -------------------------------------------------------------------------------- /code_blocks/check_crsi/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "xtechnical_indicators.hpp" 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | cout << "Hello world!" << endl; 9 | std::array test_data = {0,1,2,4,8,5,6,7,8,16,10,12,14,16,14,15,16,17,18,19}; 10 | xtechnical::CRSI> crsi(3,5,10); 11 | std::cout << "-0-" << std::endl; 12 | for(size_t i = 0; i < test_data.size(); ++i) { 13 | crsi.update(test_data[i]); 14 | std::cout 15 | << "i " << test_data[i] 16 | << " crsi " << crsi.get() 17 | << std::endl; 18 | } 19 | std::cout << "-1-" << std::endl; 20 | for(size_t i = 0; i < test_data.size(); ++i) { 21 | crsi.test(test_data[i]); 22 | std::cout 23 | << "i " << test_data[i] 24 | << " crsi " << crsi.get() 25 | << std::endl; 26 | } 27 | std::cout << "-2-" << std::endl; 28 | for(size_t i = 0; i < test_data.size(); ++i) { 29 | crsi.update(test_data[i]); 30 | std::cout 31 | << "i " << test_data[i] 32 | << " crsi " << crsi.get() 33 | << std::endl; 34 | } 35 | std::cout << "-3-" << std::endl; 36 | crsi.clear(); 37 | for(size_t i = 0; i < test_data.size(); ++i) { 38 | crsi.update(test_data[i]); 39 | std::cout 40 | << "i " << test_data[i] 41 | << " crsi " << crsi.get() 42 | << std::endl; 43 | } 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /code_blocks/check_delay_line/check_delay_line.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 43 | 44 | -------------------------------------------------------------------------------- /code_blocks/check_delay_line/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "xtechnical_indicators.hpp" 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | cout << "Hello world!" << endl; 9 | std::array test_data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; 10 | xtechnical_indicators::DelayLine delay_line(1); 11 | for(size_t i = 0; i < test_data.size(); ++i) { 12 | delay_line.update(test_data[i]); 13 | std::cout 14 | << "date " << test_data[i] 15 | << " get " << delay_line.get() 16 | << std::endl; 17 | } 18 | for(size_t i = 0; i < test_data.size(); ++i) { 19 | delay_line.test(test_data[i]); 20 | std::cout 21 | << "test date " << test_data[i] 22 | << " get test " << delay_line.get() 23 | << std::endl; 24 | } 25 | delay_line.clear(); 26 | for(size_t i = 0; i < test_data.size(); ++i) { 27 | delay_line.update(test_data[i]); 28 | std::cout 29 | << "date " << test_data[i] 30 | << " get " << delay_line.get() 31 | << std::endl; 32 | } 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /code_blocks/check_fft/check_fft.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 41 | 42 | -------------------------------------------------------------------------------- /code_blocks/check_fft/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | cout << "Hello world!" << endl; 8 | xtechnical_indicators::FreqHist 9 | iFreqHist(100, xtechnical_dft::RECTANGULAR_WINDOW); 10 | const double MATH_PI = 3.14159265358979323846264338327950288; 11 | for(size_t i = 0; i < 1000; ++i) { 12 | double temp = std::cos(3 * MATH_PI * 2 * (double)i / 100.0); 13 | 14 | std::vector amplitude; 15 | std::vector frequencies; 16 | iFreqHist.update(temp, amplitude, frequencies, 100); 17 | 18 | std::cout << "step: " << i << " temp " << temp << std::endl; 19 | for(size_t i = 0; i < frequencies.size(); ++i) { 20 | std::cout << "freq " << frequencies[i] << " " << amplitude[i] << std::endl; 21 | } 22 | std::cout << std::endl << std::endl; 23 | } 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /code_blocks/check_indicators/check_indicators.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 52 | 53 | -------------------------------------------------------------------------------- /code_blocks/check_indicators/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | cout << "Hello world!" << endl; 8 | xtechnical_indicators::MW iMW(30); 9 | xtechnical_indicators::MMA iMMA(5); 10 | xtechnical_indicators::SMA iSMA(5); 11 | xtechnical_indicators::AMA iAMA(10); 12 | xtechnical_indicators::NoLagMa iNoLagMa(10); 13 | xtechnical_indicators::RoC iRoC(3); 14 | xtechnical_indicators::VWMA iVWMA(20); 15 | 16 | 17 | for(int i = 1; i <= 50; ++i) { 18 | //int temp = -(i*2);//i % 4; 19 | int temp = i % 4; 20 | iMW.update(temp); 21 | 22 | double std_dev_value = 0; 23 | int err_std_dev = iMW.get_std_dev(std_dev_value, 10, 0); 24 | if(err_std_dev == 0) { 25 | double mean_value = 0; 26 | iMW.get_average(mean_value, 4, 0); 27 | double angle_value = 0; 28 | iMW.compare_data( 29 | angle_value, 30 | xtechnical_common::CALCULATE_ANGLE, 31 | true, 32 | mean_value - 2*std_dev_value, 33 | mean_value + 2*std_dev_value, 34 | 10, 35 | 0); 36 | std::cout << "ANGLE " << angle_value << std::endl; 37 | } 38 | 39 | double mma_out = 0.0; 40 | iMMA.update(temp, mma_out); 41 | 42 | double ama_out = 0.0; 43 | iAMA.update(temp, ama_out); 44 | 45 | double sma_out = 0.0; 46 | iSMA.update(temp, sma_out); 47 | 48 | double roc_out = 0.0; 49 | iRoC.update(temp, roc_out); 50 | 51 | double vwma_out = 0.0; 52 | iVWMA.update(temp,i, vwma_out); 53 | 54 | std::vector rsi; 55 | std::vector sma; 56 | std::vector std_dev; 57 | iMW.get_rsi_array(rsi, 3, 15, 3); 58 | iMW.get_average_and_std_dev_array(sma, std_dev, 10, 22, 3); 59 | 60 | std::cout << "step: " << i << " temp " << temp << " is init: " << iMW.is_init() << std::endl; 61 | for(size_t i = 0; i < sma.size(); ++i) { 62 | std::cout << "rsi: " << rsi[i] << " sma: " << sma[i] << " std_dev: " << std_dev[i] << std::endl; 63 | } 64 | std::cout << "MMA: " << mma_out << " SMA " << sma_out << " AMA " << ama_out << std::endl; 65 | std::cout << "RoC: " << roc_out << std::endl; 66 | std::cout << "VWMA: " << vwma_out << std::endl; 67 | } 68 | 69 | double rsi_value = 0; 70 | iMW.get_rsi(rsi_value, 15); 71 | std::cout << "rsi_value: " << rsi_value << std::endl; 72 | double aver_value = 0; 73 | iMW.get_average(aver_value, 22); 74 | std::cout << "aver_value: " << aver_value << std::endl; 75 | double std_dev_value = 0; 76 | iMW.get_std_dev(std_dev_value, 22); 77 | std::cout << "std_dev: " << std_dev_value << std::endl; 78 | 79 | xtechnical_indicators::VCMA iVCMA; 80 | std::cout << iVCMA.update(2,1) << std::endl; 81 | std::cout << iVCMA.update(3,0.5) << std::endl; 82 | std::cout << iVCMA.update(1,0.5) << std::endl; 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /code_blocks/check_maz/check_maz.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 44 | 45 | -------------------------------------------------------------------------------- /code_blocks/check_maz/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "xtechnical_indicators.hpp" 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | cout << "Hello world!" << endl; 9 | 10 | std::array test_data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; 11 | xtechnical_indicators::MAZ iMAZ(5, 20); 12 | 13 | for(size_t i = 0; i < test_data.size(); ++i) { 14 | iMAZ.update(test_data[i]); 15 | } 16 | 17 | for(size_t i = 0; i < test_data.size(); ++i) { 18 | iMAZ.update(test_data[i]); 19 | std::cout 20 | << "date " << test_data[i] 21 | << " get " << iMAZ.get() 22 | << std::endl; 23 | } 24 | 25 | for(size_t i = 0; i < test_data.size(); ++i) { 26 | iMAZ.test(test_data[i]); 27 | std::cout 28 | << "date " << test_data[i] 29 | << " get test " << iMAZ.get() 30 | << std::endl; 31 | } 32 | for(size_t i = 0; i < test_data.size(); ++i) { 33 | iMAZ.update(test_data[i]); 34 | std::cout 35 | << "date " << test_data[i] 36 | << " get " << iMAZ.get() 37 | << std::endl; 38 | } 39 | iMAZ.clear(); 40 | for(size_t i = 0; i < test_data.size(); ++i) { 41 | iMAZ.update(test_data[i]); 42 | std::cout 43 | << "date " << test_data[i] 44 | << " get " << iMAZ.get() 45 | << std::endl; 46 | } 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /code_blocks/check_min_max/check_min_max.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 43 | 44 | -------------------------------------------------------------------------------- /code_blocks/check_min_max/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "xtechnical_indicators.hpp" 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | cout << "Hello world!" << endl; 9 | std::array test_data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; 10 | xtechnical_indicators::MinMax min_max(4, 1); 11 | std::cout << "---" << std::endl; 12 | for(size_t i = 0; i < test_data.size(); ++i) { 13 | min_max.update(test_data[i]); 14 | std::cout 15 | << "date " << test_data[i] 16 | << " min " << min_max.get_min() 17 | << " max " << min_max.get_max() 18 | << std::endl; 19 | } 20 | for(size_t i = 0; i < test_data.size(); ++i) { 21 | min_max.test(test_data[i]); 22 | std::cout 23 | << "date test " << test_data[i] 24 | << " min " << min_max.get_min() 25 | << " max " << min_max.get_max() 26 | << std::endl; 27 | } 28 | for(size_t i = 0; i < test_data.size(); ++i) { 29 | min_max.update(test_data[i]); 30 | std::cout 31 | << "date " << test_data[i] 32 | << " min " << min_max.get_min() 33 | << " max " << min_max.get_max() 34 | << std::endl; 35 | } 36 | min_max.clear(); 37 | for(size_t i = 0; i < test_data.size(); ++i) { 38 | min_max.update(test_data[i]); 39 | std::cout 40 | << "date " << test_data[i] 41 | << " min " << min_max.get_min() 42 | << " max " << min_max.get_max() 43 | << std::endl; 44 | } 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /code_blocks/check_min_max_difference/check_min_max_difference.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 43 | 44 | -------------------------------------------------------------------------------- /code_blocks/check_min_max_difference/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "xtechnical_indicators.hpp" 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | cout << "Hello world!" << endl; 9 | std::array test_data = {0,1,2,4,8,5,6,7,8,16,10,12,14,16,14,15,16,17,18,19}; 10 | xtechnical_indicators::MinMaxDiff min_max(4, 1); 11 | std::cout << "---" << std::endl; 12 | for(size_t i = 0; i < test_data.size(); ++i) { 13 | min_max.update(test_data[i]); 14 | std::cout 15 | << "date " << test_data[i] 16 | << " get " << min_max.get() 17 | << " min " << min_max.get_min() 18 | << " max " << min_max.get_max() 19 | << std::endl; 20 | } 21 | for(size_t i = 0; i < test_data.size(); ++i) { 22 | min_max.test(test_data[i]); 23 | std::cout 24 | << "date test " << test_data[i] 25 | << " get " << min_max.get() 26 | << " min " << min_max.get_min() 27 | << " max " << min_max.get_max() 28 | << std::endl; 29 | } 30 | for(size_t i = 0; i < test_data.size(); ++i) { 31 | min_max.update(test_data[i]); 32 | std::cout 33 | << "date " << test_data[i] 34 | << " get " << min_max.get() 35 | << " min " << min_max.get_min() 36 | << " max " << min_max.get_max() 37 | << std::endl; 38 | } 39 | min_max.clear(); 40 | for(size_t i = 0; i < test_data.size(); ++i) { 41 | min_max.update(test_data[i]); 42 | std::cout 43 | << "date " << test_data[i] 44 | << " get " << min_max.get() 45 | << " min " << min_max.get_min() 46 | << " max " << min_max.get_max() 47 | << std::endl; 48 | } 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /code_blocks/check_pri/check_pri.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 43 | 44 | -------------------------------------------------------------------------------- /code_blocks/check_pri/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "xtechnical_indicators.hpp" 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | cout << "Hello world!" << endl; 9 | std::array test_data = {0,1,2,4,8,5,6,7,8,16,10,12,14,16,14,15,16,17,18,19}; 10 | xtechnical_indicators::PRI pri(4); 11 | std::cout << "---" << std::endl; 12 | for(size_t i = 0; i < test_data.size(); ++i) { 13 | pri.update(test_data[i]); 14 | std::cout 15 | << "date " << test_data[i] 16 | << " get " << pri.get() 17 | << std::endl; 18 | } 19 | for(size_t i = 0; i < test_data.size(); ++i) { 20 | pri.test(test_data[i]); 21 | std::cout 22 | << "date test " << test_data[i] 23 | << " get " << pri.get() 24 | << std::endl; 25 | } 26 | for(size_t i = 0; i < test_data.size(); ++i) { 27 | pri.update(test_data[i]); 28 | std::cout 29 | << "date " << test_data[i] 30 | << " get " << pri.get() 31 | << std::endl; 32 | } 33 | pri.clear(); 34 | for(size_t i = 0; i < test_data.size(); ++i) { 35 | pri.update(test_data[i]); 36 | std::cout 37 | << "date " << test_data[i] 38 | << " get " << pri.get() 39 | << std::endl; 40 | } 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /code_blocks/check_sma/check_sma.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 43 | 44 | -------------------------------------------------------------------------------- /code_blocks/check_sma/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "xtechnical_indicators.hpp" 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | cout << "Hello world!" << endl; 9 | std::array test_data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; 10 | xtechnical_indicators::SMA sma(4); 11 | for(size_t i = 0; i < test_data.size(); ++i) { 12 | sma.update(test_data[i]); 13 | std::cout 14 | << "date " << test_data[i] 15 | << " get " << sma.get() 16 | << std::endl; 17 | } 18 | for(size_t i = 0; i < test_data.size(); ++i) { 19 | sma.test(test_data[i]); 20 | std::cout 21 | << "date test " << test_data[i] 22 | << " get test " << sma.get() 23 | << std::endl; 24 | } 25 | for(size_t i = 0; i < test_data.size(); ++i) { 26 | sma.update(test_data[i]); 27 | std::cout 28 | << "date " << test_data[i] 29 | << " get " << sma.get() 30 | << std::endl; 31 | } 32 | sma.clear(); 33 | for(size_t i = 0; i < test_data.size(); ++i) { 34 | sma.update(test_data[i]); 35 | std::cout 36 | << "date " << test_data[i] 37 | << " get " << sma.get() 38 | << std::endl; 39 | } 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /code_blocks/check_stochastics/check_stochastics.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 43 | 44 | -------------------------------------------------------------------------------- /code_blocks/check_stochastics/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "xtechnical_indicators.hpp" 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | cout << "Hello world!" << endl; 9 | std::array test_data = {0,1,2,4,8,5,6,7,8,16,10,12,14,16,14,15,16,17,18,19}; 10 | xtechnical_indicators::Stochastics> stochastics(10,3,5); 11 | std::cout << "-0-" << std::endl; 12 | for(size_t i = 0; i < test_data.size(); ++i) { 13 | stochastics.update(test_data[i]); 14 | std::cout 15 | << "i " << test_data[i] 16 | << " k " << stochastics.get() 17 | << " %k " << stochastics.get_k() 18 | << " %d " << stochastics.get_d() 19 | << std::endl; 20 | } 21 | std::cout << "-1-" << std::endl; 22 | for(size_t i = 0; i < test_data.size(); ++i) { 23 | stochastics.test(test_data[i]); 24 | std::cout 25 | << "i " << test_data[i] 26 | << " k " << stochastics.get() 27 | << " %k " << stochastics.get_k() 28 | << " %d " << stochastics.get_d() 29 | << std::endl; 30 | } 31 | std::cout << "-2-" << std::endl; 32 | for(size_t i = 0; i < test_data.size(); ++i) { 33 | stochastics.update(test_data[i]); 34 | std::cout 35 | << "i " << test_data[i] 36 | << " k " << stochastics.get() 37 | << " %k " << stochastics.get_k() 38 | << " %d " << stochastics.get_d() 39 | << std::endl; 40 | } 41 | std::cout << "-3-" << std::endl; 42 | stochastics.clear(); 43 | for(size_t i = 0; i < test_data.size(); ++i) { 44 | stochastics.update(test_data[i]); 45 | std::cout 46 | << "i " << test_data[i] 47 | << " k " << stochastics.get() 48 | << " %k " << stochastics.get_k() 49 | << " %d " << stochastics.get_d() 50 | << std::endl; 51 | } 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /code_blocks/check_sum/check_sum.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 43 | 44 | -------------------------------------------------------------------------------- /code_blocks/check_sum/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "xtechnical_indicators.hpp" 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | cout << "Hello world!" << endl; 9 | std::array test_data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; 10 | xtechnical_indicators::SUM sum(4); 11 | for(size_t i = 0; i < test_data.size(); ++i) { 12 | sum.update(test_data[i]); 13 | std::cout 14 | << "date " << test_data[i] 15 | << " get " << sum.get() 16 | << std::endl; 17 | } 18 | for(size_t i = 0; i < test_data.size(); ++i) { 19 | sum.test(test_data[i]); 20 | std::cout 21 | << "date test " << test_data[i] 22 | << " get test " << sum.get() 23 | << std::endl; 24 | } 25 | for(size_t i = 0; i < test_data.size(); ++i) { 26 | sum.update(test_data[i]); 27 | std::cout 28 | << "date " << test_data[i] 29 | << " get " << sum.get() 30 | << std::endl; 31 | } 32 | sum.clear(); 33 | for(size_t i = 0; i < test_data.size(); ++i) { 34 | sum.update(test_data[i]); 35 | std::cout 36 | << "date " << test_data[i] 37 | << " get " << sum.get() 38 | << std::endl; 39 | } 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /code_blocks/check_zscore/check_zscore.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 45 | 46 | -------------------------------------------------------------------------------- /code_blocks/check_zscore/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "xtechnical_indicators.hpp" 4 | #include "xtechnical_normalization.hpp" 5 | 6 | using namespace std; 7 | 8 | int main() { 9 | cout << "Hello world!" << endl; 10 | 11 | std::array zscore_test_data = {1,2,3,4,5}; 12 | std::array zscore_out; 13 | xtechnical::normalization::calculate_zscore(zscore_test_data, zscore_out, 1, 1000); 14 | for(size_t i = 0; i < zscore_out.size(); ++i) { 15 | std::cout 16 | << "zscore " << zscore_out[i] 17 | << std::endl; 18 | } 19 | 20 | std::system("pause"); 21 | std::array test_data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; 22 | const size_t period = 5; 23 | xtechnical::Zscore zscore(period); 24 | for(size_t i = 0; i < test_data.size(); ++i) { 25 | zscore.update(test_data[i]); 26 | std::cout 27 | << "date " << test_data[i] 28 | << " get " << zscore.get() 29 | << std::endl; 30 | } 31 | for(size_t i = 0; i < test_data.size(); ++i) { 32 | zscore.test(test_data[i]); 33 | std::cout 34 | << "date " << test_data[i] 35 | << " get test " << zscore.get() 36 | << std::endl; 37 | } 38 | for(size_t i = 0; i < test_data.size(); ++i) { 39 | zscore.update(test_data[i]); 40 | std::cout 41 | << "date " << test_data[i] 42 | << " get " << zscore.get() 43 | << std::endl; 44 | } 45 | zscore.clear(); 46 | for(size_t i = 0; i < test_data.size(); ++i) { 47 | zscore.update(test_data[i]); 48 | std::cout 49 | << "date " << test_data[i] 50 | << " get " << zscore.get() 51 | << std::endl; 52 | } 53 | 54 | zscore.clear(); 55 | { 56 | double _m = 0, _sum = 0, _std = 0; 57 | for(size_t i = 0; i < period; ++i) { 58 | _m += test_data[i]; 59 | zscore.update(test_data[i]); 60 | std::cout 61 | << "date " << test_data[i] 62 | << " get " << zscore.get() 63 | << std::endl; 64 | } 65 | _m /= (double)period; 66 | 67 | for(size_t i = 0; i < period; ++i) { 68 | const double temp = test_data[i] - _m; 69 | _sum += temp * temp; 70 | } 71 | 72 | _sum /= (double)(period - 1); 73 | _std = std::sqrt(_sum); 74 | 75 | } 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /code_blocks/checking_circular_buffer/checking_circular_buffer.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 41 | 42 | -------------------------------------------------------------------------------- /code_blocks/checking_circular_buffer/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_circular_buffer.hpp" 3 | #include 4 | 5 | int main() { 6 | std::cout << "Hello world!" << std::endl; 7 | std::array test_data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; 8 | 9 | /* создадим кольцевой буфер размером 8 элементов */ 10 | const size_t buffer_size = 8; 11 | xtechnical::circular_buffer circular_buffer(buffer_size); 12 | 13 | /* заполняем буфер данными и выводим на экран */ 14 | for(size_t i = 0; i < test_data.size(); ++i) { 15 | circular_buffer.push_back(test_data[i]); 16 | std::cout 17 | << "push " << test_data[i] 18 | << " front " << circular_buffer.front() 19 | << " back " << circular_buffer.back() 20 | << " [0] " << circular_buffer[0] 21 | << " [" << (buffer_size - 1) << "] " << circular_buffer[buffer_size - 1] 22 | << " full " << circular_buffer.full() 23 | << std::endl; 24 | } 25 | 26 | /* выводим на экран данные буфера */ 27 | for(size_t i = 0; i < buffer_size; ++i) { 28 | std::cout 29 | << " [" << i << "] " << circular_buffer[i] 30 | << std::endl; 31 | } 32 | 33 | /* флаги буфера */ 34 | std::cout << "empty " << circular_buffer.empty() << std::endl; 35 | std::cout << "full " << circular_buffer.full() << std::endl; 36 | 37 | /* первый и последний эхлемент буфера */ 38 | std::cout << "front " << circular_buffer.front() << std::endl; 39 | std::cout << "back " << circular_buffer.back() << std::endl; 40 | 41 | /* проверяем методы тест */ 42 | std::cout << "test(20)" << std::endl; 43 | circular_buffer.test(20); 44 | std::cout << "back " << circular_buffer.back() << std::endl; 45 | std::cout << "test(21)" << std::endl; 46 | circular_buffer.test(21); 47 | std::cout << "back " << circular_buffer.back() << std::endl; 48 | std::cout << "update(20)" << std::endl; 49 | circular_buffer.update(20); 50 | std::cout << "back " << circular_buffer.back() << std::endl; 51 | 52 | /* выводим на экран данные буфера */ 53 | for(size_t i = 0; i < buffer_size; ++i) { 54 | std::cout 55 | << " [" << i << "] " << circular_buffer[i] 56 | << std::endl; 57 | } 58 | 59 | /* получаем значения среднего элемента, суммы и среднего значения буфера */ 60 | std::cout << "middle " << circular_buffer.middle() << std::endl; 61 | std::cout << "sum " << circular_buffer.sum() << std::endl; 62 | std::cout << "mean " << circular_buffer.mean() << std::endl; 63 | 64 | /* очищаем и повторно заполняем буфер данными и выводим на экран */ 65 | circular_buffer.clear(); 66 | for(size_t i = 0; i < test_data.size(); ++i) { 67 | circular_buffer.push_back(test_data[i]); 68 | std::cout 69 | << "push " << test_data[i] 70 | << " front " << circular_buffer.front() 71 | << " back " << circular_buffer.back() 72 | << " [0] " << circular_buffer[0] 73 | << " [" << (buffer_size - 1) << "] " << circular_buffer[buffer_size - 1] 74 | << " full " << circular_buffer.full() 75 | << std::endl; 76 | } 77 | 78 | std::vector temp = circular_buffer.to_vector(); 79 | for(size_t i = 0; i < temp.size(); ++i) { 80 | std::cout 81 | << "temp[" << i << "] " << temp[i] 82 | << std::endl; 83 | } 84 | 85 | for(size_t i = 0; i < test_data.size(); ++i) { 86 | std::cout << "***" << std::endl; 87 | circular_buffer.push_back(test_data[i]); 88 | std::vector temp = circular_buffer.to_vector(); 89 | for(size_t i = 0; i < temp.size(); ++i) { 90 | std::cout 91 | << "temp[" << i << "] " << temp[i] 92 | << std::endl; 93 | } 94 | std::system("pause"); 95 | } 96 | for(size_t i = 0; i < test_data.size(); ++i) { 97 | std::cout << "***" << std::endl; 98 | circular_buffer.push_back(test_data[i]); 99 | std::vector temp = circular_buffer.to_vector(); 100 | for(size_t i = 0; i < temp.size(); ++i) { 101 | std::cout 102 | << "temp[" << i << "] " << temp[i] 103 | << std::endl; 104 | } 105 | std::system("pause"); 106 | } 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /code_blocks/checking_delay_measurement/checking_delay_measurement.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 42 | 43 | -------------------------------------------------------------------------------- /code_blocks/checking_least_square_method/checking_least_square_method.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 51 | 52 | -------------------------------------------------------------------------------- /code_blocks/checking_least_square_method/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_regression_analysis.hpp" 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::cout << "Hello world!" << std::endl; 8 | 9 | double coeff[3]; 10 | double test_data[6][2] = { 11 | {1,2}, 12 | {2,3}, 13 | {3,4}, 14 | {4,5}, 15 | {5,6}, 16 | {6,7}, 17 | }; 18 | 19 | std::array test_data2 = { 20 | 1,2,3,4,5,6, 21 | 2,3,4,5,6,7 22 | }; 23 | 24 | std::vector> test_data3; 25 | test_data3.resize(6); 26 | test_data3[0][0] = 1; 27 | test_data3[0][1] = 2; 28 | test_data3[1][0] = 2; 29 | test_data3[1][1] = 3; 30 | test_data3[2][0] = 3; 31 | test_data3[2][1] = 4; 32 | test_data3[3][0] = 4; 33 | test_data3[3][1] = 5; 34 | test_data3[4][0] = 5; 35 | test_data3[4][1] = 6; 36 | test_data3[5][0] = 6; 37 | test_data3[5][1] = 7; 38 | 39 | xtechnical_regression_analysis::calc_least_squares_method(coeff, test_data, 6, xtechnical_regression_analysis::LSM_PARABOLA); 40 | double in_data = 7; 41 | double out_data = xtechnical_regression_analysis::calc_line(coeff, in_data, xtechnical_regression_analysis::LSM_PARABOLA); 42 | std::cout << "out_data " << out_data << std::endl; 43 | 44 | xtechnical_regression_analysis::calc_least_squares_method(coeff, test_data2, 6, xtechnical_regression_analysis::LSM_PARABOLA); 45 | out_data = xtechnical_regression_analysis::calc_line(coeff, in_data, xtechnical_regression_analysis::LSM_PARABOLA); 46 | std::cout << "out_data " << out_data << std::endl; 47 | 48 | xtechnical_regression_analysis::calc_least_squares_method(coeff, test_data3, 6, xtechnical_regression_analysis::LSM_PARABOLA); 49 | out_data = xtechnical_regression_analysis::calc_line(coeff, in_data, xtechnical_regression_analysis::LSM_PARABOLA); 50 | std::cout << "out_data " << out_data << std::endl; 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /code_blocks/checking_normalization/checking_normalization.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 49 | 50 | -------------------------------------------------------------------------------- /code_blocks/checking_normalization/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | #include 4 | 5 | int main() { 6 | std::cout << "Hello world!" << std::endl; 7 | std::array test_data = {1,2,3,1,0.5,6,6}; 8 | std::array out_data; 9 | xtechnical_normalization::calculate_min_max(test_data, out_data, xtechnical_common::MINMAX_UNSIGNED); 10 | std::cout << "calculate_min_max (MINMAX_UNSIGNED):" << std::endl; 11 | for(size_t i = 0; i < out_data.size(); ++i) { 12 | std::cout << out_data[i] << std::endl; 13 | } 14 | 15 | xtechnical_normalization::calculate_min_max(test_data, out_data, xtechnical_common::MINMAX_SIGNED); 16 | std::cout << "calculate_min_max (MINMAX_SIGNED):" << std::endl; 17 | for(size_t i = 0; i < out_data.size(); ++i) { 18 | std::cout << out_data[i] << std::endl; 19 | } 20 | 21 | xtechnical_normalization::calculate_zscore(test_data, out_data); 22 | std::cout << "calculate_zscore:" << std::endl; 23 | for(size_t i = 0; i < out_data.size(); ++i) { 24 | std::cout << out_data[i] << std::endl; 25 | } 26 | 27 | std::array out_data_2; 28 | xtechnical_normalization::calculate_difference(test_data, out_data_2); 29 | std::cout << "calculate_difference:" << std::endl; 30 | for(size_t i = 0; i < out_data_2.size(); ++i) { 31 | std::cout << out_data_2[i] << std::endl; 32 | } 33 | 34 | 35 | xtechnical_normalization::normalize_amplitudes(test_data, out_data, (double)1.0); 36 | std::cout << "normalize_amplitudes:" << std::endl; 37 | for(size_t i = 0; i < out_data.size(); ++i) { 38 | std::cout << out_data[i] << std::endl; 39 | } 40 | 41 | xtechnical_normalization::calculate_log(test_data, out_data); 42 | std::cout << "calculate_log:" << std::endl; 43 | for(size_t i = 0; i < out_data.size(); ++i) { 44 | std::cout << out_data[i] << std::endl; 45 | } 46 | 47 | 48 | xtechnical_normalization::calc_automatic_gain_control>(test_data, out_data, 3); 49 | std::cout << "automatic_gain_control:" << std::endl; 50 | for(size_t i = 0; i < out_data.size(); ++i) { 51 | std::cout << out_data[i] << std::endl; 52 | } 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /code_blocks/checking_statistical_indicators/checking_statistical_indicators.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 50 | 51 | -------------------------------------------------------------------------------- /code_blocks/checking_statistical_indicators/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | #include 4 | 5 | int main() { 6 | std::cout << "Hello world!" << std::endl; 7 | std::array test_data = {1,2,3,1,0.5,6,6}; 8 | 9 | double temp = 0; 10 | xtechnical_indicators::calculate_sma(test_data, temp, 4, 1); 11 | std::cout << "calculate_sma:" << std::endl; 12 | std::cout << temp << std::endl; 13 | xtechnical_indicators::calculate_std_dev(test_data, temp, 4, 1); 14 | std::cout << "calculate_std_dev:" << std::endl; 15 | std::cout << temp << std::endl; 16 | double temp2 = 0; 17 | xtechnical_indicators::calculate_std_dev_and_mean(test_data, temp, temp2, 4, 1); 18 | std::cout << "calculate_std_dev_and_mean:" << std::endl; 19 | std::cout << temp << std::endl; 20 | std::cout << temp2 << std::endl; 21 | 22 | std::array test_data2 = {100,101,99,97,110,105,99}; 23 | std::array out_tl, out_ml, out_bl; 24 | xtechnical_indicators::calc_ring_bollinger(test_data2, out_tl, out_ml, out_bl, 4, 2); 25 | std::cout << "calc_ring_bollinger:" << std::endl; 26 | for(size_t i = 0; i < test_data2.size(); ++i) { 27 | std::cout << out_tl[i] << " " << test_data2[i] << " " << out_bl[i] << std::endl; 28 | } 29 | 30 | std::array test_data3 = {100,101,99,97,110,105,99}; 31 | std::array out_rsi; 32 | xtechnical_indicators::calc_ring_rsi(test_data2, out_rsi, 4); 33 | std::cout << "calc_ring_rsi:" << std::endl; 34 | for(size_t i = 0; i < test_data3.size(); ++i) { 35 | std::cout << out_rsi[i] << " " << test_data3[i] << std::endl; 36 | } 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /code_blocks/checking_statistics/checking_statistics.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 50 | 51 | -------------------------------------------------------------------------------- /code_blocks/checking_statistics/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_statistics.hpp" 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::cout << "Hello world!" << std::endl; 8 | std::array test_data = {3,8,10,17,24,27}; 9 | 10 | double median_absolute_deviation_value = xtechnical_statistics::calc_median_absolute_deviation(test_data); 11 | std::cout << "median absolute deviation value: " << median_absolute_deviation_value << std::endl; 12 | 13 | double median_value = xtechnical_statistics::calc_median(test_data); 14 | std::cout << "median value: " << median_value << std::endl; 15 | 16 | double harmonic_mean = xtechnical_statistics::calc_harmonic_mean(test_data); 17 | std::cout << "harmonic mean: " << harmonic_mean << std::endl; 18 | 19 | double mean_value = xtechnical_statistics::calc_mean_value(test_data); 20 | std::cout << "mean value: " << mean_value << std::endl; 21 | 22 | double skewness = xtechnical_statistics::calc_skewness(test_data); 23 | std::cout << "skewness: " << skewness << std::endl; 24 | 25 | double snr = xtechnical_statistics::calc_signal_to_noise_ratio(test_data); 26 | std::cout << "snr: " << snr << std::endl; 27 | 28 | 29 | std::array test_data2 = {1.1,1.1,1.1,1.1,1.1,1.1}; 30 | double geometric_mean = xtechnical_statistics::calc_geometric_mean(test_data2); 31 | std::cout << "geometric mean: " << geometric_mean << std::endl; 32 | 33 | std::array test_out; 34 | std::vector test_data3 = {1.1,1.1,1.1,1.1,1.1,1.1}; 35 | test_out[0] = xtechnical_statistics::calc_median(test_data3); 36 | std::cout << "median: " << test_out[0] << std::endl; 37 | 38 | 39 | std::vector test_data4 = {1,1,2,2,3,3,4,5,6,7}; 40 | double excess = xtechnical_statistics::calc_excess(test_data4); 41 | std::cout << "excess: " << excess << std::endl; 42 | 43 | std::vector test_data5 = {1,1,1,0,0,1}; 44 | double standard_error = xtechnical_statistics::calc_standard_error(test_data5); 45 | std::cout << "standard_error: " << standard_error << std::endl; 46 | 47 | double integral_laplace = xtechnical_statistics::calc_integral_laplace(0.01, 0.00001); 48 | std::cout << "integral_laplace: " << integral_laplace << std::endl; 49 | 50 | double integral_laplace2 = xtechnical_statistics::calc_integral_laplace(1.51, 0.01); 51 | std::cout << "integral_laplace2: " << integral_laplace2 << std::endl; 52 | 53 | double p_bet = xtechnical_statistics::calc_probability_winrate(0.6, 31, 44); 54 | std::cout << "p_bet: " << p_bet << std::endl; // получим ответ 93.6 55 | 56 | p_bet = xtechnical_statistics::calc_probability_winrate(0.56, 5700, 10000); 57 | std::cout << "p_bet: " << p_bet << std::endl; 58 | 59 | p_bet = xtechnical_statistics::calc_probability_winrate(0.54, 5700, 10000); 60 | std::cout << "p_bet: " << p_bet << std::endl; 61 | 62 | p_bet = xtechnical_statistics::calc_probability_winrate(0.57, 1, 1); 63 | std::cout << "p_bet (1): " << p_bet << std::endl; 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /code_blocks/cmp_min_max_witch_streaming_min_max/cmp_min_max_witch_streaming_min_max.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 44 | 45 | -------------------------------------------------------------------------------- /code_blocks/cmp_min_max_witch_streaming_min_max/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "xtechnical_indicators.hpp" 5 | #include "../../include/xtechnical_streaming_min_max.hpp" 6 | 7 | using namespace std; 8 | 9 | int main() { 10 | cout << "Hello world!" << endl; 11 | 12 | std::vector test_data; 13 | for(size_t i = 0; i < 100; ++i) { 14 | test_data.push_back(i); 15 | } 16 | for(size_t i = 0; i < 30; ++i) { 17 | test_data.push_back(100); 18 | } 19 | for(int i = 100; i >= 0; --i) { 20 | test_data.push_back(i); 21 | } 22 | for(size_t i = 0; i < 30; ++i) { 23 | test_data.push_back(0); 24 | } 25 | 26 | xtechnical_indicators::MinMax min_max(30, 0); 27 | xtechnical_indicators::FastMinMax fast_min_max(30, 0); 28 | xtechnical::StreamingMaximumMinimumFilter streaming_min_max(30); 29 | 30 | std::cout << "-1-" << std::endl; 31 | for(size_t n = 0; n < 1000; ++n) 32 | for(size_t i = 0; i < test_data.size(); ++i) { 33 | min_max.update(test_data[i]); 34 | streaming_min_max.update(test_data[i]); 35 | fast_min_max.update(test_data[i]); 36 | //std::cout << "in " << test_data[i] << " min " << min_max.get_min() << " smin " << streaming_min_max.get_min() << std::endl; 37 | if (!std::isnan(min_max.get_min()) && !std::isnan(streaming_min_max.get_min()) && min_max.get_min() != streaming_min_max.get_min()) { 38 | std::cout << "error! index " << i << " in " << test_data[i] << " min " << min_max.get_min() << " s min " << streaming_min_max.get_min() << std::endl; 39 | return 0; 40 | } 41 | if (!std::isnan(min_max.get_max()) && !std::isnan(streaming_min_max.get_max()) && min_max.get_max() != streaming_min_max.get_max()) { 42 | std::cout << "error! index " << i << " in " << test_data[i] << " max " << min_max.get_min() << " s max " << streaming_min_max.get_max() << std::endl; 43 | return 0; 44 | } 45 | if (!std::isnan(min_max.get_min()) && !std::isnan(fast_min_max.get_min()) && min_max.get_min() != fast_min_max.get_min()) { 46 | std::cout << "error! index " << i << " in " << test_data[i] << " min " << min_max.get_min() << " s min " << fast_min_max.get_min() << std::endl; 47 | return 0; 48 | } 49 | } 50 | std::cout << "ok" << std::endl; 51 | 52 | { 53 | xtechnical_indicators::MinMax min_max(30, 2); 54 | xtechnical_indicators::FastMinMax fast_min_max(30, 2); 55 | std::cout << "-2-" << std::endl; 56 | for(size_t n = 0; n < 1000; ++n) 57 | for(size_t i = 0; i < test_data.size(); ++i) { 58 | min_max.update(test_data[i]); 59 | fast_min_max.update(test_data[i]); 60 | if (!std::isnan(min_max.get_min()) && !std::isnan(fast_min_max.get_min()) && min_max.get_min() != fast_min_max.get_min()) { 61 | std::cout << "error! index " << i << " in " << test_data[i] << " min " << min_max.get_min() << " s min " << fast_min_max.get_min() << std::endl; 62 | return 0; 63 | } 64 | } 65 | std::cout << "ok" << std::endl; 66 | } 67 | 68 | { 69 | xtechnical_indicators::MinMax min_max(60, 0); 70 | auto begin = std::chrono::steady_clock::now(); 71 | for(size_t n = 0; n < 100000; ++n) 72 | for(size_t i = 0; i < test_data.size(); ++i) { 73 | min_max.update(test_data[i]); 74 | } 75 | auto end = std::chrono::steady_clock::now(); 76 | auto elapsed_ms = std::chrono::duration_cast(end - begin); 77 | std::cout << "min max time: " << elapsed_ms.count() << " ms\n"; 78 | } 79 | { 80 | xtechnical::StreamingMaximumMinimumFilter streaming_min_max(60); 81 | auto begin = std::chrono::steady_clock::now(); 82 | for(size_t n = 0; n < 100000; ++n) 83 | for(size_t i = 0; i < test_data.size(); ++i) { 84 | streaming_min_max.update(test_data[i]); 85 | } 86 | auto end = std::chrono::steady_clock::now(); 87 | auto elapsed_ms = std::chrono::duration_cast(end - begin); 88 | std::cout << "streaming min max time: " << elapsed_ms.count() << " ms\n"; 89 | } 90 | { 91 | xtechnical_indicators::FastMinMax min_max(60, 0); 92 | auto begin = std::chrono::steady_clock::now(); 93 | for(size_t n = 0; n < 100000; ++n) 94 | for(size_t i = 0; i < test_data.size(); ++i) { 95 | streaming_min_max.update(test_data[i]); 96 | } 97 | auto end = std::chrono::steady_clock::now(); 98 | auto elapsed_ms = std::chrono::duration_cast(end - begin); 99 | std::cout << "fast min max time: " << elapsed_ms.count() << " ms\n"; 100 | } 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /code_blocks/test/atr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) { 7 | std::cout << "Hello world!" << std::endl; 8 | std::array test_data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; 9 | 10 | const size_t period = 2; 11 | xtechnical::ATR> atr(period); 12 | 13 | for(size_t i = 0; i < test_data.size(); ++i) { 14 | atr.update(test_data[i]); 15 | std::cout 16 | << "update " << test_data[i] 17 | << " get " << atr.get() 18 | << std::endl; 19 | } 20 | 21 | /* проверяем методы тест */ 22 | std::cout << "test(20)" << std::endl; 23 | atr.test(20); 24 | std::cout << "get " << atr.get() << std::endl; 25 | 26 | 27 | std::cout << "test(21)" << std::endl; 28 | atr.test(21); 29 | std::cout << "get " << atr.get() << std::endl; 30 | 31 | std::cout << "test(10)" << std::endl; 32 | atr.test(10); 33 | std::cout << "get " << atr.get() << std::endl; 34 | 35 | for(size_t i = test_data.size() - 1; i > 0; --i) { 36 | atr.update(test_data[i]); 37 | std::cout 38 | << "update " << test_data[i] 39 | << " get " << atr.get() 40 | << std::endl; 41 | } 42 | 43 | for(size_t i = 0; i < test_data.size(); ++i) { 44 | atr.update(test_data[i]); 45 | std::cout 46 | << "update " << test_data[i] 47 | << " get " << atr.get() 48 | << std::endl; 49 | } 50 | 51 | std::system("pause"); 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /code_blocks/test/body_filter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) { 7 | std::cout << "Hello world!" << std::endl; 8 | 9 | { 10 | xtechnical::BodyFilter> body_filter(1); 11 | body_filter.update(2,5,1,3); 12 | std::cout << body_filter.get() << std::endl; 13 | } 14 | { 15 | xtechnical::BodyFilter> body_filter(3); 16 | body_filter.update(2,5,1,3); 17 | body_filter.update(3,5,1,3); 18 | body_filter.update(2,4,2,4); 19 | body_filter.update(2,4,2,4); 20 | std::cout << body_filter.get() << std::endl; 21 | } 22 | std::system("pause"); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /code_blocks/test/cci.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) { 7 | std::cout << "Hello world!" << std::endl; 8 | std::array test_data = {0,1,2,9,4,5,8,7,8,9,10,11,12,13,14,15,16,17,18,19}; 9 | 10 | const size_t period = 4; 11 | xtechnical::CCI> cci(period); 12 | 13 | for(size_t i = 0; i < test_data.size(); ++i) { 14 | cci.update(test_data[i]); 15 | std::cout 16 | << "update " << test_data[i] 17 | << " get " << cci.get() 18 | << std::endl; 19 | } 20 | 21 | /* проверяем методы тест */ 22 | std::cout << "test(20)" << std::endl; 23 | cci.test(20); 24 | std::cout << "get " << cci.get() << std::endl; 25 | 26 | 27 | std::cout << "test(21)" << std::endl; 28 | cci.test(21); 29 | std::cout << "get " << cci.get() << std::endl; 30 | 31 | std::cout << "test(10)" << std::endl; 32 | cci.test(10); 33 | std::cout << "get " << cci.get() << std::endl; 34 | 35 | for(size_t i = test_data.size() - 1; i > 0; --i) { 36 | cci.update(test_data[i]); 37 | std::cout 38 | << "update " << test_data[i] 39 | << " get " << cci.get() 40 | << std::endl; 41 | } 42 | 43 | for(size_t i = 0; i < test_data.size(); ++i) { 44 | cci.update(test_data[i]); 45 | std::cout 46 | << "update " << test_data[i] 47 | << " get " << cci.get() 48 | << std::endl; 49 | } 50 | 51 | std::system("pause"); 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /code_blocks/test/cluster_shaper.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | #include "easy_plot.hpp" 4 | #include 5 | #include 6 | #include 7 | 8 | void print_map(const std::map &distribution) { 9 | for (auto it = distribution.begin(); it != distribution.end(); ++it) { 10 | std::cout << it->first << " " << it->second << std::endl; 11 | } 12 | } 13 | 14 | int main(int argc, char* argv[]) { 15 | ep::init(&argc, argv); 16 | std::cout << "Hello world!" << std::endl; 17 | // 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 18 | xtechnical::ClusterShaper cluster_shaper(60, 0.0001d); 19 | cluster_shaper.on_close_bar = [&](const xtechnical::ClusterShaper::Cluster &cluster) { 20 | auto normalized_cluster = cluster.get_normalized_array(); 21 | auto no_normalized_cluster = cluster.get_array(); 22 | 23 | if (false) { 24 | std::copy(normalized_cluster.begin(), normalized_cluster.end(), std::ostream_iterator(std::cout, " ")); 25 | std::cout << std::endl; 26 | std::copy(no_normalized_cluster.begin(), no_normalized_cluster.end(), std::ostream_iterator(std::cout, " ")); 27 | std::cout << std::endl; 28 | print_map(cluster.distribution); 29 | } 30 | 31 | std::cout << "o: " << cluster.open << " c: " << cluster.close << " m: " << cluster.get_center_mass() << std::endl; 32 | const double center = cluster.get_center_mass_norm(); 33 | std::cout << "center: " << center << std::endl; 34 | if (center < 0.38) { 35 | std::copy(no_normalized_cluster.begin(), no_normalized_cluster.end(), std::ostream_iterator(std::cout, " ")); 36 | std::cout << std::endl; 37 | ep::WindowSpec wstyle; 38 | ep::plot("center", wstyle, (int)1, 39 | normalized_cluster, ep::LineSpec(0,1,0)); 40 | std::system("pause"); 41 | } 42 | 43 | //auto triangular_distribution = xtechnical::ClusterShaper::get_triangular_distribution(normalized_cluster.size(), normalized_cluster.size()/2); 44 | 45 | auto triangular_distribution = xtechnical::ClusterShaper::get_triangular_distribution(normalized_cluster.size(), normalized_cluster.size() * 0.0); 46 | double similarity = xtechnical::ClusterShaper::get_cosine_similarity(normalized_cluster, triangular_distribution); 47 | double dist = xtechnical::ClusterShaper::get_euclidean_distance(normalized_cluster, triangular_distribution); 48 | std::cout << "similarity: " << similarity << std::endl; 49 | if (similarity > 0.55) { 50 | std::copy(no_normalized_cluster.begin(), no_normalized_cluster.end(), std::ostream_iterator(std::cout, " ")); 51 | std::cout << std::endl; 52 | ep::WindowSpec wstyle; 53 | ep::plot("similarity", wstyle, (int)2, 54 | normalized_cluster, ep::LineSpec(0,1,0), 55 | triangular_distribution, ep::LineSpec(0,0,1)); 56 | std::system("pause"); 57 | } 58 | std::cout << "dist: " << dist << std::endl; 59 | if (dist < 0.02) { 60 | std::copy(no_normalized_cluster.begin(), no_normalized_cluster.end(), std::ostream_iterator(std::cout, " ")); 61 | std::cout << std::endl; 62 | ep::WindowSpec wstyle; 63 | ep::plot("euclidean", wstyle, (int)2, 64 | normalized_cluster, ep::LineSpec(0,1,0), 65 | triangular_distribution, ep::LineSpec(0,0,1)); 66 | std::system("pause"); 67 | } 68 | 69 | }; 70 | cluster_shaper.on_unformed_bar = [&](const xtechnical::ClusterShaper::Cluster &cluster) { 71 | auto normalized_cluster = cluster.get_normalized_array(); 72 | //std::copy(normalized_cluster.begin(), normalized_cluster.end(), std::ostream_iterator(std::cout, " ")); 73 | }; 74 | 75 | std::mt19937 gen(time(0)); 76 | //std::normal_distribution<> urd(-0.5, 1.0); 77 | //std::lognormal_distribution<> urd(-0.5, 1.0); 78 | 79 | std::uniform_real_distribution<> urd(-0.5, 1.0); 80 | 81 | const std::size_t price_size = 5000000; 82 | std::vector prices(price_size); 83 | double last_price = 10 + urd(gen); 84 | std::generate(prices.begin(), prices.begin() + price_size, [&]() -> double { 85 | last_price = last_price + 0.001d* urd(gen); 86 | return last_price; 87 | }); 88 | 89 | for (size_t i = 0; i < price_size; ++i) { 90 | //std::cout << "price " << prices[i] << " " << i << std::endl; 91 | cluster_shaper.update(prices[i], i/2); 92 | } 93 | 94 | { 95 | auto triangular_distribution = xtechnical::ClusterShaper::get_triangular_distribution(10, 5); 96 | std::copy(triangular_distribution.begin(), triangular_distribution.end(), std::ostream_iterator(std::cout, " ")); 97 | std::cout << std::endl; 98 | std::system("pause"); 99 | } 100 | { 101 | auto triangular_distribution = xtechnical::ClusterShaper::get_triangular_distribution(3, 1); 102 | std::copy(triangular_distribution.begin(), triangular_distribution.end(), std::ostream_iterator(std::cout, " ")); 103 | std::cout << std::endl; 104 | std::system("pause"); 105 | } 106 | { 107 | auto triangular_distribution = xtechnical::ClusterShaper::get_triangular_distribution(5, 0); 108 | std::copy(triangular_distribution.begin(), triangular_distribution.end(), std::ostream_iterator(std::cout, " ")); 109 | std::cout << std::endl; 110 | std::system("pause"); 111 | } 112 | { 113 | auto triangular_distribution = xtechnical::ClusterShaper::get_triangular_distribution(5, 4); 114 | std::copy(triangular_distribution.begin(), triangular_distribution.end(), std::ostream_iterator(std::cout, " ")); 115 | std::cout << std::endl; 116 | std::system("pause"); 117 | } 118 | 119 | std::system("pause"); 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /code_blocks/test/fractals.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) { 7 | std::cout << "Hello world!" << std::endl; 8 | std::array test_data = {0,12,2,91,42,54,84,74,88,98,101,111,122,132,143,153,126,117,118,119}; 9 | 10 | xtechnical::Fractals fractals; 11 | 12 | for(size_t i = 0; i < test_data.size(); ++i) { 13 | fractals.update(test_data[i], test_data[i] - 1); 14 | std::cout 15 | << "update " << test_data[i] 16 | << " up " << fractals.get_up() 17 | << " dn " << fractals.get_dn() 18 | << std::endl; 19 | } 20 | 21 | /* проверяем методы тест */ 22 | std::cout << "test(20, 19)" << std::endl; 23 | fractals.test(20, 19); 24 | std::cout << "up " << fractals.get_up() << " dn " << fractals.get_dn() << std::endl; 25 | 26 | std::cout << "test(21, 18)" << std::endl; 27 | fractals.test(21, 18); 28 | std::cout << "up " << fractals.get_up() << " dn " << fractals.get_dn() << std::endl; 29 | 30 | std::cout << "test(10, 8)" << std::endl; 31 | fractals.test(10, 8); 32 | std::cout << "up " << fractals.get_up() << " dn " << fractals.get_dn() << std::endl; 33 | 34 | for(size_t i = test_data.size() - 1; i > 0; --i) { 35 | fractals.update(test_data[i], test_data[i] - 2); 36 | std::cout 37 | << "update " << test_data[i] 38 | << " up " << fractals.get_up() 39 | << " dn " << fractals.get_dn() 40 | << std::endl; 41 | } 42 | 43 | for(size_t i = 0; i < test_data.size(); ++i) { 44 | fractals.update(test_data[i], test_data[i] - 1); 45 | std::cout 46 | << "update " << test_data[i] 47 | << " up " << fractals.get_up() 48 | << " dn " << fractals.get_dn() 49 | << std::endl; 50 | } 51 | 52 | std::system("pause"); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /code_blocks/test/period_stats.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) { 7 | std::cout << "Hello world!" << std::endl; 8 | 9 | xtechnical::PeriodStatsV1 period_stats(60); 10 | 11 | period_stats.add(10, 10000); 12 | std::cout << "e " << period_stats.empty() << " mv " << period_stats.get_max_value() << std::endl; 13 | period_stats.add(10, 10001); 14 | std::cout << "e " << period_stats.empty() << " mv " << period_stats.get_max_value() << std::endl; 15 | period_stats.add(10, 10002); 16 | std::cout << "e " << period_stats.empty() << " mv " << period_stats.get_max_value() << std::endl; 17 | period_stats.add(12, 10010); 18 | std::cout << "e " << period_stats.empty() << " mv " << period_stats.get_max_value() << std::endl; 19 | period_stats.add(15, 10020); 20 | std::cout << "e " << period_stats.empty() << " mv " << period_stats.get_max_value() << std::endl; 21 | period_stats.add(30, 10030); 22 | std::cout << "e " << period_stats.empty() << " mv " << period_stats.get_max_value() << std::endl; 23 | period_stats.add(10, 10050); 24 | std::cout << "e " << period_stats.empty() << " mv " << period_stats.get_max_value() << std::endl; 25 | period_stats.add(15, 10059); 26 | std::cout << "e " << period_stats.empty() << " mv " << period_stats.get_max_value() << std::endl; 27 | period_stats.add(12, 10089); 28 | std::cout << "e " << period_stats.empty() << " mv " << period_stats.get_max_value() << std::endl; 29 | period_stats.add(12, 10090); 30 | std::cout << "e " << period_stats.empty() << " mv " << period_stats.get_max_value() << std::endl; 31 | period_stats.add(11, 10060); 32 | std::cout << "e " << period_stats.empty() << " mv " << period_stats.get_max_value() << std::endl; 33 | period_stats.add(11, 10119); 34 | std::cout << "e " << period_stats.empty() << " mv " << period_stats.get_max_value() << std::endl; 35 | period_stats.add(5, 10120); 36 | std::cout << "e " << period_stats.empty() << " mv " << period_stats.get_max_value() << std::endl; 37 | period_stats.add(11, 10121); 38 | std::cout << "e " << period_stats.empty() << " mv " << period_stats.get_max_value() << std::endl; 39 | std::cout << "w " << period_stats.get_max_weight() << " c " << period_stats.get_center_mass() << std::endl; 40 | 41 | std::system("pause"); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /code_blocks/test/ssa.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "xtechnical_indicators.hpp" 8 | #include 9 | 10 | int main(int argc, char* argv[]) { 11 | std::cout << "Hello world!" << std::endl; 12 | Eigen::VectorXf x(11); 13 | x << 1, 2, 3, 2, 1, 2, 3, 2, 1, 2, 3; 14 | 15 | int M = 6; // number of ticks to forecast after the end of the time series 16 | int K = 5; // window length 17 | //int r = 0; // rank of the Hankel matrix 18 | 19 | std::cout << "res:\n" << xtechnical::SSA::calc_ssa(x, M, K, 0, xtechnical::SSA::SSAMode::OriginalSeriesAddition) << std::endl; 20 | 21 | xtechnical::SSA SSA(11); 22 | 23 | for (size_t i = 0; i < x.size(); ++i) { 24 | SSA.update(x(i), xtechnical::common::PriceType::Close); 25 | } 26 | 27 | SSA.calc(M, K, 2, 1, xtechnical::SSA::MetricType::RSquared, true, xtechnical::SSA::SSAMode::RestoredSeriesAddition); 28 | 29 | std::cout << "get_last_forecast:\n" << SSA.get_last_forecast() << std::endl; 30 | 31 | std::cout << "get_forecast:\n"; 32 | for (auto &item : SSA.get_forecast()) { 33 | std::cout << item << " "; 34 | 35 | } 36 | std::cout << std::endl; 37 | 38 | std::cout << "get_reconstructed:\n"; 39 | for (auto &item : SSA.get_reconstructed()) { 40 | std::cout << item << " "; 41 | 42 | } 43 | std::cout << std::endl; 44 | 45 | std::cout << "get_metric:\n" << SSA.get_metric() << std::endl; 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /code_blocks/test/super_trend.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) { 7 | std::cout << "Hello world!" << std::endl; 8 | std::array test_data = {0,1,2,9,4,5,8,7,8,9,10,11,12,13,14,15,16,17,18,19}; 9 | 10 | xtechnical::SuperTrend> super_trend(50,5); 11 | 12 | for(size_t n = 0; n < 10; ++n) 13 | for(size_t i = 0; i < test_data.size(); ++i) { 14 | super_trend.update(test_data[i]); 15 | std::cout 16 | << "update " << test_data[i] 17 | << " get " << super_trend.get() 18 | << std::endl; 19 | } 20 | 21 | /* проверяем методы тест */ 22 | std::cout << "test(20)" << std::endl; 23 | super_trend.test(20); 24 | std::cout << "get " << super_trend.get() << std::endl; 25 | 26 | 27 | std::cout << "test(21)" << std::endl; 28 | super_trend.test(21); 29 | std::cout << "get " << super_trend.get() << std::endl; 30 | 31 | std::cout << "test(10)" << std::endl; 32 | super_trend.test(10); 33 | std::cout << "get " << super_trend.get() << std::endl; 34 | 35 | for(size_t i = test_data.size() - 1; i > 0; --i) { 36 | super_trend.update(test_data[i]); 37 | std::cout 38 | << "update " << test_data[i] 39 | << " get " << super_trend.get() 40 | << std::endl; 41 | } 42 | 43 | for(size_t i = 0; i < test_data.size(); ++i) { 44 | super_trend.update(test_data[i]); 45 | std::cout 46 | << "update " << test_data[i] 47 | << " get " << super_trend.get() 48 | << std::endl; 49 | } 50 | 51 | std::system("pause"); 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /code_blocks/test/trend_direction_force_index.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xtechnical_indicators.hpp" 3 | #include 4 | 5 | int main() { 6 | std::cout << "Hello world!" << std::endl; 7 | std::array test_data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; 8 | 9 | const size_t period = 2; 10 | xtechnical::TrendDirectionForceIndex> trend(period); 11 | 12 | for(size_t i = 0; i < test_data.size(); ++i) { 13 | trend.update(test_data[i]); 14 | std::cout 15 | << "update " << test_data[i] 16 | << " get " << trend.get() 17 | << std::endl; 18 | } 19 | 20 | /* проверяем методы тест */ 21 | std::cout << "test(20)" << std::endl; 22 | trend.test(20); 23 | std::cout << "get " << trend.get() << std::endl; 24 | 25 | 26 | std::cout << "test(21)" << std::endl; 27 | trend.test(21); 28 | std::cout << "get " << trend.get() << std::endl; 29 | 30 | std::cout << "test(10)" << std::endl; 31 | trend.test(10); 32 | std::cout << "get " << trend.get() << std::endl; 33 | 34 | for(size_t i = test_data.size() - 1; i > 0; --i) { 35 | trend.update(test_data[i]); 36 | std::cout 37 | << "update " << test_data[i] 38 | << " get " << trend.get() 39 | << std::endl; 40 | } 41 | 42 | for(size_t i = 0; i < test_data.size(); ++i) { 43 | trend.update(test_data[i]); 44 | std::cout 45 | << "update " << test_data[i] 46 | << " get " << trend.get() 47 | << std::endl; 48 | } 49 | 50 | std::system("pause"); 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /doc/example_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewYaroslav/xtechnical_analysis/9e24d06f904a76a6d3e2e5403a9f7910d65e9817/doc/example_0.png -------------------------------------------------------------------------------- /include/backtest/xtechnical_winrate_statistics.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_WINRATE_STATISTICS_HPP_INCLUDED 2 | #define XTECHNICAL_WINRATE_STATISTICS_HPP_INCLUDED 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace xtechnical { 10 | 11 | /** \brief Статистика винрейта 12 | */ 13 | template 14 | class WinrateStats { 15 | public: 16 | 17 | /** \brief Класс тика 18 | */ 19 | class Tick { 20 | public: 21 | double bid = 0; /**< Цена bid */ 22 | double ask = 0; /**< Цена ask */ 23 | uint64_t timestamp = 0; /**< Метка времени */ 24 | 25 | Tick() {}; 26 | 27 | Tick(const double b, const double a, const uint64_t t) : 28 | bid(b), ask(a), timestamp(t) { 29 | } 30 | }; 31 | 32 | /** \brief Класс данных ставок 33 | */ 34 | class Bet { 35 | public: 36 | std::string broker; 37 | std::string symbol; 38 | int direction = 0; 39 | uint64_t t1 = 0; 40 | uint64_t t2 = 0; 41 | uint64_t last_t = 0; 42 | double open = 0; 43 | double close = 0; 44 | bool init_open = false; 45 | bool init_close = false; 46 | T user_data; 47 | }; 48 | 49 | private: 50 | std::deque bets; 51 | std::map> ticks; 52 | 53 | public: 54 | 55 | /** \brief Класс конфигурации 56 | */ 57 | class Config { 58 | public: 59 | uint64_t expiration = 60000; /**< Экспирация */ 60 | uint64_t delay = 150; /**< Задержка */ 61 | uint64_t period = 0; /**< Период в миллисекундах */ 62 | uint64_t between_ticks = 20000; /**< Задержка между тиками */ 63 | std::function on_error = nullptr; 64 | std::function on_win = nullptr; 65 | std::function on_loss = nullptr; 66 | } config; 67 | 68 | uint64_t wins = 0; /**< Число удачных сделок */ 69 | uint64_t losses = 0; /**< Число убыточных сделок */ 70 | 71 | WinrateStats() {}; 72 | 73 | /** \brief Сделать ставку 74 | * \param broker Имя брокера 75 | * \param symbol Символ 76 | * \param timestamp Метка времени 77 | * \param direction Направление, 1 - BUY, -1 - SELL 78 | * \param callback Функция обратного вызова для передачи структуры ставки 79 | */ 80 | void place_bet( 81 | const std::string &broker, 82 | const std::string &symbol, 83 | const uint64_t timestamp, 84 | const int direction, 85 | std::function callback = nullptr) noexcept { 86 | Bet bet; 87 | bet.broker = broker; 88 | bet.symbol = symbol; 89 | bet.direction = direction; 90 | 91 | const uint64_t t1 = timestamp + config.delay; 92 | bet.t1 = config.period == 0 ? t1 : (t1 - (t1 % config.period) + config.period); 93 | bet.t2 = bet.t1 + config.expiration; 94 | // ищем котировку 95 | auto it_broker = ticks.find(broker); 96 | if (it_broker == ticks.end()) return; 97 | auto it_symbol = it_broker->second.find(symbol); 98 | if (it_symbol == it_broker->second.end()) return; 99 | 100 | bet.open = (it_symbol->second.ask + it_symbol->second.bid) / 2.0d; 101 | if (callback != nullptr) callback(bet); 102 | bets.push_back(bet); 103 | } 104 | 105 | /** \brief Обновить состояние сделок 106 | * \param broker Имя брокера 107 | * \param symbol Символ 108 | * \param tick Данные тика 109 | */ 110 | void update( 111 | const std::string &broker, 112 | const std::string &symbol, 113 | const Tick &tick) noexcept { 114 | ticks[broker][symbol] = tick; 115 | if (bets.empty()) return; 116 | size_t index = 0; 117 | while (index < bets.size()) { 118 | if (bets[index].broker != broker) { 119 | ++index; 120 | continue; 121 | } 122 | if (bets[index].symbol != symbol) { 123 | ++index; 124 | continue; 125 | } 126 | 127 | if (!bets[index].init_open && bets[index].t1 >= tick.timestamp) { 128 | bets[index].open = (tick.ask + tick.bid) / 2.0d; 129 | } 130 | if (!bets[index].init_open && bets[index].t1 <= tick.timestamp) { 131 | bets[index].init_open = true; 132 | } 133 | 134 | if (!bets[index].init_close && bets[index].t2 >= tick.timestamp) { 135 | bets[index].close = (tick.ask + tick.bid) / 2.0d; 136 | bets[index].last_t = tick.timestamp; 137 | } 138 | if (!bets[index].init_close && bets[index].t2 <= tick.timestamp) { 139 | bets[index].init_close = true; 140 | if ((bets[index].t2 - bets[index].last_t) > config.between_ticks) { 141 | // ошибка сделки, слишком долго не было тика 142 | if (config.on_error != nullptr) config.on_error(bets[index]); 143 | bets.erase(bets.begin() + index); 144 | continue; 145 | } 146 | } 147 | 148 | if (!bets[index].init_close || 149 | !bets[index].init_open) { 150 | ++index; 151 | continue; 152 | } 153 | 154 | if (bets[index].direction == 1) { 155 | if (bets[index].close > bets[index].open) { 156 | ++wins; 157 | if (config.on_win != nullptr) config.on_win(bets[index]); 158 | } else { 159 | ++losses; 160 | if (config.on_loss != nullptr) config.on_loss(bets[index]); 161 | } 162 | bets.erase(bets.begin() + index); 163 | continue; 164 | } else 165 | if (bets[index].direction == -1) { 166 | if (bets[index].close < bets[index].open) { 167 | ++wins; 168 | if (config.on_win != nullptr) config.on_win(bets[index]); 169 | } else { 170 | ++losses; 171 | if (config.on_loss != nullptr) config.on_loss(bets[index]); 172 | } 173 | bets.erase(bets.begin() + index); 174 | continue; 175 | } 176 | ++index; 177 | } // while 178 | } 179 | 180 | inline void update( 181 | const std::string &broker, 182 | const std::string &symbol, 183 | const double bid, 184 | const double ask, 185 | const uint64_t timestamp) noexcept { 186 | update(broker, symbol, Tick(bid, ask, timestamp)); 187 | } 188 | 189 | /** \brief Получить винрейт 190 | * \return Винрейт 191 | */ 192 | inline double get_winrate() noexcept { 193 | const double deals = wins + losses; 194 | const double winrate = deals == 0 ? 0 : (double)wins / (double)deals; 195 | return winrate; 196 | } 197 | 198 | /** \brief Получить число сделок 199 | * \return Число сделок 200 | */ 201 | inline uint64_t get_deals() noexcept { 202 | const uint64_t deals = wins + losses; 203 | return deals; 204 | } 205 | }; 206 | }; 207 | 208 | #endif // XTECHNICAL_WINRATE_STATISTICS_HPP_INCLUDED 209 | -------------------------------------------------------------------------------- /include/indicators/xtechnical_atr.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_ATR_HPP_INCLUDED 2 | #define XTECHNICAL_ATR_HPP_INCLUDED 3 | 4 | #include "../xtechnical_common.hpp" 5 | #include "xtechnical_true_range.hpp" 6 | 7 | namespace xtechnical { 8 | 9 | /** \brief Истинный диапазон (True Range) 10 | */ 11 | template 12 | class ATR { 13 | private: 14 | MA_TYPE ma; 15 | TrueRange tr; 16 | T output_value = std::numeric_limits::quiet_NaN(); 17 | public: 18 | ATR() {}; 19 | 20 | ATR(const size_t period) : ma(period) {} 21 | 22 | inline int update(const T high, const T low, const T close) noexcept { 23 | tr.update(high, low, close); 24 | if (std::isnan(tr.get())) return common::NO_INIT; 25 | ma.update(tr.get()); 26 | if (std::isnan(ma.get())) return common::NO_INIT; 27 | output_value = ma.get(); 28 | return common::OK; 29 | } 30 | 31 | inline int update(const T high, const T low, const T close, T &out) noexcept { 32 | const int err = update(high, low, close); 33 | out = output_value; 34 | return err; 35 | } 36 | 37 | /** \brief Обновить состояние индикатора 38 | * \param in Сигнал на входе 39 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 40 | */ 41 | inline int update(const T in) noexcept { 42 | tr.update(in); 43 | if (std::isnan(tr.get())) return common::NO_INIT; 44 | ma.update(tr.get()); 45 | if (std::isnan(ma.get())) return common::NO_INIT; 46 | output_value = ma.get(); 47 | return common::OK; 48 | } 49 | 50 | /** \brief Обновить состояние индикатора 51 | * \param in Сигнал на входе 52 | * \param out Сигнал на выходе 53 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 54 | */ 55 | inline int update(const T in, T &out) noexcept { 56 | const int err = update(in); 57 | out = output_value; 58 | return err; 59 | } 60 | 61 | inline int test(const T high, const T low, const T close) noexcept { 62 | tr.test(high, low, close); 63 | if (std::isnan(tr.get())) return common::NO_INIT; 64 | ma.test(tr.get()); 65 | if (std::isnan(ma.get())) return common::NO_INIT; 66 | output_value = ma.get(); 67 | return common::OK; 68 | } 69 | 70 | inline int test(const T high, const T low, const T close, T &out) noexcept { 71 | const int err = test(high, low, close); 72 | out = output_value; 73 | return err; 74 | } 75 | 76 | /** \brief Протестировать индикатор 77 | * 78 | * Данная функция отличается от update тем, 79 | * что не влияет на внутреннее состояние индикатора 80 | * \param in сигнал на входе 81 | * \return вернет 0 в случае успеха, иначе см. ErrorType 82 | */ 83 | inline int test(const T in) noexcept { 84 | tr.test(in); 85 | if (std::isnan(tr.get())) return common::NO_INIT; 86 | ma.test(tr.get()); 87 | if (std::isnan(ma.get())) return common::NO_INIT; 88 | output_value = ma.get(); 89 | return common::OK; 90 | } 91 | 92 | /** \brief Протестировать индикатор 93 | * 94 | * Данная функция отличается от update тем, 95 | * что не влияет на внутреннее состояние индикатора 96 | * \param in Сигнал на входе 97 | * \param out Сигнал на выходе 98 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 99 | */ 100 | inline int test(const T in, T &out) noexcept { 101 | const int err = test(in); 102 | out = output_value; 103 | return err; 104 | } 105 | 106 | /** \brief Получить значение индикатора 107 | * \return Значение индикатора 108 | */ 109 | inline T get() const noexcept { 110 | return output_value; 111 | } 112 | 113 | /** \brief Очистить данные индикатора 114 | */ 115 | inline void clear() noexcept { 116 | output_value = std::numeric_limits::quiet_NaN(); 117 | tr.clear(); 118 | ma.clear(); 119 | } 120 | }; // ATR 121 | 122 | }; // xtechnical 123 | 124 | #endif // XTECHNICAL_ATR_HPP_INCLUDED 125 | -------------------------------------------------------------------------------- /include/indicators/xtechnical_awesome_oscillator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_AWESOME_OSCILLATOR_HPP_INCLUDED 2 | #define XTECHNICAL_AWESOME_OSCILLATOR_HPP_INCLUDED 3 | 4 | #include "../xtechnical_common.hpp" 5 | #include "xtechnical_sma.hpp" 6 | 7 | namespace xtechnical { 8 | using namespace xtechnical_common; 9 | 10 | /** \brief Awesome Oscillator 11 | */ 12 | template > 13 | class AwesomeOscillator { 14 | private: 15 | MA_TYPE fast; 16 | MA_TYPE slow; 17 | T output_value = std::numeric_limits::quiet_NaN(); 18 | public: 19 | 20 | AwesomeOscillator() {} 21 | 22 | /** \brief Конструктор Awesome Oscillator 23 | * \param fast_period Период медленной МА 24 | * \param slow_period Период быстрой МА 25 | */ 26 | AwesomeOscillator(const size_t fast_period, const size_t slow_period) : 27 | fast(fast_period), slow(slow_period) { 28 | } 29 | 30 | /** \brief Обновить состояние индикатора 31 | * \param price Цена бара 32 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 33 | */ 34 | inline int update(const T price) noexcept { 35 | fast.update(price); 36 | slow.update(price); 37 | if (std::isnan(fast.get()) || 38 | std::isnan(slow.get())) return INDICATOR_NOT_READY_TO_WORK; 39 | output_value = fast.get() - slow.get(); 40 | } 41 | 42 | /** \brief Обновить состояние индикатора 43 | * \param high Наивысшая цена бара 44 | * \param low Наинизшая цена бара 45 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 46 | */ 47 | int update(const T high, const T low) noexcept { 48 | const T price = (high + low) / 2.0d; 49 | return update(price); 50 | } 51 | 52 | /** \brief Обновить состояние индикатора 53 | * \param high Наивысшая цена бара 54 | * \param low Наинизшая цена бара 55 | * \param out Сигнал на выходе 56 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 57 | */ 58 | inline int update(const T high, const T low, T &out) noexcept { 59 | const int err = update(high, low); 60 | out = output_value; 61 | return err; 62 | } 63 | 64 | /** \brief Обновить состояние индикатора 65 | * \param price Цена бара 66 | * \param out Сигнал на выходе 67 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 68 | */ 69 | inline int update(const T price, T &out) noexcept { 70 | const int err = update(price); 71 | out = output_value; 72 | return err; 73 | } 74 | 75 | /** \brief Протестировать индикатор 76 | * \param price Цена бара 77 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 78 | */ 79 | inline int test(const T price) noexcept { 80 | fast.test(price); 81 | slow.test(price); 82 | if (std::isnan(fast.get()) || 83 | std::isnan(slow.get())) return INDICATOR_NOT_READY_TO_WORK; 84 | output_value = fast.get() - slow.get(); 85 | } 86 | 87 | /** \brief Протестировать индикатор 88 | * \param high Наивысшая цена бара 89 | * \param low Наинизшая цена бара 90 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 91 | */ 92 | int test(const T high, const T low) noexcept { 93 | const T price = (high + low) / 2.0d; 94 | return test(price); 95 | } 96 | 97 | /** \brief Протестировать индикатор 98 | * \param high Наивысшая цена бара 99 | * \param low Наинизшая цена бара 100 | * \param out Сигнал на выходе 101 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 102 | */ 103 | inline int test(const T high, const T low, T &out) noexcept { 104 | const int err = test(high, low); 105 | out = output_value; 106 | return OK; 107 | } 108 | 109 | /** \brief Протестировать индикатор 110 | * \param price Цена бара 111 | * \param out Сигнал на выходе 112 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 113 | */ 114 | inline int test(const T price, T &out) noexcept { 115 | const int err = test(price); 116 | out = output_value; 117 | return err; 118 | } 119 | 120 | /** \brief Получить значение индикатора 121 | * \return Значение индикатора 122 | */ 123 | inline T get() const noexcept { 124 | return output_value; 125 | } 126 | 127 | /** \brief Очистить данные индикатора 128 | */ 129 | void clear() noexcept { 130 | output_value = std::numeric_limits::quiet_NaN(); 131 | fast.clear(); 132 | slow.clear(); 133 | } 134 | }; 135 | }; // xtechnical 136 | 137 | #endif // XTECHNICAL_AWESOME_OSCILLATOR_HPP_INCLUDED 138 | -------------------------------------------------------------------------------- /include/indicators/xtechnical_body_filter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_BODY_FILTER_HPP_INCLUDED 2 | #define XTECHNICAL_BODY_FILTER_HPP_INCLUDED 3 | 4 | #include "../xtechnical_common.hpp" 5 | 6 | namespace xtechnical { 7 | 8 | /** \brief Фильтр размера тела бара 9 | */ 10 | template 11 | class BodyFilter { 12 | private: 13 | MA_TYPE ma; 14 | T output_value = std::numeric_limits::quiet_NaN(); 15 | size_t period = 0; 16 | public: 17 | BodyFilter() {}; 18 | 19 | BodyFilter(const size_t p) : ma(p), period(p) {} 20 | 21 | inline int update(const T open, const T high, const T low, const T close) noexcept { 22 | const T body = std::abs(open - close); 23 | const T total = std::abs(high - low); 24 | const T body_per = total == 0 ? 1.0 : body / total; 25 | if (period <= 1) output_value = body_per; 26 | else { 27 | ma.update(body_per); 28 | if (std::isnan(ma.get())) return common::NO_INIT; 29 | output_value = ma.get(); 30 | } 31 | return common::OK; 32 | } 33 | 34 | inline int update(const T open, const T high, const T low, const T close, T &out) noexcept { 35 | const int err = update(high, low, close); 36 | out = output_value; 37 | return err; 38 | } 39 | 40 | inline int test(const T open, const T high, const T low, const T close) noexcept { 41 | const T body = std::abs(open - close); 42 | const T total = std::abs(high - low); 43 | const T body_per = total == 0 ? 1.0 : body / total; 44 | if (period <= 1) output_value = body_per; 45 | else { 46 | ma.test(body_per); 47 | if (std::isnan(ma.get())) return common::NO_INIT; 48 | output_value = ma.get(); 49 | } 50 | return common::OK; 51 | } 52 | 53 | inline int test(const T open, const T high, const T low, const T close, T &out) noexcept { 54 | const int err = test(high, low, close); 55 | out = output_value; 56 | return err; 57 | } 58 | 59 | /** \brief Получить значение индикатора 60 | * \return Значение индикатора 61 | */ 62 | inline T get() const noexcept { 63 | return output_value; 64 | } 65 | 66 | /** \brief Очистить данные индикатора 67 | */ 68 | inline void clear() noexcept { 69 | output_value = std::numeric_limits::quiet_NaN(); 70 | ma.clear(); 71 | } 72 | }; // BodyFilter 73 | 74 | }; // xtechnical 75 | 76 | #endif // XTECHNICAL_BODY_FILTER_HPP_INCLUDED 77 | -------------------------------------------------------------------------------- /include/indicators/xtechnical_cci.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_CCI_HPP_INCLUDED 2 | #define XTECHNICAL_CCI_HPP_INCLUDED 3 | 4 | #include "../xtechnical_common.hpp" 5 | #include "xtechnical_true_range.hpp" 6 | 7 | namespace xtechnical { 8 | 9 | /** \brief Индекс товарного канала 10 | */ 11 | template 12 | class CCI { 13 | private: 14 | MA_TYPE ma; 15 | xtechnical::circular_buffer buffer; 16 | T output_value = std::numeric_limits::quiet_NaN(); 17 | T coeff = 0.015; 18 | public: 19 | 20 | CCI() {}; 21 | 22 | CCI(const size_t p, const T c = 0.015) : 23 | ma(p), buffer(p), coeff(c) { 24 | }; 25 | 26 | inline int update(const T in) noexcept { 27 | buffer.update(in); 28 | ma.update(in); 29 | if (!buffer.full()) return common::INDICATOR_NOT_READY_TO_WORK; 30 | if (std::isnan(ma.get())) return common::INDICATOR_NOT_READY_TO_WORK; 31 | std::vector temp(buffer.to_vector()); 32 | T sum = 0; 33 | for (size_t i = 0; i < temp.size(); ++i) { 34 | sum += std::abs(temp[i] - ma.get()); 35 | } 36 | const T mad = sum / (T)temp.size(); 37 | output_value = (in - ma.get()) / (coeff * mad); 38 | return common::OK; 39 | } 40 | 41 | inline int update(const T high, const T low, const T close) noexcept { 42 | const T in = (high + low + close) / 3.0d; 43 | return update(in); 44 | } 45 | 46 | inline int update(const T in, T &out) noexcept { 47 | const int err = update(in); 48 | out = output_value; 49 | return err; 50 | } 51 | 52 | inline int update(const T high, const T low, const T close, T &out) noexcept { 53 | const int err = update(high, low, close); 54 | out = output_value; 55 | return err; 56 | } 57 | 58 | inline int test(const T in) noexcept { 59 | buffer.test(in); 60 | ma.test(in); 61 | if (!buffer.full()) return common::INDICATOR_NOT_READY_TO_WORK; 62 | if (std::isnan(ma.get())) return common::INDICATOR_NOT_READY_TO_WORK; 63 | const std::vector temp(buffer.to_vector()); 64 | T sum = 0; 65 | for (size_t i = 0; i < temp.size(); ++i) { 66 | sum += std::abs(temp[i] - ma.get()); 67 | } 68 | const T mad = sum / (T)temp.size(); 69 | output_value = (in - ma.get()) / (coeff * mad); 70 | return common::OK; 71 | } 72 | 73 | inline int test(const T high, const T low, const T close) noexcept { 74 | const T in = (high + low + close) / 3.0d; 75 | return test(in); 76 | } 77 | 78 | inline int test(const T in, T &out) noexcept { 79 | const int err = test(in); 80 | out = output_value; 81 | return err; 82 | } 83 | 84 | inline int test(const T high, const T low, const T close, T &out) noexcept { 85 | const int err = test(high, low, close); 86 | out = output_value; 87 | return err; 88 | } 89 | 90 | /** \brief Получить значение индикатора 91 | * \return Значение индикатора 92 | */ 93 | inline T get() const noexcept { 94 | return output_value; 95 | } 96 | 97 | /** \brief Очистить данные индикатора 98 | */ 99 | inline void clear() noexcept { 100 | ma.clear(); 101 | buffer.clear(); 102 | output_value = std::numeric_limits::quiet_NaN(); 103 | } 104 | }; // CCI 105 | 106 | }; // xtechnical 107 | 108 | #endif // XTECHNICAL_CCI_HPP_INCLUDED 109 | -------------------------------------------------------------------------------- /include/indicators/xtechnical_cluster_shaper.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_CLUSTER_CLUSTER_HPP_INCLUDED 2 | #define XTECHNICAL_CLUSTER_CLUSTER_HPP_INCLUDED 3 | 4 | #include "../xtechnical_common.hpp" 5 | 6 | namespace xtechnical { 7 | 8 | /** \brief Формирователь Кластеров 9 | */ 10 | class ClusterShaper { 11 | public: 12 | 13 | /** \brief Кластер 14 | */ 15 | class Cluster { 16 | public: 17 | std::map distribution; 18 | int open = 0; 19 | int close = 0; 20 | int high = 0; 21 | int low = 0; 22 | int volume = 0; 23 | int max_volume = 0; 24 | int max_index = 0; 25 | uint64_t timestamp = 0; 26 | double pips_size = 0.0; 27 | 28 | inline double get_close_price() noexcept { 29 | return (double)close * pips_size; 30 | } 31 | 32 | inline double get_open_price() noexcept { 33 | return (double)open * pips_size; 34 | } 35 | 36 | inline std::vector get_array() const noexcept { 37 | if (distribution.empty()) return std::vector(); 38 | std::vector temp; 39 | temp.reserve(distribution.size()); 40 | int last_tick = 0; 41 | int index = 0; 42 | for (const auto &item : distribution) { 43 | if (index == 0) { 44 | temp.push_back(item.second); 45 | last_tick = item.first; 46 | } else { 47 | const int diff = (item.first - last_tick); 48 | last_tick = item.first; 49 | for(int i = 1; i < diff; ++i) { 50 | temp.push_back(0.0d); 51 | } 52 | temp.push_back(item.second); 53 | } 54 | ++index; 55 | } 56 | return std::move(temp); 57 | } 58 | 59 | inline std::vector get_normalized_array() const noexcept { 60 | std::vector temp(get_array()); 61 | if (max_volume > 0) { 62 | for (auto &item : temp) { 63 | item /= (double)max_volume; 64 | } 65 | } else return std::vector(temp.size()); 66 | return std::move(temp); 67 | } 68 | 69 | inline double get_max_volume_price() const noexcept { 70 | return (double)max_index * pips_size; 71 | } 72 | 73 | inline double get_center_mass_price() const noexcept { 74 | int64_t sum = 0; 75 | for (auto &item : distribution) { 76 | sum += item.first * item.second; 77 | } 78 | sum /= volume; 79 | return (double)sum * pips_size; 80 | } 81 | 82 | inline double get_center_mass() const noexcept { 83 | int64_t sum = 0; 84 | for (auto &item : distribution) { 85 | sum += item.first * item.second; 86 | } 87 | sum /= volume; 88 | return sum; 89 | } 90 | 91 | inline double get_center_mass_norm() const noexcept { 92 | const int diff = high - low; 93 | return diff == 0 ? 0.5 : (double)(get_center_mass() - std::min(high, low)) / (double)diff; 94 | } 95 | }; 96 | 97 | private: 98 | Cluster cluster; 99 | uint64_t period = 0; 100 | uint64_t last_bar = 0; 101 | 102 | double pips_size = 0; 103 | bool is_use_bar_stop_time = false; 104 | bool is_fill = false; 105 | bool is_once = false; 106 | 107 | public: 108 | ClusterShaper() {}; 109 | 110 | /** \brief Инициализировать формирователь баров 111 | * \param p Период индикатора в секундах 112 | * \param ps Точность цены, например 0.00001 113 | * \param ubst Флаг, включает использование последней метки времени бара вместо начала бара, как времени бара 114 | */ 115 | ClusterShaper(const size_t p, const double ps, const bool ubst = false) : 116 | period(p), pips_size(ps), is_use_bar_stop_time(ubst) { 117 | } 118 | 119 | std::function on_close_bar; /**< Функция обратного вызова в момент закрытия бара */ 120 | std::function on_unformed_bar = nullptr; /**< Функция обратного вызова для несформированного бара */ 121 | 122 | /** \brief Обновить состояние индикатора 123 | * \param input Текущая цена 124 | * \param timestamp Метка времени в секундах 125 | */ 126 | int update(const double input, const uint64_t timestamp) noexcept { 127 | if(period == 0) return common::NO_INIT; 128 | const uint64_t current_bar = timestamp / period; 129 | if (last_bar == 0) { 130 | last_bar = current_bar; 131 | return common::INDICATOR_NOT_READY_TO_WORK; 132 | } 133 | 134 | const int tick = (int)((input / pips_size) + 0.5d); 135 | 136 | if (current_bar > last_bar) { 137 | if (is_once) { 138 | cluster.timestamp = is_use_bar_stop_time ? 139 | (last_bar * period + period) : (last_bar * period); 140 | on_close_bar(cluster); 141 | cluster.distribution.clear(); 142 | cluster.distribution[tick] = 1; 143 | last_bar = current_bar; 144 | cluster.timestamp = is_use_bar_stop_time ? 145 | (last_bar * period + period) : (last_bar * period); 146 | cluster.open = cluster.close = tick; 147 | cluster.volume = 1; 148 | cluster.max_volume = 1; 149 | cluster.max_index = tick; 150 | cluster.high = cluster.low = tick; 151 | cluster.pips_size = pips_size; 152 | return common::OK; 153 | } 154 | cluster.distribution.clear(); 155 | cluster.distribution[tick] = 1; 156 | last_bar = current_bar; 157 | cluster.timestamp = is_use_bar_stop_time ? 158 | (last_bar * period + period) : (last_bar * period); 159 | cluster.open = cluster.close = tick; 160 | cluster.volume = 1; 161 | cluster.max_volume = 1; 162 | cluster.max_index = tick; 163 | cluster.high = cluster.low = tick; 164 | cluster.pips_size = pips_size; 165 | is_once = true; 166 | return common::OK; 167 | } else 168 | if (current_bar == last_bar) { 169 | if (is_once) { 170 | auto it = cluster.distribution.find(tick); 171 | if (it == cluster.distribution.end()) { 172 | cluster.distribution[tick] = 1; 173 | } else { 174 | ++it->second; 175 | if (it->second > cluster.max_volume) { 176 | cluster.max_volume = it->second; 177 | cluster.max_index = tick; 178 | } 179 | } 180 | cluster.close = tick; 181 | if (tick > cluster.high) cluster.high = tick; 182 | if (tick < cluster.low) cluster.low = tick; 183 | ++cluster.volume; 184 | if (on_unformed_bar != nullptr) { 185 | on_unformed_bar(cluster); 186 | } 187 | } 188 | } 189 | return common::OK; 190 | } 191 | 192 | static inline std::vector get_triangular_distribution( 193 | size_t length, 194 | size_t vertex_position) { 195 | if (length == 0) return std::vector(); 196 | if (length == 1) return std::vector(1,1.0d); 197 | std::vector temp(length, 0.0d); 198 | if (vertex_position >= length) vertex_position = length - 1; 199 | const double step_up = vertex_position <= 1 ? 1.0d : (1.0d / (double)vertex_position); 200 | const size_t diff = (length - 1) - vertex_position; 201 | const double step_dn = diff <= 1 ? 1.0d : (1.0d / (double)diff); 202 | double step = vertex_position == 0 ? 1.0d : 0.0d; 203 | for (size_t i = 0; i <= vertex_position; ++i) { 204 | temp[i] = step; 205 | step += step_up; 206 | } 207 | step = 1.0d - step_dn; 208 | for (size_t i = vertex_position + 1; i < length; ++i) { 209 | temp[i] = step; 210 | step -= step_dn; 211 | } 212 | return std::move(temp); 213 | } 214 | 215 | static inline double get_euclidean_distance(const std::vector &x, const std::vector &y) { 216 | double sum = 0; 217 | for (size_t i = 0; i < x.size(); ++i) { 218 | const double diff = x[i] - y[i]; 219 | sum += diff * diff; 220 | } 221 | return 1.0d / (1.0d + std::sqrt(sum)); 222 | } 223 | 224 | static inline double get_cosine_similarity(const std::vector &x, const std::vector &y) { 225 | double sum = 0; 226 | double sum_x = 0; 227 | double sum_y = 0; 228 | for (size_t i = 0; i < x.size(); ++i) { 229 | sum += x[i] * y[i]; 230 | sum_x += x[i] * x[i]; 231 | sum_y += y[i] * y[i]; 232 | } 233 | return sum / (std::sqrt(sum_x) * std::sqrt(sum_y)); 234 | } 235 | 236 | /** \brief Очистить данные индикатора 237 | */ 238 | inline void clear() noexcept { 239 | cluster = Cluster(); 240 | last_bar = 0; 241 | is_once = false; 242 | } 243 | }; // ClusterShaper 244 | 245 | }; // xtechnical 246 | 247 | #endif // XTECHNICAL_CLUSTER_CLUSTER_HPP_INCLUDED 248 | -------------------------------------------------------------------------------- /include/indicators/xtechnical_crsi.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_CRSI_HPP_INCLUDED 2 | #define XTECHNICAL_CRSI_HPP_INCLUDED 3 | 4 | #include "../math/xtechnical_compare.hpp" 5 | 6 | namespace xtechnical { 7 | 8 | }; 9 | 10 | #endif // XTECHNICAL_CRSI_HPP_INCLUDED 11 | -------------------------------------------------------------------------------- /include/indicators/xtechnical_delay_line.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_DELAY_LINE_HPP_INCLUDED 2 | #define XTECHNICAL_DELAY_LINE_HPP_INCLUDED 3 | 4 | #include "../xtechnical_common.hpp" 5 | #include "../xtechnical_circular_buffer.hpp" 6 | 7 | namespace xtechnical { 8 | 9 | /** \brief Линия задержки 10 | */ 11 | template 12 | class DelayLine { 13 | private: 14 | circular_buffer buffer; 15 | size_t period = 0; 16 | T output_value = std::numeric_limits::quiet_NaN(); 17 | public: 18 | 19 | DelayLine() : buffer() {}; 20 | 21 | /** \brief Конструктор линии задержки 22 | * \param p Период 23 | */ 24 | DelayLine(const size_t p) : 25 | buffer(p + 1), period(p) { 26 | } 27 | 28 | /** \brief Обновить состояние индикатора 29 | * \param in Сигнал на входе 30 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 31 | */ 32 | int update(const T in) noexcept { 33 | if(period == 0) { 34 | output_value = in; 35 | return common::OK; 36 | } 37 | buffer.update(in); 38 | if(buffer.full()) { 39 | output_value = buffer.front(); 40 | return common::OK; 41 | } else { 42 | output_value = std::numeric_limits::quiet_NaN(); 43 | } 44 | return common::INDICATOR_NOT_READY_TO_WORK; 45 | } 46 | 47 | /** \brief Обновить состояние индикатора 48 | * \param in Сигнал на входе 49 | * \param out Сигнал на выходе 50 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 51 | */ 52 | int update(const T in, T &out) noexcept { 53 | const int err = update(in); 54 | out = output_value; 55 | return err; 56 | } 57 | 58 | /** \brief Протестировать индикатор 59 | * 60 | * Данный метод отличается от update тем, 61 | * что не влияет на внутреннее состояние индикатора 62 | * \param in Сигнал на входе 63 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 64 | */ 65 | int test(const T in) noexcept { 66 | if(period == 0) { 67 | output_value = in; 68 | return common::OK; 69 | } 70 | buffer.test(in); 71 | if(buffer.full()) { 72 | output_value = buffer.front(); 73 | return common::OK; 74 | } else { 75 | output_value = std::numeric_limits::quiet_NaN(); 76 | } 77 | return common::INDICATOR_NOT_READY_TO_WORK; 78 | } 79 | 80 | /** \brief Протестировать индикатор 81 | * 82 | * Данный метод отличается от update тем, 83 | * что не влияет на внутреннее состояние индикатора 84 | * \param in Сигнал на входе 85 | * \param out Сигнал на выходе 86 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 87 | */ 88 | int test(const T in, T &out) noexcept { 89 | const int err = test(in); 90 | out = output_value; 91 | return err; 92 | } 93 | 94 | inline T get() const noexcept { 95 | return output_value; 96 | } 97 | 98 | /** \brief Очистить данные индикатора 99 | */ 100 | inline void clear() noexcept { 101 | buffer.clear(); 102 | output_value = std::numeric_limits::quiet_NaN(); 103 | } 104 | }; 105 | }; // xtechnical 106 | 107 | #endif // XTECHNICAL_FAST_MIN_MAX_HPP_INCLUDED 108 | -------------------------------------------------------------------------------- /include/indicators/xtechnical_fast_min_max.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_FAST_MIN_MAX_HPP_INCLUDED 2 | #define XTECHNICAL_FAST_MIN_MAX_HPP_INCLUDED 3 | 4 | #include "../xtechnical_common.hpp" 5 | #include "xtechnical_delay_line.hpp" 6 | 7 | namespace xtechnical { 8 | 9 | /** \brief Быстрый алгоритм поиска Min и Max 10 | * Оригинал: https://arxiv.org/abs/cs/0610046v5 11 | */ 12 | template 13 | class FastMinMax { 14 | private: 15 | T output_max_value = std::numeric_limits::quiet_NaN(); 16 | T output_min_value = std::numeric_limits::quiet_NaN(); 17 | T last_input = 0; 18 | int64_t period = 0; 19 | int64_t index = 0; 20 | std::deque> U, L; 21 | DelayLine delay_line; 22 | public: 23 | FastMinMax() {}; 24 | 25 | FastMinMax(const size_t p, const size_t o = 0) : 26 | period((int64_t)p), delay_line(o) { 27 | }; 28 | 29 | int update(T input) noexcept { 30 | if(delay_line.update(input) != common::OK) { 31 | return common::INDICATOR_NOT_READY_TO_WORK; 32 | } 33 | input = delay_line.get(); 34 | if (index == 0) { 35 | ++index; 36 | last_input = input; 37 | return common::INDICATOR_NOT_READY_TO_WORK; 38 | } 39 | if (input > last_input) { 40 | L.push_back(std::make_pair(index - 1, last_input)); 41 | if (index == period + L.front().first) L.pop_front() ; 42 | while (U.size() > 0) { 43 | if (input <= U.back().second) { 44 | if (index == period + U.front().first) U.pop_front(); 45 | break ; 46 | } // end if 47 | U.pop_back() ; 48 | } // end while 49 | } else { 50 | U.push_back(std::make_pair(index - 1, last_input)) ; 51 | if (index == period + U.front().first) U.pop_front() ; 52 | while (L.size() > 0) { 53 | if (input >= L.back().second) { 54 | if (index == period + L.front().first) L.pop_front(); 55 | break ; 56 | } // end if 57 | L.pop_back(); 58 | } // end while 59 | } // end if else 60 | ++index; 61 | if (index >= period) { 62 | output_max_value = U.size() > 0 ? U.front().second : input; 63 | output_min_value = L.size() > 0 ? L.front().second : input; 64 | last_input = input; 65 | return common::OK; 66 | } 67 | last_input = input; 68 | return common::INDICATOR_NOT_READY_TO_WORK; 69 | } 70 | 71 | /** \brief Обновить состояние индикатора 72 | * \param input Сигнал на входе 73 | * \param min_value Минимальный сигнал на выходе за период 74 | * \param max_value Максимальный сигнал на выходе за период 75 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 76 | */ 77 | int update(const T input, T &min_value, T &max_value) noexcept { 78 | const int err = update(input); 79 | min_value = output_min_value; 80 | max_value = output_max_value; 81 | return err; 82 | } 83 | 84 | /** \brief Протестировать индикатор 85 | * 86 | * Данная функция отличается от update тем, что не влияет на внутреннее состояние индикатора 87 | * \param input Сигнал на входе 88 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 89 | */ 90 | int test(T input) noexcept { 91 | if(delay_line.test(input) != common::OK) { 92 | return common::INDICATOR_NOT_READY_TO_WORK; 93 | } 94 | input = delay_line.get(); 95 | if (index == 0) return common::INDICATOR_NOT_READY_TO_WORK; 96 | std::deque> tU(U), tL(L); 97 | if (input > last_input) { 98 | tL.push_back(std::make_pair(index - 1, last_input)); 99 | if (index == period + tL.front().first) tL.pop_front() ; 100 | while (tU.size() > 0) { 101 | if (input <= tU.back().second) { 102 | if (index == period + tU.front().first) tU.pop_front(); 103 | break ; 104 | } // end if 105 | tU.pop_back() ; 106 | } // end while 107 | } else { 108 | tU.push_back(std::make_pair(index - 1, last_input)) ; 109 | if (index == period + tU.front().first) tU.pop_front() ; 110 | while (tL.size() > 0) { 111 | if (input >= tL.back().second) { 112 | if (index == period + tL.front().first) tL.pop_front(); 113 | break ; 114 | } // end if 115 | tL.pop_back(); 116 | } // end while 117 | } // end if else 118 | if ((index + 1) >= period) { 119 | output_max_value = tU.size() > 0 ? tU.front().second : input; 120 | output_min_value = tL.size() > 0 ? tL.front().second : input; 121 | return common::OK; 122 | } 123 | return common::INDICATOR_NOT_READY_TO_WORK; 124 | } 125 | 126 | /** \brief Протестировать индикатор 127 | * 128 | * Данная функция отличается от update тем, что не влияет на внутреннее состояние индикатора 129 | * \param input Сигнал на входе 130 | * \param min_value Минимальный сигнал на выходе за период 131 | * \param max_value Максимальный сигнал на выходе за период 132 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 133 | */ 134 | int test(const T input, T &min_value, T &max_value) { 135 | const int err = test(input); 136 | min_value = output_min_value; 137 | max_value = output_max_value; 138 | return err; 139 | } 140 | 141 | /** \brief Получить минимальное значение индикатора 142 | * \return Минимальное значение индикатора 143 | */ 144 | inline T get_min() const noexcept { 145 | return output_min_value; 146 | } 147 | 148 | /** \brief Получить максимальное значение индикатора 149 | * \return Максимальное значение индикатора 150 | */ 151 | inline T get_max() const noexcept { 152 | return output_max_value; 153 | } 154 | 155 | /** \brief Очистить данные индикатора 156 | */ 157 | inline void clear() noexcept { 158 | output_min_value = std::numeric_limits::quiet_NaN(); 159 | output_max_value = std::numeric_limits::quiet_NaN(); 160 | last_input = 0; 161 | index = 0; 162 | U.clear(); 163 | L.clear(); 164 | delay_line.clear(); 165 | } 166 | }; 167 | }; // xtechnical 168 | 169 | #endif // XTECHNICAL_FAST_MIN_MAX_HPP_INCLUDED 170 | -------------------------------------------------------------------------------- /include/indicators/xtechnical_fractals.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_FRACTALS_HPP_INCLUDED 2 | #define XTECHNICAL_FRACTALS_HPP_INCLUDED 3 | 4 | #include "../xtechnical_common.hpp" 5 | 6 | namespace xtechnical { 7 | 8 | /** \brief Фракталы Билла Вильямса 9 | * Оригинал: https://www.mql5.com/en/code/viewcode/7982/130162/Fractals.mq4 10 | */ 11 | template 12 | class Fractals { 13 | private: 14 | circular_buffer buffer_up; 15 | circular_buffer buffer_dn; 16 | 17 | T save_output_up = std::numeric_limits::quiet_NaN(); 18 | T save_output_dn = std::numeric_limits::quiet_NaN(); 19 | T output_up = std::numeric_limits::quiet_NaN(); 20 | T output_dn = std::numeric_limits::quiet_NaN(); 21 | 22 | public: 23 | 24 | Fractals() : buffer_up(9), buffer_dn(9) {}; 25 | 26 | /** \brief Обновить состояние индикатора 27 | * \param high Максимальное значение бара 28 | * \param low Минимальное значение бара 29 | * \param on_up Функция обратного вызова для верхнего уровня 30 | * \param on_dn Функция обратного вызова для нижнего уровня 31 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 32 | */ 33 | int update( 34 | const T high, 35 | const T low, 36 | std::function on_up = nullptr, 37 | std::function on_dn = nullptr) noexcept { 38 | buffer_up.update(high); 39 | buffer_dn.update(low); 40 | 41 | if(buffer_up.full()) { 42 | // Fractals up 43 | const std::vector values = buffer_up.to_vector(); 44 | // 0 1 2 3 4 5 6 7 8 45 | 46 | // 5 bars Fractal 47 | if (values[6] > values[4] && 48 | values[6] > values[5] && 49 | values[6] > values[7] && 50 | values[6] > values[8]) { 51 | save_output_up = output_up = values[6]; 52 | if (on_up) on_up(values[6]); 53 | } else 54 | // 6 bars Fractal 55 | if (values[6] > values[3] && 56 | values[6] > values[4] && 57 | values[6] == values[5] && 58 | values[6] > values[7] && 59 | values[6] > values[8]) { 60 | save_output_up = output_up = values[6]; 61 | if (on_up) on_up(values[6]); 62 | } else 63 | // 7 bars Fractal 64 | if (values[6] > values[2] && 65 | values[6] > values[3] && 66 | values[6] == values[4] && 67 | values[6] >= values[5] && 68 | values[6] > values[7] && 69 | values[6] > values[8]) { 70 | save_output_up = output_up = values[6]; 71 | if (on_up) on_up(values[6]); 72 | } else 73 | // 8 bars Fractal 74 | if (values[6] > values[1] && 75 | values[6] > values[2] && 76 | values[6] == values[3] && 77 | values[6] == values[4] && 78 | values[6] >= values[5] && 79 | values[6] > values[7] && 80 | values[6] > values[8]) { 81 | save_output_up = output_up = values[6]; 82 | if (on_up) on_up(values[6]); 83 | } else 84 | // 9 bars Fractal 85 | if (values[6] > values[0] && 86 | values[6] > values[1] && 87 | values[6] == values[2] && 88 | values[6] >= values[3] && 89 | values[6] == values[4] && 90 | values[6] >= values[5] && 91 | values[6] > values[7] && 92 | values[6] > values[8]) { 93 | save_output_up = output_up = values[6]; 94 | if (on_up) on_up(values[6]); 95 | } else { 96 | output_up = save_output_up; 97 | } 98 | } else return common::INDICATOR_NOT_READY_TO_WORK; 99 | if(buffer_dn.full()) { 100 | // Fractals down 101 | const std::vector values = buffer_dn.to_vector(); 102 | // 0 1 2 3 4 5 6 7 8 103 | 104 | // 5 bars Fractal 105 | if (values[6] < values[4] && 106 | values[6] < values[5] && 107 | values[6] < values[7] && 108 | values[6] < values[8]) { 109 | save_output_dn = output_dn = values[6]; 110 | if (on_dn) on_dn(values[6]); 111 | } else 112 | // 6 bars Fractal 113 | if (values[6] < values[3] && 114 | values[6] < values[4] && 115 | values[6] == values[5] && 116 | values[6] < values[7] && 117 | values[6] < values[8]) { 118 | save_output_dn = output_dn = values[6]; 119 | if (on_dn) on_dn(values[6]); 120 | } else 121 | // 7 bars Fractal 122 | if (values[6] < values[2] && 123 | values[6] < values[3] && 124 | values[6] == values[4] && 125 | values[6] <= values[5] && 126 | values[6] < values[7] && 127 | values[6] < values[8]) { 128 | save_output_dn = output_dn = values[6]; 129 | if (on_dn) on_dn(values[6]); 130 | } else 131 | // 8 bars Fractal 132 | if (values[6] < values[1] && 133 | values[6] < values[2] && 134 | values[6] == values[3] && 135 | values[6] == values[4] && 136 | values[6] <= values[5] && 137 | values[6] < values[7] && 138 | values[6] < values[8]) { 139 | save_output_dn = output_dn = values[6]; 140 | if (on_dn) on_dn(values[6]); 141 | } else 142 | // 9 bars Fractal 143 | if (values[6] < values[0] && 144 | values[6] < values[1] && 145 | values[6] == values[2] && 146 | values[6] <= values[3] && 147 | values[6] == values[4] && 148 | values[6] <= values[5] && 149 | values[6] < values[7] && 150 | values[6] < values[8]) { 151 | save_output_dn = output_dn = values[6]; 152 | if (on_dn) on_dn(values[6]); 153 | } else { 154 | output_dn = save_output_dn; 155 | } 156 | } else return common::INDICATOR_NOT_READY_TO_WORK; 157 | return common::OK; 158 | } 159 | 160 | /** \brief Протестировать индикатор 161 | * \param high Максимальное значение бара 162 | * \param low Минимальное значение бара 163 | * \param on_up Функция обратного вызова для верхнего уровня 164 | * \param on_dn Функция обратного вызова для нижнего уровня 165 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 166 | */ 167 | int test( 168 | const T high, 169 | const T low, 170 | std::function on_up = nullptr, 171 | std::function on_dn = nullptr) noexcept { 172 | buffer_up.test(high); 173 | buffer_dn.test(low); 174 | 175 | if(buffer_up.full()) { 176 | // Fractals up 177 | const std::vector values = buffer_up.to_vector(); 178 | // 0 1 2 3 4 5 6 7 8 179 | 180 | // 5 bars Fractal 181 | if (values[6] > values[4] && 182 | values[6] > values[5] && 183 | values[6] > values[7] && 184 | values[6] > values[8]) { 185 | output_up = values[6]; 186 | if (on_up) on_up(values[6]); 187 | } else 188 | // 6 bars Fractal 189 | if (values[6] > values[3] && 190 | values[6] > values[4] && 191 | values[6] == values[5] && 192 | values[6] > values[7] && 193 | values[6] > values[8]) { 194 | output_up = values[6]; 195 | if (on_up) on_up(values[6]); 196 | } else 197 | // 7 bars Fractal 198 | if (values[6] > values[2] && 199 | values[6] > values[3] && 200 | values[6] == values[4] && 201 | values[6] >= values[5] && 202 | values[6] > values[7] && 203 | values[6] > values[8]) { 204 | output_up = values[6]; 205 | if (on_up) on_up(values[6]); 206 | } else 207 | // 8 bars Fractal 208 | if (values[6] > values[1] && 209 | values[6] > values[2] && 210 | values[6] == values[3] && 211 | values[6] == values[4] && 212 | values[6] >= values[5] && 213 | values[6] > values[7] && 214 | values[6] > values[8]) { 215 | output_up = values[6]; 216 | if (on_up) on_up(values[6]); 217 | } else 218 | // 9 bars Fractal 219 | if (values[6] > values[0] && 220 | values[6] > values[1] && 221 | values[6] == values[2] && 222 | values[6] >= values[3] && 223 | values[6] == values[4] && 224 | values[6] >= values[5] && 225 | values[6] > values[7] && 226 | values[6] > values[8]) { 227 | output_up = values[6]; 228 | if (on_up) on_up(values[6]); 229 | } else { 230 | output_up = save_output_up; 231 | } 232 | } else return common::INDICATOR_NOT_READY_TO_WORK; 233 | if(buffer_dn.full()) { 234 | // Fractals down 235 | const std::vector values = buffer_dn.to_vector(); 236 | // 0 1 2 3 4 5 6 7 8 237 | 238 | // 5 bars Fractal 239 | if (values[6] < values[4] && 240 | values[6] < values[5] && 241 | values[6] < values[7] && 242 | values[6] < values[8]) { 243 | output_dn = values[6]; 244 | if (on_dn) on_dn(values[6]); 245 | } else 246 | // 6 bars Fractal 247 | if (values[6] < values[3] && 248 | values[6] < values[4] && 249 | values[6] == values[5] && 250 | values[6] < values[7] && 251 | values[6] < values[8]) { 252 | output_dn = values[6]; 253 | if (on_dn) on_dn(values[6]); 254 | } else 255 | // 7 bars Fractal 256 | if (values[6] < values[2] && 257 | values[6] < values[3] && 258 | values[6] == values[4] && 259 | values[6] <= values[5] && 260 | values[6] < values[7] && 261 | values[6] < values[8]) { 262 | output_dn = values[6]; 263 | if (on_dn) on_dn(values[6]); 264 | } else 265 | // 8 bars Fractal 266 | if (values[6] < values[1] && 267 | values[6] < values[2] && 268 | values[6] == values[3] && 269 | values[6] == values[4] && 270 | values[6] <= values[5] && 271 | values[6] < values[7] && 272 | values[6] < values[8]) { 273 | output_dn = values[6]; 274 | if (on_dn) on_dn(values[6]); 275 | } else 276 | // 9 bars Fractal 277 | if (values[6] < values[0] && 278 | values[6] < values[1] && 279 | values[6] == values[2] && 280 | values[6] <= values[3] && 281 | values[6] == values[4] && 282 | values[6] <= values[5] && 283 | values[6] < values[7] && 284 | values[6] < values[8]) { 285 | output_dn = values[6]; 286 | if (on_dn) on_dn(values[6]); 287 | } else { 288 | output_dn = save_output_dn; 289 | } 290 | } else return common::INDICATOR_NOT_READY_TO_WORK; 291 | return common::OK; 292 | } 293 | 294 | /** \brief Получить значение нижнего фрактала 295 | * \return Значение нижнего фрактала 296 | */ 297 | inline T get_up() const noexcept { 298 | return output_up; 299 | } 300 | 301 | /** \brief Получить значение верхнего фрактала 302 | * \return Значение верхнего фрактала 303 | */ 304 | inline T get_dn() const noexcept { 305 | return output_dn; 306 | } 307 | 308 | /** \brief Очистить данные индикатора 309 | */ 310 | inline void clear() noexcept { 311 | buffer_up.clear(); 312 | buffer_dn.clear(); 313 | output_up = std::numeric_limits::quiet_NaN(); 314 | output_dn = std::numeric_limits::quiet_NaN(); 315 | save_output_up = std::numeric_limits::quiet_NaN(); 316 | save_output_dn = std::numeric_limits::quiet_NaN(); 317 | } 318 | }; 319 | 320 | }; // xtechnical 321 | 322 | #endif // XTECHNICAL_FRACTALS_HPP_INCLUDED 323 | -------------------------------------------------------------------------------- /include/indicators/xtechnical_fractals_level.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_FRACTALS_LEVEL_HPP_INCLUDED 2 | #define XTECHNICAL_FRACTALS_LEVEL_HPP_INCLUDED 3 | 4 | #include "../xtechnical_common.hpp" 5 | #include "xtechnical_fractals.hpp" 6 | 7 | namespace xtechnical { 8 | 9 | /** \brief Уровни по фракталам Билла Вильямса 10 | */ 11 | template 12 | class FractalsLevel { 13 | private: 14 | Fractals fractals; 15 | circular_buffer buffer_up; 16 | circular_buffer buffer_dn; 17 | 18 | T output_up = std::numeric_limits::quiet_NaN(); 19 | T output_dn = std::numeric_limits::quiet_NaN(); 20 | T save_output_up = std::numeric_limits::quiet_NaN(); 21 | T save_output_dn = std::numeric_limits::quiet_NaN(); 22 | public: 23 | 24 | std::function on_up = nullptr; 25 | std::function on_dn = nullptr; 26 | 27 | FractalsLevel() : buffer_up(3), buffer_dn(3) {}; 28 | 29 | /** \brief Обновить состояние индикатора 30 | * \param high Максимальное значение бара 31 | * \param low Минимальное значение бара 32 | * \param on_up Функция обратного вызова для верхнего уровня 33 | * \param on_dn Функция обратного вызова для нижнего уровня 34 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 35 | */ 36 | int update( 37 | const T high, 38 | const T low, 39 | std::function on_up = nullptr, 40 | std::function on_dn = nullptr) noexcept { 41 | 42 | fractals.update( 43 | high, 44 | low, 45 | [&](const double value){ 46 | buffer_up.update(value); 47 | }, 48 | [&](const double value){ 49 | buffer_dn.update(value); 50 | } 51 | ); 52 | 53 | if(buffer_up.full()) { 54 | // Fractals up 55 | const std::vector values = buffer_up.to_vector(); 56 | // 0 1 2 57 | 58 | if (values[1] > values[0] && 59 | values[1] > values[2]) { 60 | save_output_up = output_up = values[1]; 61 | if (on_up) on_up(values[1]); 62 | } else { 63 | output_up = save_output_up; 64 | } 65 | } else return common::INDICATOR_NOT_READY_TO_WORK; 66 | if(buffer_dn.full()) { 67 | // Fractals down 68 | std::vector values = buffer_dn.to_vector(); 69 | // 0 1 2 70 | 71 | if (values[1] < values[0] && 72 | values[1] < values[2]) { 73 | save_output_dn = output_dn = values[1]; 74 | if (on_dn) on_dn(values[1]); 75 | } else { 76 | output_dn = save_output_dn; 77 | } 78 | } else return common::INDICATOR_NOT_READY_TO_WORK; 79 | return common::OK; 80 | } 81 | 82 | /** \brief Протестировать индикатор 83 | * \param high Максимальное значение бара 84 | * \param low Минимальное значение бара 85 | * \param on_up Функция обратного вызова для верхнего уровня 86 | * \param on_dn Функция обратного вызова для нижнего уровня 87 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 88 | */ 89 | int test( 90 | const T high, 91 | const T low, 92 | std::function on_up = nullptr, 93 | std::function on_dn = nullptr) noexcept { 94 | 95 | fractals.test( 96 | high, 97 | low, 98 | [&](const double value){ 99 | buffer_up.test(value); 100 | }, 101 | [&](const double value){ 102 | buffer_dn.test(value); 103 | } 104 | ); 105 | 106 | if(buffer_up.full()) { 107 | // Fractals up 108 | const std::vector values = buffer_up.to_vector(); 109 | // 0 1 2 110 | 111 | if (values[1] > values[0] && 112 | values[1] > values[2]) { 113 | output_up = values[1]; 114 | if (on_up) on_up(values[1]); 115 | } else { 116 | output_up = save_output_up; 117 | } 118 | } else return common::INDICATOR_NOT_READY_TO_WORK; 119 | if(buffer_dn.full()) { 120 | // Fractals down 121 | std::vector values = buffer_dn.to_vector(); 122 | // 0 1 2 123 | 124 | if (values[1] < values[0] && 125 | values[1] < values[2]) { 126 | output_dn = values[1]; 127 | if (on_dn) on_dn(values[1]); 128 | } else { 129 | output_dn = save_output_dn; 130 | } 131 | } else return common::INDICATOR_NOT_READY_TO_WORK; 132 | return common::OK; 133 | } 134 | 135 | /** \brief Получить значение нижнего фрактала 136 | * \return Значение нижнего фрактала 137 | */ 138 | inline T get_up() const noexcept { 139 | return output_up; 140 | } 141 | 142 | /** \brief Получить значение верхнего фрактала 143 | * \return Значение верхнего фрактала 144 | */ 145 | inline T get_dn() const noexcept { 146 | return output_dn; 147 | } 148 | 149 | /** \brief Очистить данные индикатора 150 | */ 151 | inline void clear() noexcept { 152 | fractals.clear(); 153 | buffer_up.clear(); 154 | buffer_dn.clear(); 155 | output_up = std::numeric_limits::quiet_NaN(); 156 | output_dn = std::numeric_limits::quiet_NaN(); 157 | save_output_up = std::numeric_limits::quiet_NaN(); 158 | save_output_dn = std::numeric_limits::quiet_NaN(); 159 | } 160 | }; 161 | 162 | }; // xtechnical 163 | 164 | #endif // XTECHNICAL_FRACTALS_LEVEL_HPP_INCLUDED 165 | -------------------------------------------------------------------------------- /include/indicators/xtechnical_rsi.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_RSI_HPP_INCLUDED 2 | #define XTECHNICAL_RSI_HPP_INCLUDED 3 | 4 | #include "../xtechnical_common.hpp" 5 | 6 | namespace xtechnical { 7 | 8 | /** \brief Индекс относительной силы (RSI) 9 | */ 10 | template 11 | class RSI { 12 | private: 13 | MA_TYPE iU; 14 | MA_TYPE iD; 15 | bool is_init_ = false; 16 | bool is_update_ = false; 17 | T prev_ = 0; 18 | T output_value = std::numeric_limits::quiet_NaN(); 19 | public: 20 | 21 | RSI() {} 22 | 23 | /** \brief Инициализировать индикатор индекса относительной силы 24 | * \param period период индикатора 25 | */ 26 | RSI(const size_t period) : 27 | iU(period), iD(period) { 28 | } 29 | 30 | /** \brief Инициализировать индикатор индекса относительной силы 31 | * \param period Период индикатора 32 | */ 33 | inline void init(const size_t period) noexcept { 34 | is_update_ = false; 35 | iU = MA_TYPE(period); 36 | iD = MA_TYPE(period); 37 | } 38 | 39 | /** \brief Обновить состояние индикатора 40 | * \param in сигнал на входе 41 | * \return вернет 0 в случае успеха, иначе см. ErrorType 42 | */ 43 | int update(const T in) noexcept { 44 | if(!is_update_) { 45 | prev_ = in; 46 | output_value = std::numeric_limits::quiet_NaN(); 47 | is_update_ = true; 48 | return common::INDICATOR_NOT_READY_TO_WORK; 49 | } 50 | T u = 0, d = 0; 51 | if(prev_ < in) { 52 | u = in - prev_; 53 | } else 54 | if(prev_ > in) { 55 | d = prev_ - in; 56 | } 57 | int erru, errd = 0; 58 | erru = iU.update(u, u); 59 | errd = iD.update(d, d); 60 | prev_ = in; 61 | if(erru != common::OK || errd != common::OK) { 62 | output_value = std::numeric_limits::quiet_NaN(); 63 | return common::INDICATOR_NOT_READY_TO_WORK; 64 | } 65 | if(d == 0) { 66 | output_value = 100.0; 67 | return common::OK; 68 | } 69 | T rs = u / d; 70 | output_value = 100.0 - (100.0 / (1.0 + rs)); 71 | return common::OK; 72 | } 73 | 74 | /** \brief Обновить состояние индикатора 75 | * \param in Сигнал на входе 76 | * \param out Сигнал на выходе 77 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 78 | */ 79 | int update(const T in, T &out) noexcept { 80 | const int err = update(in); 81 | out = output_value; 82 | return common::OK; 83 | } 84 | 85 | /** \brief Протестировать индикатор 86 | * 87 | * Данная функция отличается от update тем, что не влияет на внутреннее состояние индикатора 88 | * \param in сигнал на входе 89 | * \return вернет 0 в случае успеха, иначе см. ErrorType 90 | */ 91 | int test(const T in) noexcept { 92 | if(!is_update_) { 93 | output_value = std::numeric_limits::quiet_NaN(); 94 | return common::INDICATOR_NOT_READY_TO_WORK; 95 | } 96 | T u = 0, d = 0; 97 | if(prev_ < in) { 98 | u = in - prev_; 99 | } else 100 | if(prev_ > in) { 101 | d = prev_ - in; 102 | } 103 | int erru, errd = 0; 104 | erru = iU.test(u, u); 105 | errd = iD.test(d, d); 106 | if(erru != common::OK || errd != common::OK) { 107 | output_value = std::numeric_limits::quiet_NaN(); 108 | return common::INDICATOR_NOT_READY_TO_WORK; 109 | } 110 | if(d == 0) { 111 | output_value = 100.0; 112 | return common::OK; 113 | } 114 | T rs = u / d; 115 | output_value = 100.0 - (100.0 / (1.0 + rs)); 116 | return common::OK; 117 | } 118 | 119 | /** \brief Протестировать индикатор 120 | * 121 | * Данная функция отличается от update тем, 122 | * что не влияет на внутреннее состояние индикатора 123 | * \param in Сигнал на входе 124 | * \param out Сигнал на выходе 125 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 126 | */ 127 | int test(const T in, T &out) noexcept { 128 | const int err = test(in); 129 | out = output_value; 130 | return common::OK; 131 | } 132 | 133 | /** \brief Получить значение индикатора 134 | * \return Значение индикатора 135 | */ 136 | inline T get() const noexcept { 137 | return output_value; 138 | } 139 | 140 | /** \brief Очистить данные индикатора 141 | */ 142 | void clear() noexcept { 143 | output_value = std::numeric_limits::quiet_NaN(); 144 | is_update_ = false; 145 | iU.clear(); 146 | iD.clear(); 147 | } 148 | }; 149 | 150 | }; // xtechnical 151 | 152 | #endif // XTECHNICAL_RSI_HPP_INCLUDED 153 | -------------------------------------------------------------------------------- /include/indicators/xtechnical_sma.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_SMA_HPP_INCLUDED 2 | #define XTECHNICAL_SMA_HPP_INCLUDED 3 | 4 | #include "../xtechnical_common.hpp" 5 | 6 | namespace xtechnical { 7 | 8 | /** \brief Простая скользящая средняя 9 | */ 10 | template 11 | class SMA { 12 | private: 13 | xtechnical::circular_buffer buffer; 14 | T last_data = 0; 15 | T output_value = std::numeric_limits::quiet_NaN(); 16 | size_t period = 0; 17 | public: 18 | SMA() {}; 19 | 20 | /** \brief Инициализировать простую скользящую среднюю 21 | * \param p Период 22 | */ 23 | SMA(const size_t p) : 24 | buffer(p + 1), period(p) { 25 | } 26 | 27 | /** \brief Обновить состояние индикатора 28 | * \param in сигнал на входе 29 | * \return вернет 0 в случае успеха, иначе см. ErrorType 30 | */ 31 | int update(const T in) noexcept { 32 | if(period == 0) { 33 | output_value = std::numeric_limits::quiet_NaN(); 34 | return common::NO_INIT; 35 | } 36 | buffer.update(in); 37 | if(buffer.full()) { 38 | last_data = last_data + (in - buffer.front()); 39 | output_value = last_data/(T)period; 40 | } else { 41 | last_data += in; 42 | output_value = std::numeric_limits::quiet_NaN(); 43 | return common::INDICATOR_NOT_READY_TO_WORK; 44 | } 45 | return common::OK; 46 | } 47 | 48 | /** \brief Обновить состояние индикатора 49 | * \param in Сигнал на входе 50 | * \param out Сигнал на выходе 51 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 52 | */ 53 | int update(const T in, T &out) noexcept { 54 | const int err = update(in); 55 | out = output_value; 56 | return err; 57 | } 58 | 59 | /** \brief Протестировать индикатор 60 | * 61 | * Данная функция отличается от update тем, 62 | * что не влияет на внутреннее состояние индикатора 63 | * \param in сигнал на входе 64 | * \return вернет 0 в случае успеха, иначе см. ErrorType 65 | */ 66 | int test(const T in) noexcept { 67 | if(period == 0) { 68 | output_value = std::numeric_limits::quiet_NaN(); 69 | return common::NO_INIT; 70 | } 71 | buffer.test(in); 72 | if(buffer.full()) { 73 | output_value = (last_data + (in - buffer.front()))/(T)period; 74 | } else { 75 | output_value = std::numeric_limits::quiet_NaN(); 76 | return common::INDICATOR_NOT_READY_TO_WORK; 77 | } 78 | return common::OK; 79 | } 80 | 81 | /** \brief Протестировать индикатор 82 | * 83 | * Данная функция отличается от update тем, 84 | * что не влияет на внутреннее состояние индикатора 85 | * \param in Сигнал на входе 86 | * \param out Сигнал на выходе 87 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 88 | */ 89 | int test(const T in, T &out) noexcept { 90 | const int err = test(in); 91 | out = output_value; 92 | return err; 93 | } 94 | 95 | /** \brief Получить значение индикатора 96 | * \return Значение индикатора 97 | */ 98 | inline T get() const noexcept { 99 | return output_value; 100 | } 101 | 102 | /** \brief Очистить данные индикатора 103 | */ 104 | inline void clear() noexcept { 105 | buffer.clear(); 106 | output_value = std::numeric_limits::quiet_NaN(); 107 | last_data = 0; 108 | } 109 | }; 110 | 111 | }; // xtechnical 112 | 113 | #endif // XTECHNICAL_SMA_HPP_INCLUDED 114 | -------------------------------------------------------------------------------- /include/indicators/xtechnical_super_trend.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_SUPER_TREND_HPP_INCLUDED 2 | #define XTECHNICAL_SUPER_TREND_HPP_INCLUDED 3 | 4 | #include "../xtechnical_common.hpp" 5 | #include "xtechnical_atr.hpp" 6 | #include "xtechnical_cci.hpp" 7 | 8 | namespace xtechnical { 9 | 10 | /** \brief Индекс товарного канала 11 | */ 12 | template 13 | class SuperTrend { 14 | private: 15 | CCI iCCI; 16 | ATR iATR; 17 | T output_value = std::numeric_limits::quiet_NaN(); 18 | T output_cci = std::numeric_limits::quiet_NaN(); 19 | public: 20 | 21 | SuperTrend() {}; 22 | 23 | /** \brief Конструктор класса индикатора SuperTrend 24 | * \param period_cci Период CCI. Стандартное значение 50 25 | * \param period_atr Период ATR. Стандартное значение 5 26 | * \param coeff_cci Коэффициент CCI, по умолчанию 0.015 27 | */ 28 | SuperTrend(const size_t period_cci, const size_t period_atr, const T coeff_cci = 0.015) : 29 | iCCI(period_cci, coeff_cci), iATR(period_atr) { 30 | }; 31 | 32 | inline int update(const T in) noexcept { 33 | iCCI.update(in); 34 | iATR.update(in); 35 | if (std::isnan(iCCI.get())) return common::NO_INIT; 36 | if (std::isnan(iATR.get())) return common::NO_INIT; 37 | output_cci = iCCI.get(); 38 | if (output_cci >= 0) output_value = in + iATR.get(); 39 | else output_value = in - iATR.get(); 40 | return common::OK; 41 | } 42 | 43 | inline int update(const T high, const T low, const T close) noexcept { 44 | iCCI.update(high, low, close); 45 | iATR.update(high, low, close); 46 | if (std::isnan(iCCI.get())) return common::NO_INIT; 47 | if (std::isnan(iATR.get())) return common::NO_INIT; 48 | output_cci = iCCI.get(); 49 | if (output_cci >= 0) output_value = high + iATR.get(); 50 | else output_value = low - iATR.get(); 51 | return common::OK; 52 | } 53 | 54 | inline int update(const T in, T &out) noexcept { 55 | const int err = update(in); 56 | out = output_value; 57 | return err; 58 | } 59 | 60 | inline int update(const T high, const T low, const T close, T &out) noexcept { 61 | const int err = update(high, low, close); 62 | out = output_value; 63 | return err; 64 | } 65 | 66 | inline int test(const T in) noexcept { 67 | iCCI.test(in); 68 | iATR.test(in); 69 | if (std::isnan(iCCI.get())) return common::NO_INIT; 70 | if (std::isnan(iATR.get())) return common::NO_INIT; 71 | output_cci = iCCI.get(); 72 | if (output_cci >= 0) output_value = in + iATR.get(); 73 | else output_value = in - iATR.get(); 74 | return common::OK; 75 | } 76 | 77 | inline int test(const T high, const T low, const T close) noexcept { 78 | iCCI.test(high, low, close); 79 | iATR.test(high, low, close); 80 | if (std::isnan(iCCI.get())) return common::NO_INIT; 81 | if (std::isnan(iATR.get())) return common::NO_INIT; 82 | output_cci = iCCI.get(); 83 | if (output_cci >= 0) output_value = high + iATR.get(); 84 | else output_value = low - iATR.get(); 85 | return common::OK; 86 | } 87 | 88 | inline int test(const T in, T &out) noexcept { 89 | const int err = test(in); 90 | out = output_value; 91 | return err; 92 | } 93 | 94 | inline int test(const T high, const T low, const T close, T &out) noexcept { 95 | const int err = test(high, low, close); 96 | out = output_value; 97 | return err; 98 | } 99 | 100 | /** \brief Получить значение индикатора 101 | * \return Значение индикатора 102 | */ 103 | inline T get() const noexcept { 104 | return output_value; 105 | } 106 | 107 | /** \brief Получить значение индикатора CCI 108 | * \return Значение индикатора 109 | */ 110 | inline T get_cci() const noexcept { 111 | return output_cci; 112 | } 113 | 114 | /** \brief Очистить данные индикатора 115 | */ 116 | inline void clear() noexcept { 117 | iCCI.clear(); 118 | iATR.clear(); 119 | output_cci = std::numeric_limits::quiet_NaN(); 120 | output_value = std::numeric_limits::quiet_NaN(); 121 | } 122 | }; // CCI 123 | 124 | }; // xtechnical 125 | 126 | #endif // XTECHNICAL_SUPER_TREND_HPP_INCLUDED 127 | -------------------------------------------------------------------------------- /include/indicators/xtechnical_true_range.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_TRUE_RANGE_HPP_INCLUDED 2 | #define XTECHNICAL_TRUE_RANGE_HPP_INCLUDED 3 | 4 | #include "../xtechnical_common.hpp" 5 | 6 | namespace xtechnical { 7 | 8 | /** \brief Истинный диапазон (True Range) 9 | */ 10 | template 11 | class TrueRange { 12 | private: 13 | T last_data = std::numeric_limits::quiet_NaN(); 14 | T output_value = std::numeric_limits::quiet_NaN(); 15 | 16 | public: 17 | TrueRange() {}; 18 | 19 | inline int update(const T high, const T low, const T close) noexcept { 20 | output_value = std::max(std::max(high - low, high - close), close - low); 21 | return common::OK; 22 | } 23 | 24 | inline int update(const T high, const T low, const T close, T &out) noexcept { 25 | const int err = update(high, low, close); 26 | out = output_value; 27 | return err; 28 | } 29 | 30 | /** \brief Обновить состояние индикатора 31 | * \param in Сигнал на входе 32 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 33 | */ 34 | inline int update(const T in) noexcept { 35 | if (std::isnan(last_data)) { 36 | last_data = in; 37 | return common::NO_INIT; 38 | } 39 | output_value = std::abs(in - last_data); 40 | last_data = in; 41 | return common::OK; 42 | } 43 | 44 | /** \brief Обновить состояние индикатора 45 | * \param in Сигнал на входе 46 | * \param out Сигнал на выходе 47 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 48 | */ 49 | inline int update(const T in, T &out) noexcept { 50 | const int err = update(in); 51 | out = output_value; 52 | return err; 53 | } 54 | 55 | inline int test(const T high, const T low, const T close) noexcept { 56 | output_value = std::max(std::max(high - low, high - close), close - low); 57 | return common::OK; 58 | } 59 | 60 | inline int test(const T high, const T low, const T close, T &out) noexcept { 61 | const int err = test(high, low, close); 62 | out = output_value; 63 | return err; 64 | } 65 | 66 | /** \brief Протестировать индикатор 67 | * 68 | * Данная функция отличается от update тем, 69 | * что не влияет на внутреннее состояние индикатора 70 | * \param in сигнал на входе 71 | * \return вернет 0 в случае успеха, иначе см. ErrorType 72 | */ 73 | inline int test(const T in) noexcept { 74 | if (std::isnan(last_data)) return common::NO_INIT; 75 | output_value = std::abs(in - last_data); 76 | return common::OK; 77 | } 78 | 79 | /** \brief Протестировать индикатор 80 | * 81 | * Данная функция отличается от update тем, 82 | * что не влияет на внутреннее состояние индикатора 83 | * \param in Сигнал на входе 84 | * \param out Сигнал на выходе 85 | * \return Вернет 0 в случае успеха, иначе см. ErrorType 86 | */ 87 | inline int test(const T in, T &out) noexcept { 88 | const int err = test(in); 89 | out = output_value; 90 | return err; 91 | } 92 | 93 | /** \brief Получить значение индикатора 94 | * \return Значение индикатора 95 | */ 96 | inline T get() const noexcept { 97 | return output_value; 98 | } 99 | 100 | /** \brief Очистить данные индикатора 101 | */ 102 | inline void clear() noexcept { 103 | output_value = std::numeric_limits::quiet_NaN(); 104 | last_data = std::numeric_limits::quiet_NaN(); 105 | } 106 | }; // TrueRange 107 | 108 | }; // xtechnical 109 | 110 | #endif // XTECHNICAL_TRUE_RANGE_HPP_INCLUDED 111 | -------------------------------------------------------------------------------- /include/math/xtechnical_compare.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_COMPARE_HPP_INCLUDED 2 | #define XTECHNICAL_COMPARE_HPP_INCLUDED 3 | 4 | namespace xtechnical { 5 | 6 | /** \brief Сравнение двух переменных с плавающей точкой 7 | * \param x Первая переменная 8 | * \param y Вторая переменная 9 | * \return Вернет true, если две переменные ранвы 10 | */ 11 | template 12 | bool combined_tolerance_compare(const T x, const T y) { 13 | double maxXYOne = std::max( { 1.0, std::fabs(x) , std::fabs(y) } ) ; 14 | return std::fabs(x - y) <= std::numeric_limits::epsilon() * maxXYOne; 15 | } 16 | } 17 | 18 | #endif // XTECHNICAL_COMPARE_HPP_INCLUDED 19 | -------------------------------------------------------------------------------- /include/math/xtechnical_ordinary_least_squares.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_ORDINARY_LEAST_SQUARES_HPP_INCLUDED 2 | #define XTECHNICAL_ORDINARY_LEAST_SQUARES_HPP_INCLUDED 3 | 4 | namespace xtechnical { 5 | 6 | enum class OlsFunctionType { 7 | LINE = 0, /**< Y = A1*X + A0 */ 8 | PARABOLA = 1, /**< Y = A2*X^2 + A1*X + A0 */ 9 | }; 10 | 11 | /** \brief Метод наименьших квадратов 12 | * Определение коэффициентов линейной аппроксимации по МНК 13 | * С помощью данной функции можно найти коэффициенты для функций 14 | * Y = A1*X + A0 или Y = A2*X^2 + A1*X + A0 15 | * \param x Массив точек X 16 | * \param y Массив точек Y 17 | * \param type_line Тип линии 18 | * \param coeff Массив коэффициентов (2 либо 3 коэффициента) 19 | */ 20 | template 21 | void calc_ols(const T1 &x, const T1 &y, const OlsFunctionType type_line, T2& coeff) { 22 | if(type_line == OlsFunctionType::LINE) { 23 | double sx = 0, sy = 0, sx2 = 0, sxy = 0; 24 | for (size_t i = 0; i < x.size(); ++i) { 25 | sx += x[i]; 26 | sy += y[i]; 27 | sx2 += x[i] * x[i]; 28 | sxy += x[i] * y[i]; 29 | } 30 | //coeff.resize(2); 31 | coeff[1] = ((double)x.size() * sxy - (sx * sy)) / ((double)x.size() * sx2 - sx * sx); 32 | coeff[0] = (sy - coeff[0] * sx) / (double)x.size(); 33 | } else 34 | if(type_line == OlsFunctionType::PARABOLA) { 35 | double sx = 0, sy = 0, sx2 = 0, sx3 = 0, sx4 = 0, sxy = 0, sx2y = 0; 36 | for (size_t i = 0; i < x.size(); ++i) { 37 | sx += x[i]; 38 | sy += y[i]; 39 | double m2 = x[i] * x[i]; 40 | double m3 = m2 * x[i]; 41 | sx2 += m2; 42 | sx3 += m3; 43 | sx4 += m3 * x[i]; 44 | double mxy = x[i] * y[i]; 45 | sxy += mxy; 46 | sx2y += x[i] * mxy; 47 | } 48 | double sxsx2 = sx*sx2; 49 | double sxsx4 = sx*sx4; 50 | double sx2sx2 = sx2*sx2; 51 | double sx2sx3 = sx2*sx3; 52 | double sxsx3 = sx*sx3; 53 | double nsx3 = (double)x.size()*sx3; 54 | /* найдем определитель матрицы 55 | * n sx sx2 56 | * sx sx2 sx3 57 | * sx2 sx3 sx4 58 | */ 59 | double A = (double)x.size() * (sx2 * sx4 - sx3 * sx3) - sx* (sx * sx4 - sx2 * sx3) + sx2 * (sx * sx3 - sx2 * sx2); 60 | A = 1.0/A; 61 | /* найдем транспонированную матрицу, она будет такой же 62 | * n sx sx2 63 | * sx sx2 sx3 64 | * sx2 sx3 sx4 65 | * далее найдем определитель для матриц 2 x 2 и применим матрицу кофакторов 66 | * sx2*sx4-sx3*sx3 sx2*sx3-sx*sx4 sx*sx3-sx2*sx2 67 | * sx3*sx2-sx*sx4 n*sx4-sx2*sx2 sx*sx2-n*sx3 68 | * sx*sx3-sx2*sx2 sx*sx2-n*sx3 n*sx2-sx*sx 69 | * далее каждый элемент надо делить на определитель 70 | */ 71 | //coeff.resize(3); 72 | coeff[0] = A * ((sx2*sx4 - sx3*sx3) * sy + (sx2sx3 - sxsx4) * sxy + (sxsx3 - sx2sx2) * sx2y); 73 | coeff[1] = A * ((sx2sx3 - sxsx4) * sy + ((double)x.size()*sx4 - sx2sx2) * sxy + (sxsx2 - nsx3) * sx2y); 74 | coeff[2] = A * ((sxsx3 - sx2sx2) * sy + (sxsx2 - nsx3) * sxy + ((double)x.size()*sx2 - sx*sx) * sx2y); 75 | } 76 | } 77 | 78 | template 79 | T2 calc_ols_line(const T1& coeff, const T2 x) { 80 | if(coeff.size() == 2) { 81 | return coeff[1] * x + coeff[0]; 82 | } else 83 | if(coeff.size() == 3) { 84 | return coeff[2] * x * x + coeff[1] * x + coeff[0]; 85 | } 86 | return 0; 87 | } 88 | 89 | }; 90 | 91 | #endif // XTECHNICAL_ORDINARY_LEAST_SQUARES_HPP_INCLUDED 92 | -------------------------------------------------------------------------------- /include/math/xtechnical_smoothing.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_SMOOTHING_HPP_INCLUDED 2 | #define XTECHNICAL_SMOOTHING_HPP_INCLUDED 3 | 4 | #include "xtechnical_ordinary_least_squares.hpp" 5 | #include "../indicators/xtechnical_sma.hpp" 6 | #include "../indicators/xtechnical_rsi.hpp" 7 | 8 | namespace xtechnical { 9 | 10 | enum class SmoothingType { 11 | LINE = 0, 12 | PARABOLA = 1, 13 | }; 14 | 15 | template 16 | void smoothing(const SmoothingType type, const T &input, T &output) { 17 | switch(type) { 18 | case SmoothingType::LINE: { 19 | auto temp(input); 20 | std::iota(temp.begin(), temp.end(), 0); 21 | std::vector coeff(2); 22 | calc_ols(temp, input, OlsFunctionType::LINE, coeff); 23 | for (size_t i = 0; i < input.size(); ++i) output[i] = calc_ols_line(coeff, i); 24 | } 25 | break; 26 | case SmoothingType::PARABOLA: { 27 | auto temp(input); 28 | std::iota(temp.begin(), temp.end(), 0); 29 | std::vector coeff(3); 30 | calc_ols(temp, input, OlsFunctionType::PARABOLA, coeff); 31 | for (size_t i = 0; i < input.size(); ++i) output[i] = calc_ols_line(coeff, i); 32 | } 33 | break; 34 | default: 35 | break; 36 | }; 37 | } 38 | 39 | template 40 | void smoothing_cycle_sma(const size_t period, const size_t offset, const T1 &input, T2 &output) { 41 | using NumType = typename T2::value_type; 42 | SMA ma(period); 43 | size_t index = 0; 44 | while (true) { 45 | if (!std::isnan(ma.get()) && index == (input.size() - offset)) break; 46 | ma.update(input[index++]); 47 | if (index >= input.size()) index = 0; 48 | } 49 | for (size_t i = 0; i < input.size(); ++i) { 50 | output[i] = ma.get(); 51 | ma.update(input[index++]); 52 | if (index >= input.size()) index = 0; 53 | } 54 | } 55 | 56 | /** \brief Посчитать простую скользящую среднюю (SMA) 57 | * 58 | * Данная функция для расчетов использует последние N = period значений 59 | * \param input Массив значений 60 | * \param output Значение SMA 61 | * \param period Период SMA 62 | * \param start_pos Начальная позиция в массиве 63 | * \return Вернет true в случае успеха 64 | */ 65 | template 66 | bool calculate_sma( 67 | T1 &input, 68 | T2 &output, 69 | const size_t period, 70 | const size_t start_pos = 0) noexcept { 71 | if(input.size() <= start_pos + period) return false; 72 | using NumType = typename T1::value_type; 73 | auto sum = std::accumulate( 74 | input.begin() + start_pos, 75 | input.begin() + start_pos + period, 76 | NumType(0)); 77 | output = sum / (T2)period; 78 | return true; 79 | } 80 | 81 | /** \brief Заполнить буфер средним значением данных 82 | * \param input Массив значений 83 | * \param output Массив средних значений 84 | * \param period Период SMA 85 | * \param start_pos Начальная позиция в массиве 86 | * \return Вернет true в случае успеха 87 | */ 88 | template 89 | bool fill_sma( 90 | T1 &input, 91 | T2 &output, 92 | const size_t period, 93 | const size_t start_pos = 0) noexcept { 94 | using NumType = typename T2::value_type; 95 | NumType mean = 0; 96 | if (!calculate_sma(input, mean, period, start_pos)) return false; 97 | std::fill(output.begin(),output.end(), mean); 98 | return true; 99 | } 100 | 101 | /** \brief Расчитать стандартное отклонение 102 | * \param input входные данные индикатора 103 | * \param output стандартное отклонение 104 | * \param period период STD 105 | * \param start_pos начальная позиция в массиве 106 | * \return вернет 0 в случае успеха 107 | */ 108 | template 109 | bool calculate_std_dev( 110 | T1 &input, 111 | T2 &output, 112 | const size_t period, 113 | const size_t start_pos = 0) noexcept { 114 | if(input.size() < start_pos + period) return false; 115 | using NumType = typename T1::value_type; 116 | auto mean = std::accumulate( 117 | input.begin() + start_pos, 118 | input.begin() + start_pos + period, 119 | NumType(0)); 120 | mean /= (NumType)period; 121 | double _std_dev = 0; 122 | for(int i = 0; i < (int)input.size(); i++) { 123 | double diff = (input[i] - mean); 124 | _std_dev += diff * diff; 125 | } 126 | output = std::sqrt(_std_dev / (T2)(period - 1)); 127 | return true; 128 | } 129 | 130 | /** \brief Расчитать стандартное отклонение и среднее значение 131 | * \param input входные данные индикатора 132 | * \param output стандартное отклонение 133 | * \param period период STD 134 | * \param start_pos начальная позиция в массиве 135 | * \return вернет 0 в случае успеха 136 | */ 137 | template 138 | bool calculate_std_dev_and_mean( 139 | T1 &input, 140 | T2 &std_dev, 141 | T2 &mean, 142 | const size_t period, 143 | const size_t start_pos = 0) { 144 | if(input.size() < start_pos + period) return false; 145 | using NumType = typename T1::value_type; 146 | mean = (T2)std::accumulate( 147 | input.begin() + start_pos, 148 | input.begin() + start_pos + period, 149 | NumType(0)); 150 | mean /= (NumType)period; 151 | double _std_dev = 0; 152 | for(int i = 0; i < (int)input.size(); i++) { 153 | double diff = (input[i] - mean); 154 | _std_dev += diff * diff; 155 | } 156 | std_dev = std::sqrt(_std_dev / (T2)(period - 1)); 157 | return true; 158 | } 159 | 160 | 161 | template 162 | bool calc_ring_rsi(const T1 &in, T2 &out, const size_t &period) { 163 | size_t input_size = in.size(); 164 | size_t output_size = out.size(); 165 | if( input_size == 0 || input_size < period || 166 | output_size != input_size) 167 | return false; 168 | using NumType = typename T1::value_type; 169 | RSI> iRSI(period); 170 | for(size_t i = input_size - period; i < input_size; ++i) { 171 | iRSI.update(in[i]); 172 | } 173 | for(size_t i = 0; i < input_size; ++i) { 174 | iRSI.update(in[i], out[i]); 175 | } 176 | return true; 177 | } 178 | } 179 | 180 | #endif // XTECHNICAL_SMOOTHING_HPP_INCLUDED 181 | -------------------------------------------------------------------------------- /include/xtechnical_circular_buffer.mqh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewYaroslav/xtechnical_analysis/9e24d06f904a76a6d3e2e5403a9f7910d65e9817/include/xtechnical_circular_buffer.mqh -------------------------------------------------------------------------------- /include/xtechnical_common.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * xtechnical_analysis - Technical analysis C++ library 3 | * 4 | * Copyright (c) 2018 Elektro Yar. Email: git.electroyar@gmail.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef XTECHNICAL_COMMON_HPP_INCLUDED 25 | #define XTECHNICAL_COMMON_HPP_INCLUDED 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | namespace xtechnical { 39 | namespace common { 40 | const double NAN_DATA = std::numeric_limits::quiet_NaN(); 41 | 42 | enum class PriceType { 43 | IntraBar, 44 | Close, 45 | }; 46 | 47 | /// Набор возможных состояний ошибки 48 | enum { 49 | OK = 0, ///< Ошибок нет, все в порядке 50 | NO_INIT = -1, ///< Не было инициализации, поэтому метод класса не может быть использован 51 | INVALID_PARAMETER = -2, ///< Один из параметров неверно указан 52 | INDICATOR_NOT_READY_TO_WORK = -3, ///< Индикатор не готов к работе 53 | }; 54 | 55 | /// Типы нормализации данных 56 | enum { 57 | MINMAX_UNSIGNED = 0, ///< Нормализация данных. Данные приводятся к уровню от 0 до 1 58 | MINMAX_SIGNED = 1, ///< Нормализация данных. Данные приводятся к уровню от -1 до 1 59 | Z_SCORE_TRANSFORMING = 2, ///< Стандартизация данных. Преобразование данных с использованием z-показателя 60 | }; 61 | 62 | enum { 63 | COMPARE_WITH_ZERO_LINE = 0, 64 | COMPARE_WITH_STRAIGHT_LINE = 1, 65 | COMPARE_WITH_CENTER_LINE = 2, 66 | CALCULATE_ANGLE = 3, 67 | }; 68 | 69 | enum { 70 | BUY = 1, 71 | SELL = -1, 72 | }; 73 | 74 | }; // common 75 | }; // xtechnical 76 | 77 | #endif // XTECHNICAL_COMMON_HPP_INCLUDED 78 | -------------------------------------------------------------------------------- /include/xtechnical_normalization.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * xtechnical_analysis - Technical analysis C++ library 3 | * 4 | * Copyright (c) 2018 Elektro Yar. Email: git.electroyar@gmail.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef XTECHNICAL_NORMALIZATION_HPP_INCLUDED 25 | #define XTECHNICAL_NORMALIZATION_HPP_INCLUDED 26 | 27 | #include "xtechnical_common.hpp" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | namespace xtechnical { 35 | namespace normalization { 36 | 37 | /** \brief MinMax нормализация данных 38 | * \param in входные данные для нормализации 39 | * \param out нормализованный вектор 40 | * \param type тип нормализации (0 - нормализация данных к промежутку от 0 до 1, иначе от -1 до 1) 41 | * \return вернет 0 в случае успеха, иначе см. xtechnical_common.hpp 42 | */ 43 | template 44 | int calculate_min_max(const T1 &in, T2 &out, const int &type) { 45 | size_t input_size = in.size(); 46 | size_t output_size = out.size(); 47 | if(input_size == 0 || output_size != input_size) return common::INVALID_PARAMETER; 48 | auto it_max_data = std::max_element(in.begin(), in.end()); 49 | auto it_min_data = std::min_element(in.begin(), in.end()); 50 | auto max_data = in[0]; 51 | auto min_data = in[0]; 52 | if(it_max_data != in.end() && it_min_data != in.end()) { 53 | max_data = *it_max_data; 54 | min_data = *it_min_data; 55 | } 56 | auto ampl = max_data - min_data; 57 | if(ampl != 0) { 58 | for(size_t i = 0; i < input_size; i++) { 59 | out[i] = type == 0 ? (double)(in[i] - min_data) / ampl : 2.0 * ((double)(in[i] - min_data) / ampl) - 1.0; 60 | } 61 | } else { 62 | std::fill(out.begin(), out.end(),0); 63 | } 64 | return common::OK; 65 | } 66 | 67 | /** \brief MinMax нормализация данных 68 | * \param in входные данные для нормализации 69 | * \param out нормализованный вектор 70 | * \param min_value минимальное значение 71 | * \param max_value максимальное значение 72 | * \param type тип нормализации (0 - нормализация данных к промежутку от 0 до 1, иначе от -1 до 1) 73 | * \return вернет 0 в случае успеха, иначе см. xtechnical_common.hpp 74 | */ 75 | template 76 | int calculate_min_max(const T1 &in, T2 &out, const T3 min_value, const T3 max_value, const int &type) { 77 | size_t input_size = in.size(); 78 | size_t output_size = out.size(); 79 | if(input_size == 0 || output_size != input_size) return common::INVALID_PARAMETER; 80 | auto it_max_data = std::max_element(in.begin(), in.end()); 81 | auto it_min_data = std::min_element(in.begin(), in.end()); 82 | auto max_data = in[0]; 83 | auto min_data = in[0]; 84 | if(it_max_data != in.end() && it_min_data != in.end()) { 85 | max_data = *it_max_data; 86 | min_data = *it_min_data; 87 | } 88 | using NumType = typename T1::value_type; 89 | min_data = (NumType)std::min((NumType)min_value, (NumType)min_data); 90 | max_data = (NumType)std::max((NumType)max_value, (NumType)max_data); 91 | auto ampl = max_data - min_data; 92 | if(ampl != 0) { 93 | for(size_t i = 0; i < input_size; i++) { 94 | out[i] = type == 0 ? (double)(in[i] - min_data) / ampl : 2.0 * ((double)(in[i] - min_data) / ampl) - 1.0; 95 | } 96 | } else { 97 | std::fill(out.begin(), out.end(),0); 98 | } 99 | return common::OK; 100 | } 101 | 102 | /** \brief Z-Score нормализация данных 103 | * \param in Входные данные для нормализации 104 | * \param out Нормализованный вектор 105 | * \param d Множитель для стандартного отклонения 106 | * \param t Ограничитель размера z-score 107 | * \return вернет 0 в случае успеха, иначе см. xtechnical_common.hpp 108 | */ 109 | template 110 | int calculate_zscore(const T1 &in, T2 &out, const double d = 1.0, const double t = 1) { 111 | size_t input_size = in.size(); 112 | size_t output_size = out.size(); 113 | if(input_size == 0 || output_size != input_size) return common::INVALID_PARAMETER; 114 | using NumType = typename T1::value_type; 115 | auto mean = std::accumulate(in.begin(), in.end(), NumType(0)); 116 | mean /= (NumType)input_size; 117 | auto diff = 0; 118 | for(size_t k = 0; k < input_size; ++k) { 119 | diff += ((in[k] - mean) * (in[k] - mean)); 120 | } 121 | 122 | auto std_dev = diff > 0 ? std::sqrt(diff / (NumType)(input_size - 1)) : 0.0; 123 | 124 | double dix = d * std_dev; 125 | for(size_t k = 0; k < input_size; ++k) { 126 | out[k] = dix != 0 ? (in[k] - mean) / dix : 0.0; 127 | if(out[k] > t) out[k] = t; 128 | if(out[k] < -t) out[k] = -t; 129 | } 130 | return common::OK; 131 | } 132 | 133 | /** \brief Посчитать массив разности элементов 134 | * \param in входные данные для подсчета разницы 135 | * \param out массив с разностью элементов 136 | * \return вернет 0 в случае успеха, иначе см. xtechnical_common.hpp 137 | */ 138 | template 139 | int calculate_difference(const T1 &in, T2 &out) { 140 | size_t input_size = in.size(); 141 | size_t output_size = out.size(); 142 | if(input_size < 2 || output_size < (input_size - 1)) return common::INVALID_PARAMETER; 143 | for(size_t i = 1; i < input_size; i++) { 144 | out[i - 1] = in[i] - in[i - 1]; 145 | } 146 | return common::OK; 147 | } 148 | 149 | /** \brief Нормализовать амплитуду 150 | * \param in входные данные 151 | * \param out обработанные данные 152 | * \param max_amplitude максимальная амплитуда 153 | * \return вернет 0 в случае успеха, иначе см. xtechnical_common.hpp 154 | */ 155 | template 156 | int normalize_amplitudes(const T1 &in, T2 &out, const T3 &max_amplitude) { 157 | size_t input_size = in.size(); 158 | size_t output_size = out.size(); 159 | 160 | if(input_size == 0 || output_size != input_size) { 161 | return common::INVALID_PARAMETER; 162 | } 163 | 164 | auto max_data = *std::max_element(in.begin(), in.end()); 165 | auto min_data = *std::min_element(in.begin(), in.end()); 166 | auto max_data_ampl = std::max(abs(min_data),abs(max_data)); 167 | if(max_data_ampl == 0) return common::OK; 168 | auto coeff = max_amplitude/max_data_ampl; 169 | for(size_t i = 0; i < input_size; i++) { 170 | out[i] = coeff * in[i]; 171 | } 172 | return common::OK; 173 | } 174 | 175 | /** \brief Логарифм от данных 176 | * \param in входные данные 177 | * \param out обработанные данные 178 | * \return вернет 0 в случае успеха, иначе см. xtechnical_common.hpp 179 | */ 180 | template 181 | int calculate_log(const T1 &in, T2 &out) { 182 | size_t input_size = in.size(); 183 | size_t output_size = out.size(); 184 | if(input_size == 0 || output_size != input_size) return common::INVALID_PARAMETER; 185 | for(size_t i = 0; i < input_size; i++) { 186 | out[i] = std::log(in[i]); 187 | } 188 | return common::OK; 189 | } 190 | 191 | /** \brief Посчитать автоматическую регулировку усиления 192 | * Данная функция может произвести регулировку усиления сигнала в массиве при помощи 193 | * указанного индикатора. Советую использовать ФНЧ. 194 | * \param in входные данные 195 | * \param out обработанные данные 196 | * \param period период индикатора 197 | * \param is_looped использовать зацикленный сигнал 198 | * \return вернет 0 в случае успеха, иначе см. xtechnical_common.hpp 199 | */ 200 | template 201 | int calc_automatic_gain_control(const T2 &in, T2 &out, const size_t &period, const bool &is_looped = true) { 202 | size_t input_size = in.size(); 203 | size_t output_size = out.size(); 204 | if(input_size == 0 || output_size != input_size || period > input_size) return common::INVALID_PARAMETER; 205 | using NumType = typename T2::value_type; 206 | T1 filter(period); 207 | if(is_looped) { 208 | for(size_t i = input_size - period; i < input_size; ++i) { 209 | filter.update(in[i]); 210 | } 211 | } 212 | for(size_t i = 0; i < input_size; ++i) { 213 | NumType temp = 0; 214 | filter.update(in[i], temp); 215 | out[i] = in[i]/temp; 216 | } 217 | return common::OK; 218 | } 219 | }; // normalization 220 | }; // xtechnical 221 | 222 | #endif // XTECHNICAL_NORMALIZATION_HPP_INCLUDED 223 | -------------------------------------------------------------------------------- /include/xtechnical_regression_analysis.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_REGRESSION_ANALYSIS_HPP_INCLUDED 2 | #define XTECHNICAL_REGRESSION_ANALYSIS_HPP_INCLUDED 3 | 4 | namespace xtechnical_regression_analysis { 5 | 6 | enum LeastSquaresMethodType { 7 | LSM_LINE = 0, /**< Y = A1*X + A0 */ 8 | LSM_PARABOLA = 1, /**< Y = A2*X^2 + A1*X + A0 */ 9 | }; 10 | 11 | /** \brief Метод наименьших квадратов 12 | * Определение коэффициентов линейной аппроксимации по МНК 13 | * С помощью данной функции можно найти коэффициенты для функций 14 | * Y = A1*X + A0 или Y = A2*X^2 + A1*X + A0 15 | * \param coeff массив коэффициентов (2 либо 3 коэффициента) 16 | * \param point двумерный массив точек 17 | * \param type тип линии 18 | */ 19 | template 20 | void calc_least_squares_method(T2& coeff, const T1& point, const uint32_t &type) { 21 | if(type == LSM_LINE) { 22 | double sx = 0, sy = 0, sx2 = 0, sxy = 0; 23 | size_t size_point = point.size(); 24 | for(size_t i = 0; i < size_point; ++i) { 25 | sx += point[i].x; 26 | sy += point[i].y; 27 | sx2 += point[i].x * point[i].x; 28 | sxy += point[i].x * point[i].y; 29 | } 30 | //coeff.resize(2); 31 | coeff[1] = ((double)size_point * sxy - (sx * sy)) / ((double)size_point * sx2 - sx * sx); 32 | coeff[0] = (sy - coeff[0] * sx) / (double)size_point; 33 | } else 34 | if(type == LSM_PARABOLA) { 35 | double sx = 0, sy = 0, sx2 = 0, sx3 = 0, sx4 = 0, sxy = 0, sx2y = 0; 36 | size_t size_point = point.size(); 37 | for(size_t i = 0; i < size_point; ++i) { 38 | sx += point[i].x; 39 | sy += point[i].y; 40 | double m2 = point[i].x * point[i].x; 41 | double m3 = m2 * point[i].x; 42 | sx2 += m2; 43 | sx3 += m3; 44 | sx4 += m3 * point[i].x; 45 | double mxy = point[i].x * point[i].y; 46 | sxy += mxy; 47 | sx2y += point[i].x * mxy; 48 | } 49 | double sxsx2 = sx*sx2; 50 | double sxsx4 = sx*sx4; 51 | double sx2sx2 = sx2*sx2; 52 | double sx2sx3 = sx2*sx3; 53 | double sxsx3 = sx*sx3; 54 | double nsx3 = (double)size_point*sx3; 55 | /* найдем определитель матрицы 56 | * n sx sx2 57 | * sx sx2 sx3 58 | * sx2 sx3 sx4 59 | */ 60 | double A = (double)size_point * (sx2 * sx4 - sx3 * sx3) - sx* (sx * sx4 - sx2 * sx3) + sx2 * (sx * sx3 - sx2 * sx2); 61 | A = 1.0/A; 62 | /* найдем транспонированную матрицу, она будет такой же 63 | * n sx sx2 64 | * sx sx2 sx3 65 | * sx2 sx3 sx4 66 | * далее найдем определитель для матриц 2 x 2 и применим матрицу кофакторов 67 | * sx2*sx4-sx3*sx3 sx2*sx3-sx*sx4 sx*sx3-sx2*sx2 68 | * sx3*sx2-sx*sx4 n*sx4-sx2*sx2 sx*sx2-n*sx3 69 | * sx*sx3-sx2*sx2 sx*sx2-n*sx3 n*sx2-sx*sx 70 | * далее каждый элемент надо делить на определитель 71 | */ 72 | //coeff.resize(3); 73 | coeff[0] = A * ((sx2*sx4 - sx3*sx3) * sy + (sx2sx3 - sxsx4) * sxy + (sxsx3 - sx2sx2) * sx2y); 74 | coeff[1] = A * ((sx2sx3 - sxsx4) * sy + ((double)size_point*sx4 - sx2sx2) * sxy + (sxsx2 - nsx3) * sx2y); 75 | coeff[2] = A * ((sxsx3 - sx2sx2) * sy + (sxsx2 - nsx3) * sxy + ((double)size_point*sx2 - sx*sx) * sx2y); 76 | } 77 | } 78 | 79 | /** \brief Метод наименьших квадратов 80 | * Определение коэффициентов линейной аппроксимации по МНК 81 | * С помощью данной функции можно найти коэффициенты для функций 82 | * Y = A1*X + A0 или Y = A2*X^2 + A1*X + A0 83 | * \param coeff массив коэффициентов (2 либо 3 коэффициента) 84 | * \param array_point двумерный массив точек 85 | * \param array_size размер массива 86 | * \param type тип линии 87 | */ 88 | template 89 | void calc_least_squares_method(T2& coeff, const T1& array_point, const size_t array_size, const uint32_t &type) { 90 | if(type == LSM_LINE) { 91 | double sx = 0, sy = 0, sx2 = 0, sxy = 0; 92 | for(size_t i = 0; i < array_size; ++i) { 93 | sx += array_point[i][0]; 94 | sy += array_point[i][1]; 95 | sx2 += array_point[i][0] * array_point[i][0]; 96 | sxy += array_point[i][0] * array_point[i][1]; 97 | } 98 | //coeff.resize(2); 99 | coeff[1] = ((double)array_size * sxy - (sx * sy)) / ((double)array_size * sx2 - sx * sx); 100 | coeff[0] = (sy - coeff[0] * sx) / (double)array_size; 101 | } else 102 | if(type == LSM_PARABOLA) { 103 | double sx = 0, sy = 0, sx2 = 0, sx3 = 0, sx4 = 0, sxy = 0, sx2y = 0; 104 | for(size_t i = 0; i < array_size; ++i) { 105 | sx += array_point[i][0]; 106 | sy += array_point[i][1]; 107 | double m2 = array_point[i][0] * array_point[i][0]; 108 | double m3 = m2 * array_point[i][0]; 109 | sx2 += m2; 110 | sx3 += m3; 111 | sx4 += m3 * array_point[i][0]; 112 | double mxy = array_point[i][0] * array_point[i][1]; 113 | sxy += mxy; 114 | sx2y += array_point[i][0] * mxy; 115 | } 116 | double sxsx2 = sx*sx2; 117 | double sxsx4 = sx*sx4; 118 | double sx2sx2 = sx2*sx2; 119 | double sx2sx3 = sx2*sx3; 120 | double sxsx3 = sx*sx3; 121 | double nsx3 = (double)array_size*sx3; 122 | /* найдем определитель матрицы 123 | * n sx sx2 124 | * sx sx2 sx3 125 | * sx2 sx3 sx4 126 | */ 127 | double A = (double)array_size * (sx2 * sx4 - sx3 * sx3) - sx* (sx * sx4 - sx2 * sx3) + sx2 * (sx * sx3 - sx2 * sx2); 128 | A = 1.0/A; 129 | /* найдем транспонированную матрицу, она будет такой же 130 | * n sx sx2 131 | * sx sx2 sx3 132 | * sx2 sx3 sx4 133 | * далее найдем определитель для матриц 2 x 2 и применим матрицу кофакторов 134 | * sx2*sx4-sx3*sx3 sx2*sx3-sx*sx4 sx*sx3-sx2*sx2 135 | * sx3*sx2-sx*sx4 n*sx4-sx2*sx2 sx*sx2-n*sx3 136 | * sx*sx3-sx2*sx2 sx*sx2-n*sx3 n*sx2-sx*sx 137 | * далее каждый элемент надо делить на определитель 138 | */ 139 | //coeff.resize(3); 140 | coeff[0] = A * ((sx2*sx4 - sx3*sx3) * sy + (sx2sx3 - sxsx4) * sxy + (sxsx3 - sx2sx2) * sx2y); 141 | coeff[1] = A * ((sx2sx3 - sxsx4) * sy + ((double)array_size*sx4 - sx2sx2) * sxy + (sxsx2 - nsx3) * sx2y); 142 | coeff[2] = A * ((sxsx3 - sx2sx2) * sy + (sxsx2 - nsx3) * sxy + ((double)array_size*sx2 - sx*sx) * sx2y); 143 | } 144 | } 145 | 146 | template 147 | T2 calc_line(const T1& coeff, const T2 &x, const uint32_t &type) { 148 | if(type == LSM_LINE) { 149 | return coeff[1] * x + coeff[0]; 150 | } else 151 | if(type == LSM_PARABOLA) { 152 | return coeff[2] * x * x + coeff[1] * x + coeff[0]; 153 | } 154 | return 0; 155 | } 156 | } 157 | 158 | #endif // XTECHNICAL_REGRESSION_ANALYSIS_HPP_INCLUDED 159 | -------------------------------------------------------------------------------- /include/xtechnical_sma.mqh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewYaroslav/xtechnical_analysis/9e24d06f904a76a6d3e2e5403a9f7910d65e9817/include/xtechnical_sma.mqh -------------------------------------------------------------------------------- /include/xtechnical_streaming_min_max.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XTECHNICAL_STREAMING_MIN_MAX_HPP_INCLUDED 2 | #define XTECHNICAL_STREAMING_MIN_MAX_HPP_INCLUDED 3 | 4 | #include 5 | 6 | namespace xtechnical { 7 | 8 | /** \brief Streaming Maximum-Minimum Filter Using No More than Three Comparsions per Element. 9 | * URL: https://zelych.livejournal.com/2692.html 10 | * URL: https://arxiv.org/abs/cs/0610046v5 11 | * URL: https://arxiv.org/pdf/cs/0610046v5.pdf 12 | * \param a Input array 13 | * \param minval Output array 14 | * \param maxval Output array 15 | * \param w Window length 16 | */ 17 | template 18 | void streaming_maximum_minimum_filter(T &a, T &minval, T &maxval, const size_t w) { 19 | std::deque U, L; 20 | for (size_t i = 1; i < a.size(); ++i) { 21 | if (i >= w) { 22 | maxval[i - w] = a[U.size() > 0 ? U.front() : i - 1]; 23 | minval[i - w] = a[L.size() > 0 ? L.front() : i - 1]; 24 | } // end if 25 | if (a[i] > a[i - 1]) { 26 | L.push_back(i - 1); 27 | if (i == w + L.front()) L.pop_front(); 28 | while (U.size() > 0) { 29 | if (a[i] <= a[U.back()]) { 30 | if (i == w + U.front()) U.pop_front(); 31 | break; 32 | } // end if 33 | U.pop_back(); 34 | } // end while 35 | } else { 36 | U.push_back(i - 1) ; 37 | if (i == w + U.front()) U.pop_front(); 38 | while (L.size() > 0) { 39 | if (a[i] >= a[L.back()]) { 40 | if (i == w + L.front()) L.pop_front(); 41 | break; 42 | } // end if 43 | L.pop_back(); 44 | } // end while 45 | } // end if else 46 | } // end for 47 | maxval[a.size() - w] = a[U.size() > 0 ? U.front() : a.size() - 1]; 48 | minval[a.size() - w] = a[L.size() > 0 ? L.front() : a.size() - 1]; 49 | } 50 | 51 | /** \brief Streaming Maximum-Minimum Filter Using No More than Three Comparsions per Element. 52 | * URL: https://zelych.livejournal.com/2692.html 53 | * URL: https://arxiv.org/abs/cs/0610046v5 54 | * URL: https://arxiv.org/pdf/cs/0610046v5.pdf 55 | * \param window Input array 56 | * \param minval Output value 57 | * \param maxval Output value 58 | */ 59 | template 60 | void streaming_maximum_minimum_filter(T &window, T2 &minval, T2 &maxval) { 61 | std::deque U, L; 62 | const size_t w = window.size(); 63 | for (size_t i = 1; i < w; ++i) { 64 | if (window[i] > window[i - 1]) { 65 | L.push_back(i - 1) ; 66 | if (i == w + L.front()) L.pop_front(); 67 | while (U.size() > 0) { 68 | if (window[i] <= window[U.back()]) { 69 | if (i == w + U.front()) U.pop_front(); 70 | break; 71 | } // end if 72 | U.pop_back(); 73 | } // end while 74 | } else { 75 | U.push_back(i - 1); 76 | if (i == w + U.front()) U.pop_front(); 77 | while (L.size() > 0) { 78 | if (window[i] >= window[L.back()]) { 79 | if (i == w + L.front()) L.pop_front(); 80 | break; 81 | } // end if 82 | L.pop_back(); 83 | } // end while 84 | } // end if else 85 | } // end for 86 | maxval = window[U.size() > 0 ? U.front() : w - 1]; 87 | minval = window[L.size() > 0 ? L.front() : w - 1]; 88 | } 89 | 90 | template 91 | class StreamingMaximumMinimumFilter { 92 | private: 93 | T maxval = std::numeric_limits::quiet_NaN(), minval = std::numeric_limits::quiet_NaN(); 94 | T last_input = 0; 95 | int64_t period = 0; 96 | int64_t offset = 0; 97 | std::deque> U, L; 98 | public: 99 | StreamingMaximumMinimumFilter(const int64_t p) : period(p) {} 100 | 101 | void update(const T input) noexcept { 102 | if (offset == 0) { 103 | ++offset; 104 | last_input = input; 105 | return; 106 | } 107 | if (input > last_input) { 108 | L.push_back(std::make_pair(offset - 1, last_input)); 109 | if (offset == period + L.front().first) L.pop_front() ; 110 | while (U.size() > 0) { 111 | if (input <= U.back().second) { 112 | if (offset == period + U.front().first) U.pop_front(); 113 | break ; 114 | } // end if 115 | U.pop_back() ; 116 | } // end while 117 | } else { 118 | U.push_back(std::make_pair(offset - 1, last_input)) ; 119 | if (offset == period + U.front().first) U.pop_front() ; 120 | while (L.size() > 0) { 121 | if (input >= L.back().second) { 122 | if (offset == period + L.front().first) L.pop_front(); 123 | break ; 124 | } // end if 125 | L.pop_back(); 126 | } // end while 127 | } // end if else 128 | ++offset; 129 | if (offset >= period) { 130 | maxval = U.size() > 0 ? U.front().second : input; 131 | minval = L.size() > 0 ? L.front().second : input; 132 | } 133 | last_input = input; 134 | } 135 | 136 | inline T get_min() noexcept { 137 | return minval; 138 | } 139 | 140 | inline T get_max() noexcept { 141 | return maxval; 142 | } 143 | }; 144 | }; 145 | 146 | #endif // XTECHNICAL_STREAMING_MIN_MAX_HPP_INCLUDED 147 | --------------------------------------------------------------------------------