summaryrefslogtreecommitdiffstats
path: root/lib/stochastic_momentum_index.c
diff options
context:
space:
mode:
authorEthan Werner <mail@ethanwerner.com>2026-07-01 09:42:39 +0400
committerEthan Werner <mail@ethanwerner.com>2026-07-01 09:42:39 +0400
commit07e18043145f3d91c8ea7ec3ad41b3c905585277 (patch)
tree2bdeae46973f4bdfce263679a4008ac768011f28 /lib/stochastic_momentum_index.c
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
Diffstat (limited to 'lib/stochastic_momentum_index.c')
-rw-r--r--lib/stochastic_momentum_index.c130
1 files changed, 130 insertions, 0 deletions
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 <stdlib.h>
+#include <math.h>
+#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;
+}
+