From 07e18043145f3d91c8ea7ec3ad41b3c905585277 Mon Sep 17 00:00:00 2001 From: Ethan Werner Date: Wed, 1 Jul 2026 09:42:39 +0400 Subject: initial commit: ts time series analysis library v0.1.0 - 354 financial and mathematical time-series indicators - Uniform C11 API with consistent function signatures - 349 passing tests with -Werror - Static and shared library builds - pkg-config integration - Python bindings - Fuzzing and sanitizer support - Security hardening flags --- lib/stochastic_momentum_index.c | 130 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 lib/stochastic_momentum_index.c (limited to 'lib/stochastic_momentum_index.c') diff --git a/lib/stochastic_momentum_index.c b/lib/stochastic_momentum_index.c new file mode 100644 index 0000000..5491c30 --- /dev/null +++ b/lib/stochastic_momentum_index.c @@ -0,0 +1,130 @@ +// Stochastic Momentum Index +// +// stochastic_momentum_index +// +// Stochastic Momentum Index +// +// +// +// Inputs: 4 +// Outputs: 2 +// Constants: 3 + + +#include +#include +#include "ts.h" + +typedef struct { + uint_t k1; + uint_t k2; + uint_t signal_period; +} ts_stochastic_momentum_index_params_t; + +ts_parameter_t const ts_stochastic_momentum_index_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 3, .params_size = sizeof(ts_stochastic_momentum_index_params_t) }; + +uint_t ts_stochastic_momentum_index_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_stochastic_momentum_index_params_t *)c)->k1 + ((ts_stochastic_momentum_index_params_t *)c)->k2 : 0 ); +} + +int ts_stochastic_momentum_index( + fp_t * const *y, uint_t y_n, + fp_t const * const *x, uint_t x_n, + uint_t n, ts_constant_t const *c +) +{ + TS_PROLOGUE( ts_stochastic_momentum_index_p ); + if ( !c ) return -1; + uint_t k1 = ((ts_stochastic_momentum_index_params_t *)c)->k1; + uint_t k2 = ((ts_stochastic_momentum_index_params_t *)c)->k2; + uint_t signal_period = ((ts_stochastic_momentum_index_params_t *)c)->signal_period; + if (k1 == 0 || k2 == 0) return -1; + + fp_t *midpoint = calloc(n, sizeof(fp_t)); + fp_t *deviation = calloc(n, sizeof(fp_t)); + if (!midpoint || !deviation) { free(midpoint); free(deviation); return -1; } + + for( uint_t i = 0; i < n; ++i ) + { + midpoint[i] = (ts_h(x, i) + ts_l(x, i)) / 2.0; + deviation[i] = ts_c(x, i) - midpoint[i]; + } + + fp_t *sma_dev = calloc(n, sizeof(fp_t)); + fp_t *sma_high = calloc(n, sizeof(fp_t)); + if (!sma_dev || !sma_high) { free(midpoint); free(deviation); free(sma_dev); free(sma_high); return -1; } + + uint_t start = k1 - 1; + + for( uint_t i = start; i < n; ++i ) + { + fp_t sum_dev = 0; + fp_t sum_high = 0; + + for( uint_t j = 0; j < k1; ++j ) + { + sum_dev += deviation[i - j]; + fp_t abs_dev = fabs(deviation[i - j]); + if( abs_dev > sum_high ) sum_high = abs_dev; + } + + sma_dev[i] = sum_dev / k1; + sma_high[i] = sum_high; + } + + uint_t start2 = start + k2 - 1; + + fp_t *smi = calloc(n, sizeof(fp_t)); + if (!smi) { free(midpoint); free(deviation); free(sma_dev); free(sma_high); free(smi); return -1; } + + for( uint_t i = start2; i < n; ++i ) + { + fp_t sum_sma_dev = 0; + fp_t sum_sma_high = 0; + + for( uint_t j = 0; j < k2; ++j ) + { + sum_sma_dev += sma_dev[i - j]; + sum_sma_high += sma_high[i - j]; + } + + sum_sma_dev /= k2; + sum_sma_high /= k2; + + if( sum_sma_high == 0 ) + smi[i] = 0; + else + smi[i] = (sum_sma_dev / sum_sma_high) * 100; + } + + fp_t sig_a = 2.0 / (signal_period + 1); + fp_t signal_ema = 0; + uint_t signal_init = 0; + + for (uint_t j = 0; j < n && j < start2; ++j) { y[0][j] = 0; y[1][j] = 0; } + for( uint_t i = start2; i < n; ++i ) + { + y[0][i] = smi[i]; + + if( !signal_init ) + { + signal_ema = smi[i]; + signal_init = 1; + } + else + { + signal_ema = signal_ema + sig_a * (smi[i] - signal_ema); + } + y[1][i] = signal_ema; + } + + free(midpoint); + free(deviation); + free(sma_dev); + free(sma_high); + free(smi); + return 0; +} + -- cgit v1.3.1