diff options
| author | Ethan Werner <mail@ethanwerner.com> | 2026-07-01 09:42:39 +0400 |
|---|---|---|
| committer | Ethan Werner <mail@ethanwerner.com> | 2026-07-01 09:42:39 +0400 |
| commit | 07e18043145f3d91c8ea7ec3ad41b3c905585277 (patch) | |
| tree | 2bdeae46973f4bdfce263679a4008ac768011f28 /lib | |
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')
351 files changed, 20008 insertions, 0 deletions
diff --git a/lib/absolute_value.c b/lib/absolute_value.c new file mode 100644 index 0000000..10714b0 --- /dev/null +++ b/lib/absolute_value.c @@ -0,0 +1,40 @@ +// Absolute Value +// +// absolute_value - abs +// +// y[t] = abs( x[t] ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_absolute_value_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_absolute_value_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_absolute_value( + 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_absolute_value_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = fabs( x[0][i] ); + } + return 0; +} + diff --git a/lib/acceleration_bands.c b/lib/acceleration_bands.c new file mode 100644 index 0000000..776b990 --- /dev/null +++ b/lib/acceleration_bands.c @@ -0,0 +1,81 @@ +// Acceleration Bands +// +// acceleration_bands - acc_bands +// +// Upper: SMA of highest high over period k +// Middle: SMA of typical price over period k +// Lower: SMA of lowest low over period k +// +// Inputs: 4 (OHLCV) +// Outputs: 3 (Upper, Middle, Lower) +// Constants: 1 (period) + +#include <stdlib.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_acceleration_bands_params_t; + +ts_parameter_t const ts_acceleration_bands_p = { .n_inputs = 4, .n_outputs = 3, .n_constants = 1, .params_size = sizeof(ts_acceleration_bands_params_t) }; + +uint_t ts_acceleration_bands_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_acceleration_bands_params_t *)c)->k - 1 : 0 ); +} + +int ts_acceleration_bands( + 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_acceleration_bands_p ); + if ( !c ) return -1; + uint_t k = ((ts_acceleration_bands_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t *hh_r = malloc( n * sizeof( fp_t ) ); + fp_t *ll_r = malloc( n * sizeof( fp_t ) ); + fp_t *tp = malloc( n * sizeof( fp_t ) ); + if ( !hh_r || !ll_r || !tp ) { + free( hh_r ); free( ll_r ); free( tp ); + return -1; + } + + for ( uint_t i = 0; i < n; ++i ) + { + tp[i] = ( ts_h( x, i ) + ts_l( x, i ) + ts_c( x, i ) ) / 3.0; + fp_t hh = ts_h( x, i ); + fp_t ll = ts_l( x, i ); + for ( uint_t j = 1; j < k && i >= j; ++j ) + { + if ( ts_h( x, i - j ) > hh ) hh = ts_h( x, i - j ); + if ( ts_l( x, i - j ) < ll ) ll = ts_l( x, i - j ); + } + hh_r[i] = hh; + ll_r[i] = ll; + } + + for ( uint_t j = 0; j < n && j < k - 1; ++j ) { y[0][j] = 0; y[1][j] = 0; y[2][j] = 0; } + for ( uint_t i = k - 1; i < n; ++i ) + { + fp_t sum_hh = 0, sum_ll = 0, sum_tp = 0; + for ( uint_t j = 0; j < k; ++j ) + { + sum_hh += hh_r[i - j]; + sum_ll += ll_r[i - j]; + sum_tp += tp[i - j]; + } + y[0][i] = sum_hh / (fp_t)k; + y[1][i] = sum_tp / (fp_t)k; + y[2][i] = sum_ll / (fp_t)k; + } + + free( hh_r ); free( ll_r ); free( tp ); + return 0; +} + + + diff --git a/lib/acosh.c b/lib/acosh.c new file mode 100644 index 0000000..2335168 --- /dev/null +++ b/lib/acosh.c @@ -0,0 +1,41 @@ +// Hyperbolic Arccosine +// +// acosh - inverse hyperbolic cosine +// +// y[t] = acosh( x[t] ) if x[t] >= 1 +// y[t] = NAN if x[t] < 1 +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_acosh_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_acosh_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_acosh( + 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_acosh_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t v = x[0][i]; + y[0][i] = v >= 1.0 ? acosh( v ) : (fp_t)NAN; + } + return 0; +} + diff --git a/lib/ad.c b/lib/ad.c new file mode 100644 index 0000000..fd0e40e --- /dev/null +++ b/lib/ad.c @@ -0,0 +1,48 @@ +// Accumulation/Distribution Line +// +// ad - A/D +// +// Cumulative money flow: MF = ((C-L) - (H-C)) / (H-L) * V, AD = SUM(MF) +// +// Inputs: 5 (OHLCV) +// Outputs: 1 (AD Line) +// Constants: 0 + +#include "ts.h" + + +ts_parameter_t const ts_ad_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_ad_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_ad( + 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_ad_p ); + (void)c; + if( n == 0 ) return -1; + + fp_t hl0 = ts_h( x, 0 ) - ts_l( x, 0 ); + y[0][0] = hl0 != 0 + ? ( ( ts_c( x, 0 ) - ts_l( x, 0 ) ) - ( ts_h( x, 0 ) - ts_c( x, 0 ) ) ) / hl0 * ts_v( x, 0 ) + : 0; + + for( uint_t i = 1; i < n; ++i ) + { + fp_t hl = ts_h( x, i ) - ts_l( x, i ); + fp_t mf = hl != 0 + ? ( ( ts_c( x, i ) - ts_l( x, i ) ) - ( ts_h( x, i ) - ts_c( x, i ) ) ) / hl * ts_v( x, i ) + : 0; + y[0][i] = y[0][i - 1] + mf; + } + + return 0; +} + diff --git a/lib/ad_oscillator.c b/lib/ad_oscillator.c new file mode 100644 index 0000000..5021140 --- /dev/null +++ b/lib/ad_oscillator.c @@ -0,0 +1,67 @@ +// Accumulation/Distribution Oscillator +// +// ad_oscillator - ADX +// +// Difference between fast and slow EMA of the A/D line +// +// Inputs: 5 (OHLCV) +// Outputs: 1 (Oscillator) +// Constants: 2 (fast period, slow period) + +#include "ts.h" + +typedef struct { + fp_t fast; + fp_t slow; +} ts_ad_oscillator_params_t; + +ts_parameter_t const ts_ad_oscillator_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_ad_oscillator_params_t) }; + +uint_t ts_ad_oscillator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_ad_oscillator( + 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_ad_oscillator_p ); + if ( !c ) return -1; + if( n == 0 ) return -1; + + fp_t fast = ((ts_ad_oscillator_params_t *)c)->fast; + fp_t slow = ((ts_ad_oscillator_params_t *)c)->slow; + if (fast == 0 || slow == 0) return -1; + fp_t a_fast = 1.0 / fast; + fp_t a_slow = 1.0 / slow; + + fp_t hl = ts_h( x, 0 ) - ts_l( x, 0 ); + fp_t mf = hl != 0 + ? ( ( ts_c( x, 0 ) - ts_l( x, 0 ) ) - ( ts_h( x, 0 ) - ts_c( x, 0 ) ) ) / hl * ts_v( x, 0 ) + : 0; + fp_t ad = mf; + fp_t ema_f = ad; + fp_t ema_s = ad; + y[0][0] = 0; + + for( uint_t i = 1; i < n; ++i ) + { + hl = ts_h( x, i ) - ts_l( x, i ); + mf = hl != 0 + ? ( ( ts_c( x, i ) - ts_l( x, i ) ) - ( ts_h( x, i ) - ts_c( x, i ) ) ) / hl * ts_v( x, i ) + : 0; + ad += mf; + ema_f = ema_f + a_fast * ( ad - ema_f ); + ema_s = ema_s + a_slow * ( ad - ema_s ); + y[0][i] = ema_f - ema_s; + } + + return 0; +} + + + diff --git a/lib/addition.c b/lib/addition.c new file mode 100644 index 0000000..f5d0deb --- /dev/null +++ b/lib/addition.c @@ -0,0 +1,41 @@ +// Addition +// +// addition - add +// +// y[t] = x[0][t] + x[1][t] +// +// X_n - 2 +// Y_n - 1 +// C_n - 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_addition_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_addition_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_addition( + 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_addition_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] + x[1][i]; + } + return 0; +} + + + diff --git a/lib/adx.c b/lib/adx.c new file mode 100644 index 0000000..505732b --- /dev/null +++ b/lib/adx.c @@ -0,0 +1,84 @@ +// Adx +// +// adx +// +// Time series function +// +// See implementation +// +// Inputs: 4 +// Outputs: 4 +// Constants: 1 + + +#include <math.h> +#include <stdint.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_adx_params_t; + +ts_parameter_t const ts_adx_p = { .n_inputs = 4, .n_outputs = 4, .n_constants = 1, .params_size = sizeof(ts_adx_params_t) }; + +uint_t ts_adx_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_adx_params_t *)c)->k + 1 : 0 ); +} + +int ts_adx( + 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_adx_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_adx_params_t *)c)->k; + if (k == 0) return -1; + + fp_t ema_plus = 0, ema_minus = 0, ema_tr = 0; + fp_t prev_dx = 0; + + for( uint_t i = 1; i < n; ++i ) + { + fp_t hdmd = ts_h( x, i ) - ts_h( x, i - 1 ); + fp_t ldml = ts_l( x, i - 1 ) - ts_l( x, i ); + + fp_t plus_dm = hdmd > ldml && hdmd > 0 ? hdmd : 0; + fp_t minus_dm = ldml > hdmd && ldml > 0 ? ldml : 0; + + fp_t tr = fmax( ts_h( x, i ) - ts_l( x, i ), + fmax( fabs( ts_h( x, i ) - ts_c( x, i - 1 ) ), + fabs( ts_l( x, i ) - ts_c( x, i - 1 ) ) ) ); + + ema_plus = i == 1 ? plus_dm + : ema_plus + ( 1.0 / k ) * ( plus_dm - ema_plus ); + ema_minus = i == 1 ? minus_dm + : ema_minus + ( 1.0 / k ) * ( minus_dm - ema_minus ); + ema_tr = i == 1 ? tr + : ema_tr + ( 1.0 / k ) * ( tr - ema_tr ); + + if( i > k ) + { + fp_t di_plus = ema_tr != 0 ? 100.0 * ema_plus / ema_tr : 0; + fp_t di_minus = ema_tr != 0 ? 100.0 * ema_minus / ema_tr : 0; + + y[0][i] = di_plus; + y[1][i] = di_minus; + + fp_t sum = di_plus + di_minus; + fp_t dx = sum != 0 ? 100.0 * fabs( di_plus - di_minus ) / sum : 0; + + y[2][i] = dx; + y[3][i] = i == k + 1 ? dx + : prev_dx + ( 1.0 / k ) * ( dx - prev_dx ); + prev_dx = y[3][i]; + } + } + + return 0; +} + diff --git a/lib/alligator.c b/lib/alligator.c new file mode 100644 index 0000000..81450b0 --- /dev/null +++ b/lib/alligator.c @@ -0,0 +1,70 @@ +// Alligator Indicator +// +// William Elder's Alligator uses three SMAs shifted forward in time: +// Jaw: SMA(13) shifted 8 bars +// Teeth: SMA(8) shifted 5 bars +// Lips: SMA(5) shifted 3 bars +// +// X_n - 1 +// Y_n - 3 +// C_n - 0 + +#include "ts.h" + + +ts_parameter_t const ts_alligator_p = { .n_inputs = 1, .n_outputs = 3, .n_constants = 0, .params_size = 0 }; + +uint_t ts_alligator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 12 ); +} + +int ts_alligator( + 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_alligator_p ); + (void)c; + if( n == 0 ) return -1; + /* Jaw: SMA(13) shifted 8 positions */ + /* Teeth: SMA(8) shifted 5 positions */ + /* Lips: SMA(5) shifted 3 positions */ + + /* Jaw: SMA13 of x[i-8..i+4], displayed at i */ + for (uint_t i = 8; i - 8 + 13 <= n; ++i) + { + fp_t sum = 0; + for (uint_t j = 0; j < 13; ++j) + { + sum += x[0][i - 8 + j]; + } + y[0][i] = sum / 13; + } + + /* Teeth: SMA8 of x[i-5..i+2], displayed at i */ + for (uint_t i = 5; i - 5 + 8 <= n; ++i) + { + fp_t sum = 0; + for (uint_t j = 0; j < 8; ++j) + { + sum += x[0][i - 5 + j]; + } + y[1][i] = sum / 8; + } + + /* Lips: SMA5 of x[i-3..i+1], displayed at i */ + for (uint_t i = 3; i - 3 + 5 <= n; ++i) + { + fp_t sum = 0; + for (uint_t j = 0; j < 5; ++j) + { + sum += x[0][i - 3 + j]; + } + y[2][i] = sum / 5; + } + return 0; +} + diff --git a/lib/angle_deg_to_rad.c b/lib/angle_deg_to_rad.c new file mode 100644 index 0000000..e6929fa --- /dev/null +++ b/lib/angle_deg_to_rad.c @@ -0,0 +1,40 @@ +// Angle Degrees to Radians +// +// angle_deg_to_rad - convert degrees to radians +// +// y[t] = x[0][t] * PI / 180.0 +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + +#include "ts.h" + + + +ts_parameter_t const ts_angle_deg_to_rad_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_angle_deg_to_rad_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_angle_deg_to_rad( + 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_angle_deg_to_rad_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] * PI / 180.0; + } + return 0; +} + + + diff --git a/lib/angle_normalize.c b/lib/angle_normalize.c new file mode 100644 index 0000000..8784f2c --- /dev/null +++ b/lib/angle_normalize.c @@ -0,0 +1,46 @@ +// Angle Normalize +// +// angle_normalize - normalize angle to [-PI, PI] +// +// y[t] = fmod( x[t], 2*PI ), adjusted to [-PI, PI] +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_angle_normalize_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_angle_normalize_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_angle_normalize( + 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_angle_normalize_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t r = fmod( x[0][i], 2.0 * PI ); + if( r > PI ) + r -= 2.0 * PI; + if( r < -PI ) + r += 2.0 * PI; + y[0][i] = r; + } + return 0; +} + + + diff --git a/lib/angle_rad_to_deg.c b/lib/angle_rad_to_deg.c new file mode 100644 index 0000000..124da05 --- /dev/null +++ b/lib/angle_rad_to_deg.c @@ -0,0 +1,40 @@ +// Angle Radians to Degrees +// +// angle_rad_to_deg - convert radians to degrees +// +// y[t] = x[0][t] * 180.0 / PI +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + +#include "ts.h" + + + +ts_parameter_t const ts_angle_rad_to_deg_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_angle_rad_to_deg_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_angle_rad_to_deg( + 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_angle_rad_to_deg_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] * 180.0 / PI; + } + return 0; +} + + + diff --git a/lib/annualized_historical_volatility.c b/lib/annualized_historical_volatility.c new file mode 100644 index 0000000..c0c88cf --- /dev/null +++ b/lib/annualized_historical_volatility.c @@ -0,0 +1,61 @@ +// Annualized Historical Volatility +// +// annualized_historical_volatility - ahv +// +// y[t] = stddev(log(x[t-k..t])) * sqrt(252) +// +// X_n - 1 +// Y_n - 1 +// C_n - 1 + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_annualized_historical_volatility_params_t; + +ts_parameter_t const ts_annualized_historical_volatility_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_annualized_historical_volatility_params_t) }; + +uint_t ts_annualized_historical_volatility_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_annualized_historical_volatility_params_t *)c)->k : 0 ); +} + +int ts_annualized_historical_volatility( + 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_annualized_historical_volatility_p ); + if ( !c ) return -1; + uint_t k = ((ts_annualized_historical_volatility_params_t *)c)->k; + if (k == 0 || n <= k) return -1; + + /* Compute log returns, then stddev, then annualize */ + for (uint_t i = k; i < n; ++i) + { + fp_t sum = 0; + fp_t sum2 = 0; + uint_t count = 0; + for (uint_t j = i - k + 1; j <= i; ++j) + { + if (x[0][j - 1] <= 0 || x[0][j] <= 0) continue; + fp_t ret = log(x[0][j] / x[0][j - 1]); + sum += ret; + sum2 += ret * ret; + count++; + } + if (count == 0) { y[0][i] = 0; continue; } + fp_t mean = sum / count; + fp_t variance = sum2 / count - mean * mean; + if (variance < 0) variance = 0; + y[0][i] = sqrt(variance) * sqrt(252.0); + } + return 0; +} + + + diff --git a/lib/apo.c b/lib/apo.c new file mode 100644 index 0000000..f888162 --- /dev/null +++ b/lib/apo.c @@ -0,0 +1,68 @@ +// Absolute Price Oscillator +// +// apo - APO +// +// Difference between fast and slow EMA: APO = EMA(fast) - EMA(slow) +// +// Inputs: 1 +// Outputs: 1 (Oscillator) +// Constants: 2 (fast period, slow period) + +#include "ts.h" + +typedef struct { + fp_t fast_k; + fp_t slow_k; +} ts_apo_params_t; + +ts_parameter_t const ts_apo_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_apo_params_t) }; + +uint_t ts_apo_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? (uint_t)((ts_apo_params_t *)c)->slow_k - 1 : 0 ); +} + +int ts_apo( + 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_apo_p ); + if ( !c ) return -1; + if (n == 0) return -1; + + fp_t fast_k = ((ts_apo_params_t *)c)->fast_k; + fp_t slow_k = ((ts_apo_params_t *)c)->slow_k; + if (fast_k == 0 || slow_k == 0) return -1; + + fp_t fast_a = 1.0 / fast_k; + fp_t slow_a = 1.0 / slow_k; + + uint_t slow_offset = (uint_t)(slow_k - 1); + if (slow_offset >= n) return -1; + + fp_t fast_ema = x[0][0]; + fp_t slow_ema = x[0][0]; + + for( uint_t i = 1; i <= slow_offset; ++i ) + { + fast_ema = fast_ema + fast_a * ( x[0][i] - fast_ema ); + slow_ema = slow_ema + slow_a * ( x[0][i] - slow_ema ); + } + + y[0][slow_offset] = fast_ema - slow_ema; + + for( uint_t i = slow_offset + 1; i < n; ++i ) + { + fast_ema = fast_ema + fast_a * ( x[0][i] - fast_ema ); + slow_ema = slow_ema + slow_a * ( x[0][i] - slow_ema ); + + y[0][i] = fast_ema - slow_ema; + } + + return 0; +} + + diff --git a/lib/aroon.c b/lib/aroon.c new file mode 100644 index 0000000..539e97b --- /dev/null +++ b/lib/aroon.c @@ -0,0 +1,67 @@ +// Aroon +// +// aroon - ar +// +// Measures the time since the highest high and lowest low in a lookback window. +// Aroon Up = ((period - days since highest high) / period) * 100 +// Aroon Down = ((period - days since lowest low) / period) * 100 +// +// Inputs: 4 (OHLC) +// Outputs: 2 (Aroon Up, Aroon Down) +// Constants: 1 (period) + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_aroon_params_t; + +ts_parameter_t const ts_aroon_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_aroon_params_t) }; + +uint_t ts_aroon_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_aroon_params_t *)c)->k - 1 : 0 ); +} + +int ts_aroon( + 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_aroon_p ); + if ( !c ) return -1; + uint_t k = ((ts_aroon_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for ( uint_t i = k - 1; i < n; ++i ) + { + fp_t highest_high = ts_h( x, i - k + 1 ); + uint_t age_highest = 0; + for ( uint_t j = i - k + 1; j <= i; ++j ) + { + if ( ts_h( x, j ) > highest_high ) + { + highest_high = ts_h( x, j ); + age_highest = i - j; + } + } + + fp_t lowest_low = ts_l( x, i - k + 1 ); + uint_t age_lowest = 0; + for ( uint_t j = i - k + 1; j <= i; ++j ) + { + if ( ts_l( x, j ) < lowest_low ) + { + lowest_low = ts_l( x, j ); + age_lowest = i - j; + } + } + + y[0][i] = ( ( fp_t )( k - age_highest ) / ( fp_t )k ) * 100.0; + y[1][i] = ( ( fp_t )( k - age_lowest ) / ( fp_t )k ) * 100.0; + } + return 0; +} + diff --git a/lib/aroon_oscillator.c b/lib/aroon_oscillator.c new file mode 100644 index 0000000..db9fe9d --- /dev/null +++ b/lib/aroon_oscillator.c @@ -0,0 +1,71 @@ +// Aroon Oscillator +// +// aroon_oscillator - aro +// +// The difference between Aroon Up and Aroon Down. +// Aroon Oscillator = Aroon Up - Aroon Down +// +// Inputs: 4 (OHLC) +// Outputs: 1 (Oscillator) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_aroon_oscillator_params_t; + +ts_parameter_t const ts_aroon_oscillator_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_aroon_oscillator_params_t) }; + +uint_t ts_aroon_oscillator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_aroon_oscillator_params_t *)c)->k - 1 : 0 ); +} + +int ts_aroon_oscillator( + 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_aroon_oscillator_p ); + if ( !c ) return -1; + uint_t k = ((ts_aroon_oscillator_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for ( uint_t i = k - 1; i < n; ++i ) + { + fp_t highest_high = ts_h( x, i - k + 1 ); + uint_t age_highest = 0; + for ( uint_t j = i - k + 1; j <= i; ++j ) + { + if ( ts_h( x, j ) > highest_high ) + { + highest_high = ts_h( x, j ); + age_highest = i - j; + } + } + + fp_t lowest_low = ts_l( x, i - k + 1 ); + uint_t age_lowest = 0; + for ( uint_t j = i - k + 1; j <= i; ++j ) + { + if ( ts_l( x, j ) < lowest_low ) + { + lowest_low = ts_l( x, j ); + age_lowest = i - j; + } + } + + fp_t aroon_up = ( ( fp_t )( k - age_highest ) / ( fp_t )k ) * 100.0; + fp_t aroon_dn = ( ( fp_t )( k - age_lowest ) / ( fp_t )k ) * 100.0; + + y[0][i] = aroon_up - aroon_dn; + } + return 0; +} + + + diff --git a/lib/asi.c b/lib/asi.c new file mode 100644 index 0000000..ac4225b --- /dev/null +++ b/lib/asi.c @@ -0,0 +1,53 @@ +// Accumulation Swing Index +// +// asi - ASI +// +// Cumulative swing indicator using OHLC data to measure buying/selling pressure +// +// Inputs: 4 (OHLC) +// Outputs: 1 (ASI) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_asi_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_asi_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_asi( + 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_asi_p ); + (void)c; + if( n == 0 ) return -1; + + y[0][0] = 0; + + for( uint_t i = 1; i < n; ++i ) + { + fp_t term1 = ts_c( x, i ) - ts_c( x, i - 1 ); + fp_t term2 = 0.5 * ( ts_o( x, i ) - ts_o( x, i - 1 ) ); + fp_t term3 = 0.25 * ( ts_c( x, i ) - ts_o( x, i ) + ts_o( x, i - 1 ) - ts_c( x, i - 1 ) ); + fp_t denom = fmax( ts_h( x, i ) - ts_l( x, i - 1 ), + fmax( ts_h( x, i - 1 ) - ts_l( x, i ), + ts_h( x, i - 1 ) - ts_l( x, i - 1 ) ) ); + fp_t component2 = denom != 0 ? ( term1 - term2 + term3 ) / denom * ( ts_h( x, i ) - ts_l( x, i ) ) : 0; + fp_t half_denom = 0.5 * denom; + fp_t component3 = half_denom != 0 ? ( term1 - term2 + term3 ) / half_denom * 0.5 : 0; + + y[0][i] = y[0][i - 1] + component2 + component3; + } + + return 0; +} + + diff --git a/lib/asinh.c b/lib/asinh.c new file mode 100644 index 0000000..992dbcc --- /dev/null +++ b/lib/asinh.c @@ -0,0 +1,42 @@ +// Hyperbolic Arcsine +// +// asinh - inverse hyperbolic sine +// +// y[t] = asinh( x[t] ) +// = ln( x + √( x^2 + 1 ) ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_asinh_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_asinh_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_asinh( + 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_asinh_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = asinh( x[0][i] ); + } + return 0; +} + + + diff --git a/lib/atan2.c b/lib/atan2.c new file mode 100644 index 0000000..5242cb7 --- /dev/null +++ b/lib/atan2.c @@ -0,0 +1,42 @@ +// Atan2 +// +// atan2 - four-quadrant arctangent +// +// y[t] = atan2( x[0][t], x[1][t] ) +// +// X_n - 2 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_atan2_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_atan2_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_atan2( + 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_atan2_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = atan2( x[0][i], x[1][i] ); + } + return 0; +} + + + diff --git a/lib/atanh.c b/lib/atanh.c new file mode 100644 index 0000000..06896df --- /dev/null +++ b/lib/atanh.c @@ -0,0 +1,50 @@ +// Hyperbolic Arctangent +// +// atanh - inverse hyperbolic tangent +// +// y[t] = atanh( x[t] ) if |x[t]| < 1 +// y[t] = +INFINITY if x[t] == 1 +// y[t] = -INFINITY if x[t] == -1 +// y[t] = NAN if |x[t]| > 1 +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_atanh_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_atanh_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_atanh( + 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_atanh_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t v = x[0][i]; + if ( v > -1.0 && v < 1.0 ) + y[0][i] = atanh( v ); + else if ( v == 1.0 ) + y[0][i] = INFINITY; + else if ( v == -1.0 ) + y[0][i] = -INFINITY; + else + y[0][i] = (fp_t)NAN; + } + return 0; +} + diff --git a/lib/atr.c b/lib/atr.c new file mode 100644 index 0000000..7c9f06f --- /dev/null +++ b/lib/atr.c @@ -0,0 +1,73 @@ +// Average True Range +// +// atr - ATR +// +// Welles Wilder's Average True Range. True Range is the maximum of: +// (1) High - Low +// (2) |High - Previous Close| +// (3) |Low - Previous Close| +// The first ATR is the SMA of the first k TR values; subsequent values +// use Wilder's smoothing: ATR = (prev_ATR * (k-1) + TR) / k +// +// Inputs: 4 (OHLC) +// Outputs: 1 (ATR) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_atr_params_t; + +ts_parameter_t const ts_atr_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_atr_params_t) }; + + +uint_t ts_atr_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_atr_params_t *)c)->k : 0 ); +} + +int ts_atr( + 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_atr_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_atr_params_t *)c)->k; + if (k == 0) return -1; + if (n < 2) return -1; + + fp_t tr_sum = 0; + + /* Cumulative SMA for first k TR values */ + for( uint_t i = 1; i < k && i < n; ++i ) + { + fp_t tr = fmax( ts_h( x, i ) - ts_l( x, i ), fmax( fabs( ts_h( x, i ) - ts_c( x, i - 1 ) ), fabs( ts_l( x, i ) - ts_c( x, i - 1 ) ) ) ); + tr_sum += tr; + y[0][i] = tr_sum / (fp_t)i; + } + + /* At bar k, use SMA of first k TR values */ + if( k < n ) + { + fp_t tr = fmax( ts_h( x, k ) - ts_l( x, k ), fmax( fabs( ts_h( x, k ) - ts_c( x, k - 1 ) ), fabs( ts_l( x, k ) - ts_c( x, k - 1 ) ) ) ); + tr_sum += tr; + y[0][k] = tr_sum / (fp_t)k; + } + + /* Wilder's smoothing from bar k+1 */ + for( uint_t i = k + 1; i < n; ++i ) + { + fp_t tr = fmax( ts_h( x, i ) - ts_l( x, i ), fmax( fabs( ts_h( x, i ) - ts_c( x, i - 1 ) ), fabs( ts_l( x, i ) - ts_c( x, i - 1 ) ) ) ); + y[0][i] = ( y[0][i - 1] * ( k - 1 ) + tr ) / k; + } + return 0; +} + + + diff --git a/lib/atr_bands.c b/lib/atr_bands.c new file mode 100644 index 0000000..73b7d44 --- /dev/null +++ b/lib/atr_bands.c @@ -0,0 +1,87 @@ +// ATR Bands +// +// atr_bands - ATR bands +// +// Upper: SMA(Close) + mult * ATR +// Middle: SMA(Close) +// Lower: SMA(Close) - mult * ATR +// +// Inputs: 4 (OHLC) +// Outputs: 3 (Upper, Middle, Lower) +// Constants: 2 (period, multiplier) + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; + fp_t mult; +} ts_atr_bands_params_t; + +ts_parameter_t const ts_atr_bands_p = { .n_inputs = 4, .n_outputs = 3, .n_constants = 2, .params_size = sizeof(ts_atr_bands_params_t) }; + + +uint_t ts_atr_bands_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_atr_bands_params_t *)c)->k : 0 ); +} + +int ts_atr_bands( + 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_atr_bands_p ); + if ( !c ) return -1; + uint_t k = ((ts_atr_bands_params_t *)c)->k; + if (k == 0 || n < k) return -1; + if (n < 2) return -1; + + fp_t mult = ((ts_atr_bands_params_t *)c)->mult; + + fp_t tr_sum = 0; + fp_t atr = 0; + + // Accumulate ATR from i=1, but only write output from i=k-1 (when SMA window is valid) + for( uint_t i = 1; i < n; ++i ) + { + fp_t tr = fmax( ts_h( x, i ) - ts_l( x, i ), fmax( fabs( ts_h( x, i ) - ts_c( x, i - 1 ) ), fabs( ts_l( x, i ) - ts_c( x, i - 1 ) ) ) ); + + if( i < k ) + { + tr_sum += tr; + atr = tr_sum / (fp_t)i; + } + else if( i == k ) + { + tr_sum += tr; + atr = tr_sum / (fp_t)k; + } + else + { + atr = ( atr * ( k - 1 ) + tr ) / k; + } + + // Only write output when SMA window is fully within bounds (i >= k-1) + if( i >= k - 1 ) + { + fp_t sum = 0; + for( uint_t j = 0; j < k; ++j ) + { + sum += ts_c( x, i - k + 1 + j ); + } + fp_t mean = sum / k; + + y[0][i] = mean + mult * atr; + y[1][i] = mean; + y[2][i] = mean - mult * atr; + } + } + return 0; +} + + + diff --git a/lib/atr_trailing_stops.c b/lib/atr_trailing_stops.c new file mode 100644 index 0000000..2c7cd73 --- /dev/null +++ b/lib/atr_trailing_stops.c @@ -0,0 +1,88 @@ +// ATR Trailing Stops +// +// atr_trailing_stops - ATR stops +// +// Upper stop: max(prev, (H+L)/2 + mult*ATR) +// Lower stop: min(prev, (H+L)/2 - mult*ATR) +// +// Inputs: 4 (OHLC) +// Outputs: 2 (Upper Stop, Lower Stop) +// Constants: 2 (period, multiplier) + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; + fp_t mult; +} ts_atr_trailing_stops_params_t; + +ts_parameter_t const ts_atr_trailing_stops_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 2, .params_size = sizeof(ts_atr_trailing_stops_params_t) }; + + +uint_t ts_atr_trailing_stops_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_atr_trailing_stops_params_t *)c)->k : 0 ); +} + +int ts_atr_trailing_stops( + 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_atr_trailing_stops_p ); + if ( !c ) return -1; + uint_t k = ((ts_atr_trailing_stops_params_t *)c)->k; + if (k == 0) return -1; + if (n < k + 1) return -1; + + fp_t mult = ((ts_atr_trailing_stops_params_t *)c)->mult; + + fp_t tr_sum = 0; + fp_t atr = 0; + + for( uint_t i = 1; i < n; ++i ) + { + fp_t tr = fmax( ts_h( x, i ) - ts_l( x, i ), fmax( fabs( ts_h( x, i ) - ts_c( x, i - 1 ) ), fabs( ts_l( x, i ) - ts_c( x, i - 1 ) ) ) ); + + if( i < k ) + { + tr_sum += tr; + atr = tr_sum / (fp_t)i; + } + else if( i == k ) + { + tr_sum += tr; + atr = tr_sum / (fp_t)k; + } + else + { + atr = ( atr * ( k - 1 ) + tr ) / k; + } + + if( i >= k ) + { + fp_t mid = ( ts_h( x, i ) + ts_l( x, i ) ) / 2.0; + fp_t calc_upper = mid + mult * atr; + fp_t calc_lower = mid - mult * atr; + + if( i == k ) + { + y[0][i] = calc_upper; + y[1][i] = calc_lower; + } + else + { + y[0][i] = fmax( y[0][i - 1], calc_upper ); + y[1][i] = fmin( y[1][i - 1], calc_lower ); + } + } + } + return 0; +} + + + diff --git a/lib/average.c b/lib/average.c new file mode 100644 index 0000000..391de93 --- /dev/null +++ b/lib/average.c @@ -0,0 +1,71 @@ +// Simple Moving Average +// +// average_simple - sma +// +// Unweighted mean of previous k data points +// +// SMA_k = ( 1 / k ) * SUM[ i = 1, k ] x_i +// +// Initial Values +// +// Cumulative moving average to n = k +// +// Successive Value +// +// SMA_n = x_n-1 + ( 1 / n )( x_n - x_n-1 ) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_average_params_t; + +ts_parameter_t const ts_average_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_average_params_t) }; + + +uint_t ts_average_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_average_params_t *)c)->k - 1 : 0 ); +} + +int ts_average( + 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_average_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_average_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = 0; + uint_t yi = k; + + fp_t sum = 0; + + for( ; xi < k; ++xi ) + { + sum += x[0][xi]; + } + + y[0][k - 1] = sum / k; + + for( ; xi < n; ++xi, ++yi ) + { + y[0][yi] = y[0][yi - 1] + ( x[0][xi] - x[0][xi - k] ) / k; + } + return 0; +} + + + diff --git a/lib/average_cumulative.c b/lib/average_cumulative.c new file mode 100644 index 0000000..905ccfe --- /dev/null +++ b/lib/average_cumulative.c @@ -0,0 +1,47 @@ +// Cumulative Moving Average +// +// average_cumulative - cma +// +// Average of all data to the current point +// +// y[t] = ( 1 / k ) * SUM[ t = 1, k ]( x[t] ) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_average_cumulative_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_average_cumulative_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_average_cumulative( + 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_average_cumulative_p ); + (void)c; + fp_t sum = 0; + + for( uint_t i = 0; i < n; ++i ) + { + sum += x[0][i]; + y[0][i] = sum / ( i + 1 ); + } + return 0; +} + + + diff --git a/lib/average_exponential.c b/lib/average_exponential.c new file mode 100644 index 0000000..bae9d5f --- /dev/null +++ b/lib/average_exponential.c @@ -0,0 +1,56 @@ +// Exponential Moving Average +// +// average_exponential - ema +// +// Weighted moving average with exponentially decreasing weights determined by +// the constant c +// +// y[0] = x[0] +// y[t] = a * x[t] + ( 1 - a ) * EMA[t - 1] +// a = 1 / k; +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + + +typedef struct { + fp_t k; +} ts_average_exponential_params_t; + +ts_parameter_t const ts_average_exponential_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_average_exponential_params_t) }; + + +uint_t ts_average_exponential_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_average_exponential( + 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_average_exponential_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + fp_t k = ((ts_average_exponential_params_t *)c)->k; + if (k <= 0 || isnan(k)) return -1; + + fp_t a = 1.0 / k; + + y[0][0] = x[0][0]; + + for( uint_t i = 1; i < n; ++i ) + { + y[0][i] = y[0][i - 1] + a * ( x[0][i] - y[0][i - 1] ); + } + return 0; +} + diff --git a/lib/average_exponential_double.c b/lib/average_exponential_double.c new file mode 100644 index 0000000..eeb890f --- /dev/null +++ b/lib/average_exponential_double.c @@ -0,0 +1,57 @@ +// Double Exponential Moving Average +// +// average_exponential_double - dema +// +// y[i] = +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + + +typedef struct { + fp_t a; +} ts_average_exponential_double_params_t; + +ts_parameter_t const ts_average_exponential_double_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_average_exponential_double_params_t) }; + + +uint_t ts_average_exponential_double_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_average_exponential_double( + 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_average_exponential_double_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + fp_t a = ((ts_average_exponential_double_params_t *)c)->a; + if (a == 0 || n == 0) return -1; + + fp_t ema1 = x[0][0]; + fp_t ema2 = x[0][0]; + + y[0][0] = x[0][0]; + + for( uint_t i = 1; i < n; ++i ) + { + ema1 = ema1 + a * ( x[0][i] - ema1 ); + ema2 = ema2 + a * ( ema1 - ema2 ); + + y[0][i] = 2 * ema1 - ema2; + } + return 0; +} + + + diff --git a/lib/average_exponential_triple.c b/lib/average_exponential_triple.c new file mode 100644 index 0000000..467d87f --- /dev/null +++ b/lib/average_exponential_triple.c @@ -0,0 +1,57 @@ +// Triple Exponential Moving Average +// +// average_exponential_triple - tema +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + + +typedef struct { + fp_t a; +} ts_average_exponential_triple_params_t; + +ts_parameter_t const ts_average_exponential_triple_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_average_exponential_triple_params_t) }; + + +uint_t ts_average_exponential_triple_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_average_exponential_triple( + 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_average_exponential_triple_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + fp_t a = ((ts_average_exponential_triple_params_t *)c)->a; + if (a == 0 || n == 0) return -1; + + fp_t ema1 = x[0][0]; + fp_t ema2 = x[0][0]; + fp_t ema3 = x[0][0]; + + y[0][0] = x[0][0]; + + for( uint_t i = 1; i < n; ++i ) + { + ema1 = ema1 + a * ( x[0][i] - ema1 ); + ema2 = ema2 + a * ( ema1 - ema2 ); + ema3 = ema3 + a * ( ema2 - ema3 ); + + y[0][i] = 3 * ema1 - 3 * ema2 + ema3; + } + return 0; +} + + + diff --git a/lib/average_price.c b/lib/average_price.c new file mode 100644 index 0000000..8c270b8 --- /dev/null +++ b/lib/average_price.c @@ -0,0 +1,39 @@ +// Average Price +// +// average_price - avg_price +// +// Average of high, low, and close: (H + L + C) / 3 +// +// Inputs: 5 (OHLCV) +// Outputs: 1 (Average Price) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_average_price_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_average_price_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_average_price( + 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_average_price_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = ( x[1][i] + x[2][i] + x[3][i] ) / 3; + } + return 0; +} + + + diff --git a/lib/average_triangle.c b/lib/average_triangle.c new file mode 100644 index 0000000..9ac952d --- /dev/null +++ b/lib/average_triangle.c @@ -0,0 +1,107 @@ +// Triangular Moving Average +// +// average_triangle - tma +// +// A moving average of moving averages +// +// y[i] = +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 +// +// 012345678901234567890123456789 +// ---------01234567890123456 +// ------------------0 + + +#include <stdlib.h> +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_average_triangle_params_t; + +ts_parameter_t const ts_average_triangle_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_average_triangle_params_t) }; + + +uint_t ts_average_triangle_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? 2 * ( ((ts_average_triangle_params_t *)c)->k - 1 ) : 0 ); +} + +int ts_average_triangle( + 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_average_triangle_p ); + if ( !c ) return -1; + uint_t k = ((ts_average_triangle_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t rk2 = _ts_reciprocal( _ts_square( k ) ); + uint_t xi = 0; + uint_t yi = 2 * ( k - 1 ); + + fp_t *xsum = malloc(k * sizeof(fp_t)); + if (!xsum) return -1; + uint_t xsumi = 0; + + fp_t sum_of_xsum = 0; + + xsum[0] = 0; + + for (uint_t j = 0; j < n && j < 2 * (k - 1); ++j) y[0][j] = 0; + + fp_t last_sum = 0; + + for( ; xi < k; xi++ ) + { + xsum[xsumi] += x[0][xi]; + last_sum = xsum[xsumi]; + } + + sum_of_xsum = xsum[xsumi]; + xsumi++; + + for( ; xi < 2 * k - 1; xi++ ) + { + xsum[xsumi] = xsum[xsumi - 1] + x[0][xi] - x[0][xi - k]; + last_sum = xsum[xsumi]; + sum_of_xsum += xsum[xsumi]; + xsumi++; + } + + y[0][yi++] = sum_of_xsum * rk2; + + for( ; xi < n; ++xi, ++yi ) + { + if( xsumi == k ) + { + xsumi = 0; + sum_of_xsum -= xsum[xsumi]; + xsum[xsumi] = last_sum + x[0][xi] - x[0][xi - k]; + } + else + { + sum_of_xsum -= xsum[xsumi]; + xsum[xsumi] = last_sum + x[0][xi] - x[0][xi - k]; + } + + last_sum = xsum[xsumi]; + sum_of_xsum += xsum[xsumi]; + y[0][yi] = sum_of_xsum * rk2; + + xsumi++; + } + + free(xsum); + return 0; +} + + + diff --git a/lib/average_weighted.c b/lib/average_weighted.c new file mode 100644 index 0000000..eb99a17 --- /dev/null +++ b/lib/average_weighted.c @@ -0,0 +1,67 @@ +// Weighted Moving Average +// +// average_weighted - wma +// +// Weighted mean of previous k data points +// +// y[t] = SUM[ i = t, t - k]( x[t] * ( ) ) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_average_weighted_params_t; + +ts_parameter_t const ts_average_weighted_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_average_weighted_params_t) }; + + +uint_t ts_average_weighted_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_average_weighted_params_t *)c)->k - 1 : 0 ); +} + +int ts_average_weighted( + 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_average_weighted_p ); + if ( !c ) return -1; + uint_t k = ((ts_average_weighted_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = 0; + uint_t yi = k; + + fp_t sum = 0; + fp_t wsum = 0; + + for( ; xi < k; ++xi ) + { + sum += x[0][xi]; + wsum += x[0][xi] * ( xi + 1 ); + } + + fp_t rtri = 1.0 / _ts_triangle_number( k ); + + y[0][k - 1] = wsum * rtri; + + for( ; xi < n; ++xi, ++yi ) + { + wsum = wsum + ( k * x[0][xi] ) - sum; + sum = sum + x[0][xi] - x[0][xi - k]; + y[0][yi] = wsum * rtri; + } + return 0; +} + + + diff --git a/lib/average_weighted_series.c b/lib/average_weighted_series.c new file mode 100644 index 0000000..d7e2ccb --- /dev/null +++ b/lib/average_weighted_series.c @@ -0,0 +1,78 @@ +// Average Weighted Series +// +// average_weighted_series - aws +// +// SMA of the product of two series: SMA(x0 * x1, k) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 (period) + +#include <math.h> +#include <stdlib.h> +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_average_weighted_series_params_t; + +ts_parameter_t const ts_average_weighted_series_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_average_weighted_series_params_t) }; + + +uint_t ts_average_weighted_series_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_average_weighted_series_params_t *)c)->k - 1 : 0 ); +} + +int ts_average_weighted_series( + 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_average_weighted_series_p ); + if ( !c ) return -1; + uint_t k = ((ts_average_weighted_series_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = 0; + uint_t yi = k; + + fp_t *b = malloc(k * sizeof(fp_t)); + if (!b) return -1; + uint_t bi = 0; + + fp_t sum = 0; + + while( xi < k ) + { + b[bi] = x[0][xi] * x[1][xi]; + sum += b[bi]; + + ++xi; + bi = _ts_circle_increment( bi, k ); + } + + y[0][k - 1] = sum / k; + uint_t tmp; + + while( xi < n ) + { + tmp = b[bi]; + b[bi] = x[0][xi] * x[1][xi]; + + y[0][yi] = y[0][yi - 1] + ( b[bi] - tmp ) / k; + + ++xi; + ++yi; + bi = _ts_circle_increment( bi, k ); + } + + free(b); + return 0; +} + + + diff --git a/lib/awesome_oscillator.c b/lib/awesome_oscillator.c new file mode 100644 index 0000000..be1932e --- /dev/null +++ b/lib/awesome_oscillator.c @@ -0,0 +1,66 @@ +// Awesome Oscillator +// +// awesome_oscillator - AO +// +// EMA5(MP) - EMA34(MP), where MP = (H + L) / 2 +// +// Inputs: 4 (OHLC) +// Outputs: 1 (Oscillator) +// Constants: 0 + +#include "ts.h" + + +ts_parameter_t const ts_awesome_oscillator_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_awesome_oscillator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 33 ); +} + +int ts_awesome_oscillator( + 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_awesome_oscillator_p ); + (void)c; + if (n < 34) return -1; + + uint_t fast_period = 5; + uint_t slow_period = 34; + + fp_t fast_a = 2.0 / ( ( fp_t )fast_period + 1.0 ); + fp_t slow_a = 2.0 / ( ( fp_t )slow_period + 1.0 ); + + fp_t sum_fast = 0; + fp_t sum_slow = 0; + + for ( uint_t j = 0; j < slow_period; ++j ) + { + fp_t mp = ( ts_h( x, j ) + ts_l( x, j ) ) / 2.0; + sum_slow += mp; + if ( j < fast_period ) + sum_fast += mp; + } + + fp_t ema_fast = sum_fast / ( fp_t )fast_period; + fp_t ema_slow = sum_slow / ( fp_t )slow_period; + + for ( uint_t i = 0; i < slow_period - 1; ++i ) + y[0][i] = 0; + + y[0][slow_period - 1] = ema_fast - ema_slow; + + for( uint_t i = slow_period; i < n; ++i ) + { + fp_t mp = ( ts_h( x, i ) + ts_l( x, i ) ) / 2.0; + ema_fast = ema_fast + fast_a * ( mp - ema_fast ); + ema_slow = ema_slow + slow_a * ( mp - ema_slow ); + y[0][i] = ema_fast - ema_slow; + } + return 0; +} + diff --git a/lib/balance_of_power.c b/lib/balance_of_power.c new file mode 100644 index 0000000..26f3456 --- /dev/null +++ b/lib/balance_of_power.c @@ -0,0 +1,41 @@ +// Balance of Power +// +// balance_of_power - BOP +// +// Measures relationship between buyers and sellers: (C - O) / (H - L) +// +// Inputs: 4 (OHLC) +// Outputs: 1 (BOP) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_balance_of_power_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_balance_of_power_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_balance_of_power( + 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_balance_of_power_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t hl = ts_h( x, i ) - ts_l( x, i ); + y[0][i] = hl != 0 ? ( ts_c( x, i ) - ts_o( x, i ) ) / hl : 0; + } + + return 0; +} + + + diff --git a/lib/band_width.c b/lib/band_width.c new file mode 100644 index 0000000..822d835 --- /dev/null +++ b/lib/band_width.c @@ -0,0 +1,60 @@ +// Band Width +// +// band_width - BW +// +// Normalized width of Bollinger Bands: (Upper - Lower) / SMA * 100 +// +// Inputs: 1 +// Outputs: 1 (Width %) +// Constants: 2 (period, std multiplier) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; + fp_t std_mult; +} ts_band_width_params_t; + +ts_parameter_t const ts_band_width_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_band_width_params_t) }; + +uint_t ts_band_width_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_band_width_params_t *)c)->k - 1 : 0 ); +} + +int ts_band_width( + 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_band_width_p ); + if ( !c ) return -1; + uint_t k = ((ts_band_width_params_t *)c)->k; + fp_t std_mult = ((ts_band_width_params_t *)c)->std_mult; + if (k == 0 || n < k) return -1; + + for (uint_t i = k - 1; i < n; ++i) + { + fp_t sum = 0; + fp_t sum2 = 0; + for (uint_t j = i - k + 1; j <= i; ++j) + { + sum += x[0][j]; + sum2 += x[0][j] * x[0][j]; + } + fp_t mean = sum / k; + fp_t variance = sum2 / k - mean * mean; + if (variance < 0) variance = 0; + fp_t stddev = sqrt(variance); + fp_t upper = mean + std_mult * stddev; + fp_t lower = mean - std_mult * stddev; + y[0][i] = mean != 0 ? (upper - lower) / mean * 100 : 0; + } + return 0; +} + + + diff --git a/lib/beta_pdf.c b/lib/beta_pdf.c new file mode 100644 index 0000000..a23ed68 --- /dev/null +++ b/lib/beta_pdf.c @@ -0,0 +1,52 @@ +// Beta PDF +// +// beta_pdf - beta probability density +// +// f(x; α, β) = x^(α-1) * (1-x)^(β-1) / B(α, β), for 0 < x < 1 +// +// Inputs: 1 +// Outputs: 1 (PDF value) +// Constants: 2 (alpha, beta) + +#include <math.h> +#include "ts.h" + +typedef struct { + fp_t alpha; + fp_t beta; +} ts_beta_pdf_params_t; + +ts_parameter_t const ts_beta_pdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_beta_pdf_params_t) }; + +uint_t ts_beta_pdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_beta_pdf( + 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_beta_pdf_p ); + if ( !c ) return -1; + fp_t alpha = ((ts_beta_pdf_params_t *)c)->alpha; + fp_t beta = ((ts_beta_pdf_params_t *)c)->beta; + if (isnan(alpha) || isnan(beta) || alpha <= 0 || beta <= 0) + { + for( uint_t i = 0; i < n; ++i ) y[0][i] = 0; + return -1; + } + fp_t beta_fn = exp( lgamma( alpha ) + lgamma( beta ) - lgamma( alpha + beta ) ); + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + y[0][i] = ( xi > 0 && xi < 1 ) ? pow( xi, alpha - 1.0 ) * pow( 1.0 - xi, beta - 1.0 ) / beta_fn : 0.0; + } + return 0; +} + + + diff --git a/lib/binomial.c b/lib/binomial.c new file mode 100644 index 0000000..9b50698 --- /dev/null +++ b/lib/binomial.c @@ -0,0 +1,58 @@ +// Binomial Coefficient +// +// binomial - C(n, k) +// +// Number of combinations: C(n, k) = n! / (k! * (n-k)!) +// +// Inputs: 2 (n, k) +// Outputs: 1 (coefficient) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_binomial_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_binomial_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_binomial( + 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_binomial_p ); + (void)c; + /* C(n, k) = n! / (k! * (n-k)!) */ + for (uint_t i = 0; i < n; ++i) + { + fp_t n_val = floor(x[0][i]); + fp_t k_val = floor(x[1][i]); + + if (k_val > n_val || k_val < 0 || n_val < 0) + { + y[0][i] = 0; + continue; + } + + /* Use symmetry: C(n,k) = C(n, n-k) */ + if (k_val > n_val - k_val) + k_val = n_val - k_val; + + fp_t result = 1; + for (uint_t j = 0; j < (uint_t)k_val; ++j) + { + result = result * (n_val - j) / (j + 1); + } + y[0][i] = result; + } + return 0; +} + + + diff --git a/lib/binomial_pdf.c b/lib/binomial_pdf.c new file mode 100644 index 0000000..8b3a442 --- /dev/null +++ b/lib/binomial_pdf.c @@ -0,0 +1,63 @@ +// Binomial PDF +// +// binomial_pdf - binomial probability density +// +// P(X=k) = C(n, k) * p^k * (1-p)^(n-k) +// +// Inputs: 1 (k values) +// Outputs: 1 (PDF value) +// Constants: 1 (n trials, p probability) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t n_trials; + fp_t p; +} ts_binomial_pdf_params_t; + +ts_parameter_t const ts_binomial_pdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_binomial_pdf_params_t) }; + +uint_t ts_binomial_pdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_binomial_pdf( + 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_binomial_pdf_p ); + if ( !c ) return -1; + uint_t n_trials = ((ts_binomial_pdf_params_t *)c)->n_trials; + fp_t p = ((ts_binomial_pdf_params_t *)c)->p; + if (p < 0.0 || p > 1.0 || isnan(p) || isinf(p)) return -1; + for( uint_t i = 0; i < n; ++i ) + { + uint_t k = (uint_t)x[0][i]; + if( k > n_trials ) + { + y[0][i] = 0.0; + } + else if( p == 0.0 ) + { + y[0][i] = k == 0 ? 1.0 : 0.0; + } + else if( p == 1.0 ) + { + y[0][i] = k == n_trials ? 1.0 : 0.0; + } + else + { + fp_t log_comb = lgamma( n_trials + 1.0 ) - lgamma( k + 1.0 ) - lgamma( n_trials - k + 1.0 ); + y[0][i] = exp( log_comb + k * log( p ) + ( n_trials - k ) * log( 1.0 - p ) ); + } + } + return 0; +} + + + diff --git a/lib/bollinger_bands.c b/lib/bollinger_bands.c new file mode 100644 index 0000000..55da054 --- /dev/null +++ b/lib/bollinger_bands.c @@ -0,0 +1,88 @@ +// Bollinger Bands +// +// bollinger_bands - BB +// +// Upper: SMA + mult * stddev +// Middle: SMA +// Lower: SMA - mult * stddev +// +// Inputs: 1 +// Outputs: 3 (Upper, Middle, Lower) +// Constants: 2 (period, std multiplier) + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; + fp_t std_mult; +} ts_bollinger_bands_params_t; + +ts_parameter_t const ts_bollinger_bands_p = { .n_inputs = 1, .n_outputs = 3, .n_constants = 2, .params_size = sizeof(ts_bollinger_bands_params_t) }; + + +uint_t ts_bollinger_bands_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_bollinger_bands_params_t *)c)->k - 1 : 0 ); +} + +int ts_bollinger_bands( + 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_bollinger_bands_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_bollinger_bands_params_t *)c)->k; + if (k == 0 || n < k) return -1; + fp_t std_mult = ((ts_bollinger_bands_params_t *)c)->std_mult; + if (std_mult < 0 || isnan(std_mult)) return -1; + + // Two-pass initial window for numerical stability + { + fp_t mean = 0; + for( uint_t j = 0; j < k; ++j ) + mean += x[0][j]; + mean /= (fp_t)k; + fp_t variance = 0; + for( uint_t j = 0; j < k; ++j ) + { + fp_t d = x[0][j] - mean; + variance += d * d; + } + variance /= (fp_t)k; + fp_t stddev = sqrt( variance ); + y[1][k - 1] = mean + std_mult * stddev; + y[0][k - 1] = mean; + y[2][k - 1] = mean - std_mult * stddev; + } + + // Sliding window: maintain running mean, two-pass variance + fp_t sum = 0; + for( uint_t j = 0; j < k; ++j ) + sum += x[0][j]; + fp_t rk = 1.0 / (fp_t)k; + for( uint_t i = k; i < n; ++i ) + { + sum = sum + x[0][i] - x[0][i - k]; + fp_t mean = sum * rk; + // Two-pass variance for stability + fp_t variance = 0; + for( uint_t j = i - k + 1; j <= i; ++j ) + { + fp_t d = x[0][j] - mean; + variance += d * d; + } + variance *= rk; + fp_t stddev = sqrt( variance ); + y[1][i] = mean + std_mult * stddev; + y[0][i] = mean; + y[2][i] = mean - std_mult * stddev; + } + return 0; +} + diff --git a/lib/bollinger_lower.c b/lib/bollinger_lower.c new file mode 100644 index 0000000..05a0883 --- /dev/null +++ b/lib/bollinger_lower.c @@ -0,0 +1,60 @@ +// Bollinger Lower Band +// +// bollinger_lower - BB lower +// +// Lower band: SMA - mult * stddev +// +// Inputs: 1 +// Outputs: 1 (Lower Band) +// Constants: 2 (period, std multiplier) + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; + fp_t std_mult; +} ts_bollinger_lower_params_t; + +ts_parameter_t const ts_bollinger_lower_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_bollinger_lower_params_t) }; + + +uint_t ts_bollinger_lower_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_bollinger_lower_params_t *)c)->k - 1 : 0 ); +} + +int ts_bollinger_lower( + 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_bollinger_lower_p ); + if ( !c ) return -1; + uint_t k = ((ts_bollinger_lower_params_t *)c)->k; + if (k == 0 || n < k) return -1; + fp_t std_mult = ((ts_bollinger_lower_params_t *)c)->std_mult; + if (isnan(std_mult) || isinf(std_mult)) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t sum = 0, sum2 = 0; + for( uint_t j = 0; j < k; ++j ) + { + fp_t v = x[0][i - k + 1 + j]; + sum += v; + sum2 += v * v; + } + fp_t mean = sum / k; + fp_t variance = sum2 / k - mean * mean; + fp_t stddev = variance >= 0 ? sqrt( variance ) : 0; + y[0][i] = mean - std_mult * stddev; + } + return 0; +} + + + diff --git a/lib/bollinger_pctb.c b/lib/bollinger_pctb.c new file mode 100644 index 0000000..a3425cd --- /dev/null +++ b/lib/bollinger_pctb.c @@ -0,0 +1,63 @@ +// Bollinger %b +// +// bollinger_pctb - %b +// +// Position of price relative to bands: (Price - Lower) / (Upper - Lower) +// +// Inputs: 1 +// Outputs: 1 (%b) +// Constants: 2 (period, std multiplier) + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; + fp_t std_mult; +} ts_bollinger_pctb_params_t; + +ts_parameter_t const ts_bollinger_pctb_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_bollinger_pctb_params_t) }; + + +uint_t ts_bollinger_pctb_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_bollinger_pctb_params_t *)c)->k - 1 : 0 ); +} + +int ts_bollinger_pctb( + 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_bollinger_pctb_p ); + if ( !c ) return -1; + uint_t k = ((ts_bollinger_pctb_params_t *)c)->k; + if (k == 0 || n < k) return -1; + fp_t std_mult = ((ts_bollinger_pctb_params_t *)c)->std_mult; + if (isnan(std_mult) || isinf(std_mult)) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t sum = 0, sum2 = 0; + for( uint_t j = 0; j < k; ++j ) + { + fp_t v = x[0][i - k + 1 + j]; + sum += v; + sum2 += v * v; + } + fp_t mean = sum / k; + fp_t variance = sum2 / k - mean * mean; + fp_t stddev = variance >= 0 ? sqrt( variance ) : 0; + fp_t upper = mean + std_mult * stddev; + fp_t lower = mean - std_mult * stddev; + fp_t width = upper - lower; + y[0][i] = width != 0 ? ( x[0][i] - lower ) / width : 0.5; + } + return 0; +} + + + diff --git a/lib/bollinger_upper.c b/lib/bollinger_upper.c new file mode 100644 index 0000000..9294cfb --- /dev/null +++ b/lib/bollinger_upper.c @@ -0,0 +1,60 @@ +// Bollinger Upper Band +// +// bollinger_upper - BB upper +// +// Upper band: SMA + mult * stddev +// +// Inputs: 1 +// Outputs: 1 (Upper Band) +// Constants: 2 (period, std multiplier) + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; + fp_t std_mult; +} ts_bollinger_upper_params_t; + +ts_parameter_t const ts_bollinger_upper_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_bollinger_upper_params_t) }; + + +uint_t ts_bollinger_upper_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_bollinger_upper_params_t *)c)->k - 1 : 0 ); +} + +int ts_bollinger_upper( + 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_bollinger_upper_p ); + if ( !c ) return -1; + uint_t k = ((ts_bollinger_upper_params_t *)c)->k; + if (k == 0 || n < k) return -1; + fp_t std_mult = ((ts_bollinger_upper_params_t *)c)->std_mult; + if (isnan(std_mult) || isinf(std_mult)) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t sum = 0, sum2 = 0; + for( uint_t j = 0; j < k; ++j ) + { + fp_t v = x[0][i - k + 1 + j]; + sum += v; + sum2 += v * v; + } + fp_t mean = sum / k; + fp_t variance = sum2 / k - mean * mean; + fp_t stddev = variance >= 0 ? sqrt( variance ) : 0; + y[0][i] = mean + std_mult * stddev; + } + return 0; +} + + + diff --git a/lib/bollinger_width.c b/lib/bollinger_width.c new file mode 100644 index 0000000..d9bca25 --- /dev/null +++ b/lib/bollinger_width.c @@ -0,0 +1,62 @@ +// Bollinger Width +// +// bollinger_width - BB width +// +// Normalized band width: (Upper - Lower) / SMA * 100 +// +// Inputs: 1 +// Outputs: 1 (Width %) +// Constants: 2 (period, std multiplier) + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; + fp_t std_mult; +} ts_bollinger_width_params_t; + +ts_parameter_t const ts_bollinger_width_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_bollinger_width_params_t) }; + + +uint_t ts_bollinger_width_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_bollinger_width_params_t *)c)->k - 1 : 0 ); +} + +int ts_bollinger_width( + 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_bollinger_width_p ); + if ( !c ) return -1; + uint_t k = ((ts_bollinger_width_params_t *)c)->k; + if (k == 0 || n < k) return -1; + fp_t std_mult = ((ts_bollinger_width_params_t *)c)->std_mult; + if (isnan(std_mult) || isinf(std_mult)) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t sum = 0, sum2 = 0; + for( uint_t j = 0; j < k; ++j ) + { + fp_t v = x[0][i - k + 1 + j]; + sum += v; + sum2 += v * v; + } + fp_t mean = sum / k; + fp_t variance = sum2 / k - mean * mean; + fp_t stddev = variance >= 0 ? sqrt( variance ) : 0; + fp_t upper = mean + std_mult * stddev; + fp_t lower = mean - std_mult * stddev; + y[0][i] = mean != 0 ? ( upper - lower ) / mean * 100.0 : 0; + } + return 0; +} + + + diff --git a/lib/candlestick_formations.c b/lib/candlestick_formations.c new file mode 100644 index 0000000..835e5d5 --- /dev/null +++ b/lib/candlestick_formations.c @@ -0,0 +1,58 @@ +// Candlestick Formations +// +// candlestick_formations - candle +// +// Detects doji, engulfing, shooting star, and hammer patterns +// +// Inputs: 4 (OHLC) +// Outputs: 1 (formation flag) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_candlestick_formations_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_candlestick_formations_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 1 ); +} + +int ts_candlestick_formations( + 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_candlestick_formations_p ); + (void)c; + if (n > 0) y[0][0] = 0; + for( uint_t i = 1; i < n; ++i ) + { + fp_t const body = ts_c( x, i ) - ts_o( x, i ); + fp_t const prev_body = ts_c( x, i - 1 ) - ts_o( x, i - 1 ); + fp_t const range = ts_h( x, i ) - ts_l( x, i ); + fp_t const body_abs = fabs( body ); + fp_t const upper_wick = ts_h( x, i ) - fmax( ts_o( x, i ), ts_c( x, i ) ); + fp_t const lower_wick = fmin( ts_o( x, i ), ts_c( x, i ) ) - ts_l( x, i ); + + y[0][i] = 0; + + if( range > 0 && body_abs / range < 0.1 ) + y[0][i] = 1; // doji + else if( prev_body > 0 && body < 0 && body_abs >= fabs( prev_body ) ) + y[0][i] = 2; // bearish engulfing + else if( prev_body < 0 && body > 0 && body_abs >= fabs( prev_body ) ) + y[0][i] = 3; // bullish engulfing + else if( upper_wick >= 2 * body_abs && body <= 0 ) + y[0][i] = 4; // shooting star + else if( lower_wick >= 2 * body_abs && body >= 0 ) + y[0][i] = 5; // hammer + } + return 0; +} + + + diff --git a/lib/catalan.c b/lib/catalan.c new file mode 100644 index 0000000..4a6ed9e --- /dev/null +++ b/lib/catalan.c @@ -0,0 +1,54 @@ +// Catalan Number +// +// catalan - C(n) +// +// nth Catalan number: C(n) = (2n)! / ((n+1)! * n!) +// +// Inputs: 1 (n) +// Outputs: 1 (Catalan number) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_catalan_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_catalan_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_catalan( + 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_catalan_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xv = x[0][i]; + if (isnan(xv) || isinf(xv) || xv < 0 || xv != (fp_t)(uint_t)xv) { + y[0][i] = 0; + continue; + } + uint_t n_val = (uint_t)xv; + fp_t result = 1.0; + for( uint_t j = 0; j < n_val; ++j ) + { + result *= (fp_t)(j + n_val + 1); + result /= (fp_t)(j + 1); + } + result /= (fp_t)(n_val + 1); + y[0][i] = result; + } + return 0; +} + + + diff --git a/lib/cauchy_cdf.c b/lib/cauchy_cdf.c new file mode 100644 index 0000000..dadaaf3 --- /dev/null +++ b/lib/cauchy_cdf.c @@ -0,0 +1,40 @@ +// Cauchy CDF +// +// cauchy_cdf - Cauchy cumulative distribution +// +// F(x) = 0.5 + atan(x) / PI +// +// Inputs: 1 +// Outputs: 1 (CDF value) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_cauchy_cdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_cauchy_cdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cauchy_cdf( + 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_cauchy_cdf_p ); + (void)c; + /* CDF = 0.5 + atan(x) / PI */ + for (uint_t i = 0; i < n; ++i) + { + y[0][i] = 0.5 + atan(x[0][i]) / PI; + } + return 0; +} + + + diff --git a/lib/cauchy_pdf.c b/lib/cauchy_pdf.c new file mode 100644 index 0000000..0d427c1 --- /dev/null +++ b/lib/cauchy_pdf.c @@ -0,0 +1,39 @@ +// Cauchy PDF +// +// cauchy_pdf - Cauchy probability density +// +// f(x) = 1 / (PI * (1 + x^2)) +// +// Inputs: 1 +// Outputs: 1 (PDF value) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_cauchy_pdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_cauchy_pdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cauchy_pdf( + 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_cauchy_pdf_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = 1.0 / ( PI * ( 1.0 + x[0][i] * x[0][i] ) ); + } + return 0; +} + + + diff --git a/lib/cbrt.c b/lib/cbrt.c new file mode 100644 index 0000000..2de15d2 --- /dev/null +++ b/lib/cbrt.c @@ -0,0 +1,41 @@ +// Cube Root +// +// cbrt - cube root +// +// y[t] = ∛(x[t]) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_cbrt_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_cbrt_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cbrt( + 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_cbrt_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = cbrt( x[0][i] ); + } + return 0; +} + + + diff --git a/lib/cci.c b/lib/cci.c new file mode 100644 index 0000000..956f619 --- /dev/null +++ b/lib/cci.c @@ -0,0 +1,89 @@ +// Commodity Channel Index +// +// cci - CCI +// +// (TP - SMA(TP)) / (0.015 * MAD(TP)), where TP = (H+L+C)/3 +// +// Inputs: 4 (OHLC) +// Outputs: 1 (CCI) +// Constants: 0 + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_cci_params_t; + +ts_parameter_t const ts_cci_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_cci_params_t) }; + +uint_t ts_cci_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_cci_params_t *)c)->k - 1 : 0 ); +} + +int ts_cci( + 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_cci_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_cci_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + // Compute initial typical prices + fp_t tp_sum = 0; + for( uint_t j = 0; j < k; ++j ) + { + tp_sum += ( ts_h( x, j ) + ts_l( x, j ) + ts_c( x, j ) ) / 3.0; + } + fp_t tp_sma = tp_sum / (fp_t)k; + + // Compute initial MAD + fp_t mad_sum = 0; + for( uint_t j = 0; j < k; ++j ) + { + fp_t tp = ( ts_h( x, j ) + ts_l( x, j ) + ts_c( x, j ) ) / 3.0; + mad_sum += fabs( tp - tp_sma ); + } + fp_t mad = mad_sum / (fp_t)k; + + { + fp_t tp = ( ts_h( x, k - 1 ) + ts_l( x, k - 1 ) + ts_c( x, k - 1 ) ) / 3.0; + if( mad == 0 ) + y[0][k - 1] = 0; + else + y[0][k - 1] = ( tp - tp_sma ) / ( 0.015 * mad ); + } + + // Sliding window: incremental tp_sum, but MAD needs recompute when tp_sma changes + // MAD depends on tp_sma which changes each step, so we can't fully incremental MAD + // However, we can still use incremental tp_sum + for( uint_t i = k; i < n; ++i ) + { + fp_t tp_new = ( ts_h( x, i ) + ts_l( x, i ) + ts_c( x, i ) ) / 3.0; + fp_t tp_old = ( ts_h( x, i - k ) + ts_l( x, i - k ) + ts_c( x, i - k ) ) / 3.0; + tp_sum = tp_sum + tp_new - tp_old; + tp_sma = tp_sum / (fp_t)k; + + mad_sum = 0; + for( uint_t j = 0; j < k; ++j ) + { + fp_t tp = ( ts_h( x, i - k + 1 + j ) + ts_l( x, i - k + 1 + j ) + ts_c( x, i - k + 1 + j ) ) / 3.0; + mad_sum += fabs( tp - tp_sma ); + } + mad = mad_sum / (fp_t)k; + + if( mad == 0 ) + y[0][i] = 0; + else + y[0][i] = ( tp_new - tp_sma ) / ( 0.015 * mad ); + } + + return 0; +} + diff --git a/lib/ceiling.c b/lib/ceiling.c new file mode 100644 index 0000000..3dc53d8 --- /dev/null +++ b/lib/ceiling.c @@ -0,0 +1,42 @@ +// Ceiling +// +// ceiling - ceil +// +// f( x ) = ⌈ x ⌉ +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_ceiling_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_ceiling_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_ceiling( + 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_ceiling_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = ceil( x[0][i] ); + } + return 0; +} + + + diff --git a/lib/center_of_gravity.c b/lib/center_of_gravity.c new file mode 100644 index 0000000..3186c44 --- /dev/null +++ b/lib/center_of_gravity.c @@ -0,0 +1,56 @@ +// Center of Gravity +// +// center_of_gravity - COG +// +// 1 - 2 * SUM(i*x_i) / ((k+1) * SUM(x_i)), oscillates around 0 +// +// Inputs: 1 +// Outputs: 1 (COG) +// Constants: 1 (period) + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_center_of_gravity_params_t; + +ts_parameter_t const ts_center_of_gravity_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_center_of_gravity_params_t) }; + +uint_t ts_center_of_gravity_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_center_of_gravity_params_t *)c)->k - 1 : 0 ); +} + +int ts_center_of_gravity( + 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_center_of_gravity_p ); + if ( !c ) return -1; + uint_t k = ((ts_center_of_gravity_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t sum_ix = 0; + fp_t sum_x = 0; + for( uint_t j = 0; j < k; ++j ) + { + fp_t idx = (fp_t)(j + 1); + fp_t val = x[0][i - k + 1 + j]; + sum_ix += idx * val; + sum_x += val; + } + if( sum_x == 0 ) + y[0][i] = 0; + else + y[0][i] = 1.0 - 2.0 * sum_ix / ( ( (fp_t)k + 1.0 ) * sum_x ); + } + return 0; +} + + + diff --git a/lib/chande_forecast_oscillator.c b/lib/chande_forecast_oscillator.c new file mode 100644 index 0000000..6e65bbe --- /dev/null +++ b/lib/chande_forecast_oscillator.c @@ -0,0 +1,67 @@ +// Chande Forecast Oscillator +// +// chande_forecast_oscillator - CFO +// +// (Actual - Forecast) / Forecast * 100, using linear regression forecast +// +// Inputs: 1 +// Outputs: 1 (Oscillator %) +// Constants: 1 (period) + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_chande_forecast_oscillator_params_t; + +ts_parameter_t const ts_chande_forecast_oscillator_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_chande_forecast_oscillator_params_t) }; + +uint_t ts_chande_forecast_oscillator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_chande_forecast_oscillator_params_t *)c)->k - 1 : 0 ); +} + +int ts_chande_forecast_oscillator( + 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_chande_forecast_oscillator_p ); + if ( !c ) return -1; + uint_t k = ((ts_chande_forecast_oscillator_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t sum_x = 0, sum_y = 0, sum_xy = 0, sum_x2 = 0; + for( uint_t j = 0; j < k; ++j ) + { + fp_t xv = (fp_t)j; + fp_t yv = x[0][i - k + 1 + j]; + sum_x += xv; + sum_y += yv; + sum_xy += xv * yv; + sum_x2 += xv * xv; + } + fp_t denom = (fp_t)k * sum_x2 - sum_x * sum_x; + fp_t forecast; + if( denom == 0 ) + forecast = sum_y / (fp_t)k; + else + { + fp_t slope = ( (fp_t)k * sum_xy - sum_x * sum_y ) / denom; + fp_t intercept = ( sum_y - slope * sum_x ) / (fp_t)k; + forecast = intercept + slope * (fp_t)k; + } + if( forecast != 0 ) + y[0][i] = ( x[0][i] - forecast ) / forecast * 100.0; + else + y[0][i] = 0; + } + return 0; +} + + + diff --git a/lib/change.c b/lib/change.c new file mode 100644 index 0000000..84815a5 --- /dev/null +++ b/lib/change.c @@ -0,0 +1,47 @@ +// Percentage Change +// +// change - pct_change +// +// (x[t] - x[t-k]) / x[t-k] * 100 +// +// Inputs: 1 +// Outputs: 1 (Change %) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_change_params_t; + +ts_parameter_t const ts_change_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_change_params_t) }; + +uint_t ts_change_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_change_params_t *)c)->k : 0 ); +} + +int ts_change( + 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_change_p ); + if ( !c ) return -1; + uint_t k = ((ts_change_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k; i < n; ++i ) + { + if( x[0][i - k] == 0 ) { y[0][i] = 0; continue; } + y[0][i] = ( x[0][i] - x[0][i - k] ) / x[0][i - k] * 100; + } + + return 0; +} + + + diff --git a/lib/channel.c b/lib/channel.c new file mode 100644 index 0000000..a2d8bd9 --- /dev/null +++ b/lib/channel.c @@ -0,0 +1,64 @@ +// Channel +// +// channel - Donchian-style channel +// +// Upper: rolling highest high, Lower: rolling lowest low over period k +// +// Inputs: 4 (OHLC) +// Outputs: 2 (Upper, Lower) +// Constants: 1 (period) + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_channel_params_t; + +ts_parameter_t const ts_channel_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_channel_params_t) }; + +uint_t ts_channel_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_channel_params_t *)c)->k - 1 : 0 ); +} + +int ts_channel( + 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_channel_p ); + if ( !c ) return -1; + uint_t k = ((ts_channel_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = k - 1; + uint_t xj = 0; + uint_t yi = k - 1; + + for( ; xi < n; xi++, xj++, yi++ ) + { + y[0][yi] = x[1][xj]; + for( uint_t i = xj; i <= xi; i++ ) + { + if( x[1][i] > y[0][yi] ) + { + y[0][yi] = x[1][i]; + } + } + + y[1][yi] = x[2][xj]; + for( uint_t i = xj; i <= xi; i++ ) + { + if( x[2][i] < y[1][yi] ) + { + y[1][yi] = x[2][i]; + } + } + } + return 0; +} + + + diff --git a/lib/chebyshev_distance.c b/lib/chebyshev_distance.c new file mode 100644 index 0000000..58c055d --- /dev/null +++ b/lib/chebyshev_distance.c @@ -0,0 +1,39 @@ +// Chebyshev Distance +// +// chebyshev_distance - L∞ norm +// +// max(|x|, |y|) +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_chebyshev_distance_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_chebyshev_distance_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_chebyshev_distance( + 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_chebyshev_distance_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = fmax( fabs( x[0][i] ), fabs( x[1][i] ) ); + } + return 0; +} + + + diff --git a/lib/chebyshev_t.c b/lib/chebyshev_t.c new file mode 100644 index 0000000..a0230b8 --- /dev/null +++ b/lib/chebyshev_t.c @@ -0,0 +1,61 @@ +// Chebyshev Polynomial of the First Kind +// +// chebyshev_t - T_n(x) +// +// T_0 = 1, T_1 = x, T_n = 2x*T_(n-1) - T_(n-2) +// +// Inputs: 2 (x, n) +// Outputs: 1 (T_n(x)) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_chebyshev_t_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_chebyshev_t_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_chebyshev_t( + 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_chebyshev_t_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xv = x[0][i]; + uint_t n_val = (uint_t)x[1][i]; + if (x[1][i] < 0 || x[1][i] > 10000) { y[0][i] = 0; continue; } + if( n_val == 0 ) + { + y[0][i] = 1.0; + } + else if( n_val == 1 ) + { + y[0][i] = xv; + } + else + { + fp_t t0 = 1.0; + fp_t t1 = xv; + for( uint_t k = 2; k <= n_val; ++k ) + { + fp_t t2 = 2.0 * xv * t1 - t0; + t0 = t1; + t1 = t2; + } + y[0][i] = t1; + } + } + return 0; +} + + + diff --git a/lib/chi_squared_pdf.c b/lib/chi_squared_pdf.c new file mode 100644 index 0000000..7f2ba09 --- /dev/null +++ b/lib/chi_squared_pdf.c @@ -0,0 +1,49 @@ +// Chi-Squared PDF +// +// chi_squared_pdf - χ² probability density +// +// f(x; k) = x^(k/2-1) * e^(-x/2) / (2^(k/2) * Γ(k/2)), for x > 0 +// +// Inputs: 1 +// Outputs: 1 (PDF value) +// Constants: 1 (degrees of freedom) + +#include <math.h> +#include "ts.h" + +typedef struct { + fp_t k; +} ts_chi_squared_pdf_params_t; + +ts_parameter_t const ts_chi_squared_pdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_chi_squared_pdf_params_t) }; + +uint_t ts_chi_squared_pdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_chi_squared_pdf( + 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_chi_squared_pdf_p ); + if ( !c ) return -1; + fp_t k = ((ts_chi_squared_pdf_params_t *)c)->k; + if ( k <= 0 ) + { + for( uint_t i = 0; i < n; ++i ) y[0][i] = 0; + return -1; + } + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + y[0][i] = xi > 0 ? pow( xi, k / 2.0 - 1.0 ) * exp( -xi / 2.0 ) / ( pow( 2.0, k / 2.0 ) * tgamma( k / 2.0 ) ) : 0.0; + } + return 0; +} + + + diff --git a/lib/choppiness_index.c b/lib/choppiness_index.c new file mode 100644 index 0000000..55ecb46 --- /dev/null +++ b/lib/choppiness_index.c @@ -0,0 +1,68 @@ +// Choppiness Index +// +// choppiness_index - CHOP +// +// 100 * log(SUM(H-L) / Range) / log(k), measures trend vs chop +// +// Inputs: 3 (HLC) +// Outputs: 1 (CHOP) +// Constants: 0 + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_choppiness_index_params_t; + +ts_parameter_t const ts_choppiness_index_p = { .n_inputs = 3, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_choppiness_index_params_t) }; + +uint_t ts_choppiness_index_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? 2 * ((ts_choppiness_index_params_t *)c)->k : 0 ); +} + +int ts_choppiness_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_choppiness_index_p ); + if ( !c ) return -1; + uint_t k = ((ts_choppiness_index_params_t *)c)->k; + uint_t range_period = 2 * k; + if (k == 0 || n < range_period) return -1; + + for ( uint_t i = range_period; i < n; ++i ) + { + fp_t sum_range = 0; + for ( uint_t j = i - k + 1; j <= i; ++j ) + { + sum_range += fabs( ts_h( x, j ) - ts_l( x, j ) ); + } + + fp_t hh = ts_h( x, i - range_period + 1 ); + fp_t ll = ts_l( x, i - range_period + 1 ); + for ( uint_t j = i - range_period + 1; j <= i; ++j ) + { + if ( ts_h( x, j ) > hh ) hh = ts_h( x, j ); + if ( ts_l( x, j ) < ll ) ll = ts_l( x, j ); + } + + fp_t range = hh - ll; + if ( range == 0 || sum_range == 0 || k <= 1 ) + { + y[0][i] = 0; + } + else + { + y[0][i] = 100.0 * log( sum_range / range ) / log( ( fp_t )k ); + } + } + return 0; +} + + + diff --git a/lib/close_minus_open.c b/lib/close_minus_open.c new file mode 100644 index 0000000..45932cb --- /dev/null +++ b/lib/close_minus_open.c @@ -0,0 +1,39 @@ +// Close Minus Open +// +// close_minus_open - C - O +// +// Difference between close and open price +// +// Inputs: 5 (OHLCV) +// Outputs: 1 (C - O) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_close_minus_open_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_close_minus_open_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_close_minus_open( + 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_close_minus_open_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[3][i] - x[0][i]; + } + return 0; +} + + + diff --git a/lib/close_to_high.c b/lib/close_to_high.c new file mode 100644 index 0000000..dc7cf7b --- /dev/null +++ b/lib/close_to_high.c @@ -0,0 +1,40 @@ +// Close to High Ratio +// +// close_to_high - CT_H +// +// (H - C) / (H - L), position of close within daily range +// +// Inputs: 5 (OHLCV) +// Outputs: 1 (ratio) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_close_to_high_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_close_to_high_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_close_to_high( + 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_close_to_high_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t denom = x[1][i] - x[2][i]; + y[0][i] = denom != 0 ? (x[1][i] - x[3][i]) / denom : 0; + } + return 0; +} + + + diff --git a/lib/close_to_open_ratio.c b/lib/close_to_open_ratio.c new file mode 100644 index 0000000..d857dd2 --- /dev/null +++ b/lib/close_to_open_ratio.c @@ -0,0 +1,39 @@ +// Close to Open Ratio +// +// close_to_open_ratio - C/O +// +// Ratio of close to open price +// +// Inputs: 5 (OHLCV) +// Outputs: 1 (ratio) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_close_to_open_ratio_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_close_to_open_ratio_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_close_to_open_ratio( + 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_close_to_open_ratio_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] != 0 ? x[3][i] / x[0][i] : 0; + } + return 0; +} + + + diff --git a/lib/cmf.c b/lib/cmf.c new file mode 100644 index 0000000..7ac0402 --- /dev/null +++ b/lib/cmf.c @@ -0,0 +1,67 @@ +// Chaikin Money Flow +// +// cmf - CMF +// +// SUM(MF * V) / SUM(V) over period, where MF = ((C-L)-(H-C))/(H-L) +// +// Inputs: 5 (OHLCV) +// Outputs: 1 (CMF) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_cmf_params_t; + +ts_parameter_t const ts_cmf_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_cmf_params_t) }; + +uint_t ts_cmf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_cmf_params_t *)c)->k - 1 : 0 ); +} + +int ts_cmf( + 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_cmf_p ); + if ( !c ) return -1; + uint_t k = ((ts_cmf_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t sum_mf = 0; + fp_t sum_vol = 0; + + for ( uint_t i = 0; i < k; ++i ) + { + fp_t hl = ts_h( x, i ) - ts_l( x, i ); + fp_t mf = hl != 0 ? ( ( ts_c( x, i ) - ts_l( x, i ) ) - ( ts_h( x, i ) - ts_c( x, i ) ) ) / hl * ts_v( x, i ) : 0; + sum_mf += mf; + sum_vol += ts_v( x, i ); + } + + y[0][k - 1] = sum_vol != 0 ? sum_mf / sum_vol : 0; + + for ( uint_t i = k; i < n; ++i ) + { + fp_t hl_prev = ts_h( x, i - k ) - ts_l( x, i - k ); + fp_t mf_prev = hl_prev != 0 ? ( ( ts_c( x, i - k ) - ts_l( x, i - k ) ) - ( ts_h( x, i - k ) - ts_c( x, i - k ) ) ) / hl_prev * ts_v( x, i - k ) : 0; + + fp_t hl_cur = ts_h( x, i ) - ts_l( x, i ); + fp_t mf_cur = hl_cur != 0 ? ( ( ts_c( x, i ) - ts_l( x, i ) ) - ( ts_h( x, i ) - ts_c( x, i ) ) ) / hl_cur * ts_v( x, i ) : 0; + + sum_mf = sum_mf - mf_prev + mf_cur; + sum_vol = sum_vol - ts_v( x, i - k ) + ts_v( x, i ); + + y[0][i] = sum_vol != 0 ? sum_mf / sum_vol : 0; + } + return 0; +} + + + diff --git a/lib/cmo.c b/lib/cmo.c new file mode 100644 index 0000000..9db5622 --- /dev/null +++ b/lib/cmo.c @@ -0,0 +1,72 @@ +// Chande Momentum Oscillator +// +// cmo - CMO +// +// 100 * (SUM(up) - SUM(down)) / (SUM(up) + SUM(down)) +// +// Inputs: 1 +// Outputs: 1 (CMO) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_cmo_params_t; + +ts_parameter_t const ts_cmo_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_cmo_params_t) }; + +uint_t ts_cmo_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_cmo_params_t *)c)->k : 0 ); +} + +int ts_cmo( + 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_cmo_p ); + if ( !c ) return -1; + uint_t k = ((ts_cmo_params_t *)c)->k; + if (k == 0 || n <= k) return -1; + + for (uint_t j = 0; j < k; ++j) y[0][j] = 0; + + fp_t up_sum = 0; + fp_t down_sum = 0; + + for( uint_t i = 1; i <= k; ++i ) + { + fp_t diff = x[0][i] - x[0][i - 1]; + if( diff > 0 ) + up_sum += diff; + else if( diff < 0 ) + down_sum += (-diff); + } + + y[0][k] = (up_sum + down_sum) == 0 ? 0 : 100.0 * (up_sum - down_sum) / (up_sum + down_sum); + + for( uint_t i = k + 1; i < n; ++i ) + { + fp_t diff_new = x[0][i] - x[0][i - 1]; + fp_t diff_old = x[0][i - k] - x[0][i - k - 1]; + + fp_t up_new = diff_new > 0 ? diff_new : 0; + fp_t down_new = diff_new < 0 ? (-diff_new) : 0; + fp_t up_old = diff_old > 0 ? diff_old : 0; + fp_t down_old = diff_old < 0 ? (-diff_old) : 0; + + up_sum = up_sum - up_old + up_new; + down_sum = down_sum - down_old + down_new; + + y[0][i] = (up_sum + down_sum) == 0 ? 0 : 100.0 * (up_sum - down_sum) / (up_sum + down_sum); + } + return 0; +} + + + diff --git a/lib/coppock_curve.c b/lib/coppock_curve.c new file mode 100644 index 0000000..dfa1ad2 --- /dev/null +++ b/lib/coppock_curve.c @@ -0,0 +1,75 @@ +// Coppock Curve +// +// coppock_curve - WMS +// +// WMA14(ROC14 + ROC11), weighted moving average of combined ROCs +// +// Inputs: 1 +// Outputs: 1 (Coppock) +// Constants: 0 + +#include <math.h> +#include <stdlib.h> +#include "ts.h" + + +ts_parameter_t const ts_coppock_curve_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_coppock_curve_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 14 ); +} + +int ts_coppock_curve( + 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_coppock_curve_p ); + (void)c; + uint_t roc_long = 14; + uint_t roc_short = 11; + uint_t wma_period = 10; + + if (n == 0 || n < roc_long) return -1; + + fp_t *combined = calloc( n, sizeof( fp_t ) ); + if ( !combined ) return -1; + + for ( uint_t i = roc_long; i < n; ++i ) + { + if ( x[0][i - roc_long] == 0 || x[0][i - roc_short] == 0 ) + { + combined[i - roc_long] = 0; + continue; + } + fp_t roc14 = ( x[0][i] - x[0][i - roc_long] ) / x[0][i - roc_long] * 100.0; + fp_t roc11 = ( x[0][i] - x[0][i - roc_short] ) / x[0][i - roc_short] * 100.0; + combined[i - roc_long] = roc14 + roc11; + } + + for (uint_t j = 0; j < n && j < roc_long; ++j) y[0][j] = 0; + + for ( uint_t i = roc_long; i < n; ++i ) + { + uint_t ci = i - roc_long; + fp_t wsum = 0; + fp_t wtotal = 0; + uint_t start = ci + 1 >= wma_period ? ci + 1 - wma_period : 0; + for ( uint_t j = start; j <= ci; ++j ) + { + uint_t weight = ci - j + 1; + wsum += combined[j] * (fp_t)weight; + wtotal += (fp_t)weight; + } + y[0][ci + roc_long] = wtotal != 0 ? wsum / wtotal : 0; + } + + free( combined ); + return 0; +} + + + diff --git a/lib/copysign.c b/lib/copysign.c new file mode 100644 index 0000000..f146741 --- /dev/null +++ b/lib/copysign.c @@ -0,0 +1,39 @@ +// Copy Sign +// +// copysign - copy sign +// +// Returns x[0] with the sign of x[1] +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_copysign_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_copysign_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_copysign( + 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_copysign_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = copysign( x[0][i], x[1][i] ); + } + return 0; +} + + + diff --git a/lib/correlation_coefficient.c b/lib/correlation_coefficient.c new file mode 100644 index 0000000..d20d1ea --- /dev/null +++ b/lib/correlation_coefficient.c @@ -0,0 +1,75 @@ +// Correlation Coefficient +// +// correlation_coefficient - corr +// +// Pearson r = (n*Σxy - Σx*Σy) / √((n*Σx²-Σx²)(n*Σy²-Σy²)) +// +// Inputs: 2 +// Outputs: 1 (r) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_correlation_coefficient_params_t; + +ts_parameter_t const ts_correlation_coefficient_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_correlation_coefficient_params_t) }; + +uint_t ts_correlation_coefficient_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_correlation_coefficient_params_t *)c)->k - 1 : 0 ); +} + +int ts_correlation_coefficient( + 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_correlation_coefficient_p ); + if ( !c ) return -1; + uint_t k = ((ts_correlation_coefficient_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t sum_x = 0, sum_y = 0, sum_xy = 0, sum_x2 = 0, sum_y2 = 0; + + for ( uint_t i = 0; i < k; ++i ) + { + fp_t xi = x[0][i]; + fp_t yi = x[1][i]; + sum_x += xi; + sum_y += yi; + sum_xy += xi * yi; + sum_x2 += xi * xi; + sum_y2 += yi * yi; + } + + fp_t denom = ( k * sum_x2 - sum_x * sum_x ) * ( k * sum_y2 - sum_y * sum_y ); + fp_t numer = k * sum_xy - sum_x * sum_y; + y[0][k - 1] = denom > 0 ? numer / sqrt( denom ) : 0; + + for ( uint_t i = k; i < n; ++i ) + { + fp_t xi_old = x[0][i - k]; + fp_t yi_old = x[1][i - k]; + fp_t xi_new = x[0][i]; + fp_t yi_new = x[1][i]; + + sum_x = sum_x - xi_old + xi_new; + sum_y = sum_y - yi_old + yi_new; + sum_xy = sum_xy - xi_old * yi_old + xi_new * yi_new; + sum_x2 = sum_x2 - xi_old * xi_old + xi_new * xi_new; + sum_y2 = sum_y2 - yi_old * yi_old + yi_new * yi_new; + + denom = ( k * sum_x2 - sum_x * sum_x ) * ( k * sum_y2 - sum_y * sum_y ); + numer = k * sum_xy - sum_x * sum_y; + y[0][i] = denom > 0 ? numer / sqrt( denom ) : 0; + } + return 0; +} + + + diff --git a/lib/cosecant.c b/lib/cosecant.c new file mode 100644 index 0000000..e2aea17 --- /dev/null +++ b/lib/cosecant.c @@ -0,0 +1,43 @@ +// Cosecant +// +// cosecant - csc +// +// f( x ) = csc( x ) = 1 / sin( x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_cosecant_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_cosecant_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cosecant( + 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_cosecant_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t s = sin( x[0][i] ); + y[0][i] = ( fabs( s ) > 1e-15 ) ? _ts_reciprocal( s ) : ( s > 0 ? (fp_t)INFINITY : (fp_t)-INFINITY ); + } + return 0; +} + + + diff --git a/lib/cosecant_hyperbolic.c b/lib/cosecant_hyperbolic.c new file mode 100644 index 0000000..96898fc --- /dev/null +++ b/lib/cosecant_hyperbolic.c @@ -0,0 +1,45 @@ +// Hyperbolic Cosecant +// +// cosecant_hyperbolic - csch +// +// f( x ) = csch( x ) +// = 1 / sinh( x ) +// = 2 / ( e^x - e^( -x ) ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_cosecant_hyperbolic_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_cosecant_hyperbolic_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cosecant_hyperbolic( + 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_cosecant_hyperbolic_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t s = sinh( x[0][i] ); + y[0][i] = ( fabs( s ) > 1e-15 ) ? _ts_reciprocal( s ) : ( s > 0 ? (fp_t)INFINITY : (fp_t)-INFINITY ); + } + return 0; +} + + + diff --git a/lib/cosecant_hyperbolic_inverse.c b/lib/cosecant_hyperbolic_inverse.c new file mode 100644 index 0000000..a9f0984 --- /dev/null +++ b/lib/cosecant_hyperbolic_inverse.c @@ -0,0 +1,44 @@ +// Inverse Hyperbolic Cosecant +// +// cosecant_hyperbolic_inverse - acsch +// +// f( x ) = acsch( x ) +// = ln( ( 1 / x ) + √( ( 1 / x^2 ) + 1 ) ) x ≠0 +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_cosecant_hyperbolic_inverse_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_cosecant_hyperbolic_inverse_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cosecant_hyperbolic_inverse( + 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_cosecant_hyperbolic_inverse_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xv = x[0][i]; + y[0][i] = xv == 0.0 ? (fp_t)NAN : asinh( _ts_reciprocal( xv ) ); + } + return 0; +} + + + diff --git a/lib/cosecant_inverse.c b/lib/cosecant_inverse.c new file mode 100644 index 0000000..b5f0bbd --- /dev/null +++ b/lib/cosecant_inverse.c @@ -0,0 +1,44 @@ +// Inverse Cosecant +// +// cosecant_inverse - acsc +// +// f( x ) = acsc( x ) +// = asin( 1 / x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_cosecant_inverse_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_cosecant_inverse_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cosecant_inverse( + 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_cosecant_inverse_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t r = _ts_reciprocal( x[0][i] ); + y[0][i] = ( r >= -1.0 && r <= 1.0 ) ? asin( r ) : 0; + } + return 0; +} + + + diff --git a/lib/cosine.c b/lib/cosine.c new file mode 100644 index 0000000..ee039e7 --- /dev/null +++ b/lib/cosine.c @@ -0,0 +1,42 @@ +// Cosine +// +// cosine - cos +// +// f( x ) = cos( x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_cosine_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_cosine_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cosine( + 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_cosine_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = cos( x[0][i] ); + } + return 0; +} + + + diff --git a/lib/cosine_hyperbolic.c b/lib/cosine_hyperbolic.c new file mode 100644 index 0000000..51f84a0 --- /dev/null +++ b/lib/cosine_hyperbolic.c @@ -0,0 +1,43 @@ +// Hyperbolic Cosine +// +// cosine_hyperbolic - cosh +// +// f( x ) = cosh( x ) +// = 0.5 * ( e^x + e^( -x ) ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_cosine_hyperbolic_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_cosine_hyperbolic_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cosine_hyperbolic( + 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_cosine_hyperbolic_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = cosh( x[0][i] ); + } + return 0; +} + + + diff --git a/lib/cosine_inverse.c b/lib/cosine_inverse.c new file mode 100644 index 0000000..dead58a --- /dev/null +++ b/lib/cosine_inverse.c @@ -0,0 +1,43 @@ +// Inverse Cosine +// +// cosine_inverse - acos +// +// f( x ) = acos( x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_cosine_inverse_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_cosine_inverse_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cosine_inverse( + 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_cosine_inverse_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t v = x[0][i]; + y[0][i] = ( v >= -1.0 && v <= 1.0 ) ? acos( v ) : 0; + } + return 0; +} + + + diff --git a/lib/cosine_similarity.c b/lib/cosine_similarity.c new file mode 100644 index 0000000..f93f9b7 --- /dev/null +++ b/lib/cosine_similarity.c @@ -0,0 +1,40 @@ +// Cosine Similarity +// +// cosine_similarity - cos_sim +// +// Sign of the product: +1 if positive, -1 if negative, 0 if zero +// +// Inputs: 2 +// Outputs: 1 (similarity) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_cosine_similarity_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_cosine_similarity_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cosine_similarity( + 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_cosine_similarity_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t p = x[0][i] * x[1][i]; + y[0][i] = p > 0.0 ? 1.0 : ( p < 0.0 ? -1.0 : 0.0 ); + } + return 0; +} + + + diff --git a/lib/cotangent.c b/lib/cotangent.c new file mode 100644 index 0000000..b23b6da --- /dev/null +++ b/lib/cotangent.c @@ -0,0 +1,43 @@ +// Cotangent +// +// cotangent - cot +// +// f( x ) = cot( x ) = 1 / tan( x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_cotangent_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_cotangent_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cotangent( + 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_cotangent_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t t = tan( x[0][i] ); + y[0][i] = ( fabs( t ) > 1e-15 ) ? _ts_reciprocal( t ) : ( t > 0 ? (fp_t)INFINITY : (fp_t)-INFINITY ); + } + return 0; +} + + + diff --git a/lib/cotangent_hyperbolic.c b/lib/cotangent_hyperbolic.c new file mode 100644 index 0000000..dca6a4f --- /dev/null +++ b/lib/cotangent_hyperbolic.c @@ -0,0 +1,46 @@ +// Hyperbolic Cotangent +// +// cotangent_hyperbolic - coth +// +// f( x ) = coth( x ) +// = 1 / tanh( x ) +// = cosh( x ) / sinh( x ) +// = ( e^2x + 1 ) / ( e^2x - 1 ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_cotangent_hyperbolic_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_cotangent_hyperbolic_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cotangent_hyperbolic( + 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_cotangent_hyperbolic_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t t = tanh( x[0][i] ); + y[0][i] = ( fabs( t ) > 1e-15 ) ? _ts_reciprocal( t ) : ( t > 0 ? (fp_t)INFINITY : (fp_t)-INFINITY ); + } + return 0; +} + + + diff --git a/lib/cotangent_hyperbolic_inverse.c b/lib/cotangent_hyperbolic_inverse.c new file mode 100644 index 0000000..3fe2c14 --- /dev/null +++ b/lib/cotangent_hyperbolic_inverse.c @@ -0,0 +1,45 @@ +// Inverse Hyperbolic Cotangent +// +// cottangent_hyperbolic_inverse - acoth +// +// f( x ) = acoth( x ) +// = 0.5 * ln( ( x + 1 ) / ( x - 1 ) ) |x| > 1 +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_cotangent_hyperbolic_inverse_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_cotangent_hyperbolic_inverse_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cotangent_hyperbolic_inverse( + 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_cotangent_hyperbolic_inverse_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + fp_t r = _ts_reciprocal( xi ); + y[0][i] = ( r > -1.0 && r < 1.0 ) ? atanh( r ) : 0; + } + return 0; +} + + + diff --git a/lib/cotangent_inverse.c b/lib/cotangent_inverse.c new file mode 100644 index 0000000..6ad3318 --- /dev/null +++ b/lib/cotangent_inverse.c @@ -0,0 +1,46 @@ +// Inverse Cotangent +// +// cotangent_inverse - acot +// +// f( x ) = acot( x ) +// = atan( 1 / x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_cotangent_inverse_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_cotangent_inverse_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cotangent_inverse( + 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_cotangent_inverse_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t v = x[0][i]; + if ( v > 0 ) y[0][i] = atan( 1.0 / v ); + else if ( v < 0 ) y[0][i] = atan( 1.0 / v ) + PI; + else y[0][i] = PI / 2.0; + } + return 0; +} + + + diff --git a/lib/crossover.c b/lib/crossover.c new file mode 100644 index 0000000..92a0c9e --- /dev/null +++ b/lib/crossover.c @@ -0,0 +1,60 @@ +// Crossover +// +// crossover - crossover +// +// ⎧ -1 if x0_i < x1_i and x0_i-1 > x1_i-1 +// y_i = ⎨ 0 if x = 0 +// ⎩ 1 if x0_i > x1_i and x0_i-1 < x1_i-1 +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_crossover_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_crossover_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 1 ); +} + +int ts_crossover( + 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_crossover_p ); + (void)c; + if ( n < 2 ) return -1; + + uint_t xi; + uint_t yi; + + xi = 1; + yi = 1; + + y[0][0] = 0; + for( ; xi < n; xi++, yi++ ) + { + if( x[0][xi] > x[1][xi] && x[0][xi - 1] <= x[1][xi - 1] ) + y[0][yi] = 1; + + else if( x[0][xi] < x[1][xi] && x[0][xi - 1] >= x[1][xi - 1] ) + y[0][yi] = -1; + + else + y[0][yi] = 0; + } + return 0; +} + + + diff --git a/lib/cumulative_product.c b/lib/cumulative_product.c new file mode 100644 index 0000000..5701deb --- /dev/null +++ b/lib/cumulative_product.c @@ -0,0 +1,42 @@ +// Cumulative Product +// +// cumulative_product - cumprod +// +// y[i] = x[0] * x[1] * ... * x[i] +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_cumulative_product_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_cumulative_product_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cumulative_product( + 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_cumulative_product_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + if( i == 0 ) + y[0][i] = x[0][i]; + else + y[0][i] = y[0][i - 1] * x[0][i]; + } + return 0; +} + + + diff --git a/lib/cumulative_sum.c b/lib/cumulative_sum.c new file mode 100644 index 0000000..417a37f --- /dev/null +++ b/lib/cumulative_sum.c @@ -0,0 +1,42 @@ +// Cumulative Sum +// +// cumulative_sum - cumsum +// +// y[i] = x[0] + x[1] + ... + x[i] +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_cumulative_sum_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_cumulative_sum_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cumulative_sum( + 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_cumulative_sum_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + if( i == 0 ) + y[0][i] = x[0][i]; + else + y[0][i] = y[0][i - 1] + x[0][i]; + } + return 0; +} + + + diff --git a/lib/cumulative_volume_delta.c b/lib/cumulative_volume_delta.c new file mode 100644 index 0000000..d76da1c --- /dev/null +++ b/lib/cumulative_volume_delta.c @@ -0,0 +1,44 @@ +// Cumulative Volume Delta +// +// cumulative_volume_delta - CVD +// +// Running sum of volume weighted by close-open direction +// +// Inputs: 5 (OHLCV) +// Outputs: 1 (CVD) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_cumulative_volume_delta_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_cumulative_volume_delta_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_cumulative_volume_delta( + 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_cumulative_volume_delta_p ); + (void)c; + fp_t cum = 0; + + for( uint_t i = 0; i < n; ++i ) + { + fp_t diff = x[3][i] - x[0][i]; + fp_t sign = ( diff > 0 ) ? 1.0 : ( diff < 0 ) ? -1.0 : 0.0; + cum += x[4][i] * sign; + y[0][i] = cum; + } + return 0; +} + + + diff --git a/lib/cv.c b/lib/cv.c new file mode 100644 index 0000000..0c06250 --- /dev/null +++ b/lib/cv.c @@ -0,0 +1,56 @@ +// ConnorsRSI Volatility +// +// cv - CV +// +// EMA_fast(H-L) - EMA_slow(H-L), volatility measure +// +// Inputs: 5 (OHLCV) +// Outputs: 1 (CV) +// Constants: 2 (fast, slow periods) + +#include <math.h> +#include "ts.h" + +typedef struct { + fp_t fast; + fp_t slow; +} ts_cv_params_t; + +ts_parameter_t const ts_cv_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_cv_params_t) }; + +uint_t ts_cv_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? (uint_t)((ts_cv_params_t *)c)->slow : 0 ); +} + +int ts_cv( + 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_cv_p ); + if ( !c ) return -1; + fp_t fast = ((ts_cv_params_t *)c)->fast; + fp_t slow = ((ts_cv_params_t *)c)->slow; + if (fast == 0 || slow == 0 || n == 0) return -1; + + fp_t a_fast = 1.0 / fast; + fp_t a_slow = 1.0 / slow; + + fp_t ema_fast = ts_h( x, 0 ) - ts_l( x, 0 ); + fp_t ema_slow = ema_fast; + + for( uint_t i = 1; i < n; ++i ) + { + fp_t range = ts_h( x, i ) - ts_l( x, i ); + ema_fast = ema_fast + a_fast * ( range - ema_fast ); + ema_slow = ema_slow + a_slow * ( range - ema_slow ); + y[0][i] = ema_fast - ema_slow; + } + return 0; +} + + + diff --git a/lib/darvas_box.c b/lib/darvas_box.c new file mode 100644 index 0000000..573ed1e --- /dev/null +++ b/lib/darvas_box.c @@ -0,0 +1,54 @@ +// Darvas Box +// +// darvas_box - DB +// +// Upper: highest high over period k +// Lower: lowest low over period k +// +// Inputs: 4 (OHLC) +// Outputs: 2 (Upper, Lower) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_darvas_box_params_t; + +ts_parameter_t const ts_darvas_box_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_darvas_box_params_t) }; + +uint_t ts_darvas_box_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_darvas_box_params_t *)c)->k > 0 ? ((ts_darvas_box_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_darvas_box( + 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_darvas_box_p ); + if ( !c ) return -1; + uint_t k = ((ts_darvas_box_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t hh = ts_h( x, i - k + 1 ); + fp_t ll = ts_l( x, i - k + 1 ); + for( uint_t j = i - k + 1; j <= i; ++j ) + { + if( ts_h( x, j ) > hh ) hh = ts_h( x, j ); + if( ts_l( x, j ) < ll ) ll = ts_l( x, j ); + } + y[0][i] = hh; + y[1][i] = ll; + } + return 0; +} + + + diff --git a/lib/dawsn.c b/lib/dawsn.c new file mode 100644 index 0000000..e77d8b0 --- /dev/null +++ b/lib/dawsn.c @@ -0,0 +1,64 @@ +// Dawson Integral +// +// dawsn - Dawson function +// +// F(x) = e^(-x²) * ∫₀ˣ e^(t²) dt +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_dawsn_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_dawsn_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_dawsn( + 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_dawsn_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t val = x[0][i]; + fp_t ax = fabs( val ); + fp_t y_val; + + if( ax < 3.0 ) + { + fp_t t = ax; + fp_t s = t; + for( uint_t k = 1; k < 20; ++k ) + { + t *= -2.0 * ax * ax / (fp_t)(2 * k + 1); + s += t; + } + y_val = s; + } + else + { + y_val = 1.0 / ( 2.0 * ax + 1.0 / ( 2.0 * ax + 3.0 / ( 2.0 * ax + 5.0 / ( 2.0 * ax ) ) ) ); + } + + if( val < 0 ) + y_val = -y_val; + + y[0][i] = y_val; + } + return 0; +} + + + diff --git a/lib/decay_exponential.c b/lib/decay_exponential.c new file mode 100644 index 0000000..97afe36 --- /dev/null +++ b/lib/decay_exponential.c @@ -0,0 +1,58 @@ +// Exponential Decay +// +// decay_exponential - edecay +// +// DESCRIPTION +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_decay_exponential_params_t; + +ts_parameter_t const ts_decay_exponential_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_decay_exponential_params_t) }; + + +uint_t ts_decay_exponential_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_decay_exponential_params_t *)c)->k : 0 ); +} + +int ts_decay_exponential( + 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_decay_exponential_p ); + if ( !c ) return -1; + uint_t k = ((ts_decay_exponential_params_t *)c)->k; + if (k == 0 || n <= k) return -1; + + fp_t a = ( fp_t ) 1.0 - _ts_reciprocal( k ); + + for( uint_t i = 0; i < k; ++i ) + y[0][i] = 0; + + fp_t prev = x[0][0]; + for( uint_t i = 1; i <= k; ++i ) + prev = fmax( x[0][i], prev * a ); + y[0][k] = prev; + + for( uint_t i = k + 1; i < n; ++i ) + { + y[0][i] = fmax( x[0][i], y[0][i - 1] * a ); + } + return 0; +} + + + diff --git a/lib/decay_linear.c b/lib/decay_linear.c new file mode 100644 index 0000000..8519d13 --- /dev/null +++ b/lib/decay_linear.c @@ -0,0 +1,85 @@ +// Linear Decay +// +// decay_linear - decay +// +// Propogates the maximum values of a function into the future for at most k periods +// +// y_i = max( x_i, y_i-1 - k ) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_decay_linear_params_t; + +ts_parameter_t const ts_decay_linear_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_decay_linear_params_t) }; + + +uint_t ts_decay_linear_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_decay_linear_params_t *)c)->k : 0 ); +} + +int ts_decay_linear( + 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_decay_linear_p ); + if ( !c ) return -1; + uint_t k = ((ts_decay_linear_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for (uint_t zi = 0; zi < k; ++zi) y[0][zi] = 0; + + uint_t xi = 1; + + fp_t prev = x[0][0]; + fp_t r = prev / k; + + for( ; xi < k; xi++ ) + { + prev -= r; + + if( x[0][xi] > prev ) + { + prev = x[0][xi]; + r = x[0][xi] / k; + } + else + { + prev = fmax( prev, 0 ); + } + } + + for( uint_t yi = k; xi < n; xi++, yi++ ) + { + fp_t curr = prev - r; + + if( x[0][xi] > curr ) + { + curr = x[0][xi]; + r = x[0][xi] / k; + } + else + { + curr = fmax( curr, 0 ); + } + + y[0][yi] = curr; + prev = curr; + } + return 0; +} + + + diff --git a/lib/degree_radian.c b/lib/degree_radian.c new file mode 100644 index 0000000..821b67f --- /dev/null +++ b/lib/degree_radian.c @@ -0,0 +1,39 @@ +// Degrees to Radians +// +// degree_radian - deg2rad +// +// y = x * PI / 180 +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_degree_radian_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_degree_radian_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_degree_radian( + 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_degree_radian_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] * PI / 180.0; + } + return 0; +} + + + diff --git a/lib/delta.c b/lib/delta.c new file mode 100644 index 0000000..02ccb66 --- /dev/null +++ b/lib/delta.c @@ -0,0 +1,50 @@ +// Delta +// +// delta - delta +// +// Calculates the delta between the current value and the value k samples ago +// +// y_i = x_i - x_i-k +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_delta_params_t; + +ts_parameter_t const ts_delta_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_delta_params_t) }; + + +uint_t ts_delta_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_delta_params_t *)c)->k : 0 ); +} + +int ts_delta( + 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_delta_p ); + if ( !c ) return -1; + uint_t k = ((ts_delta_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = k; + + for( ; xi < n; xi++ ) + { + y[0][xi] = x[0][xi] - x[0][xi - k]; + } + return 0; +} + + diff --git a/lib/deviation_average.c b/lib/deviation_average.c new file mode 100644 index 0000000..5ac7109 --- /dev/null +++ b/lib/deviation_average.c @@ -0,0 +1,78 @@ +// Moving Mean Deviation +// +// mean_deviation - md +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_deviation_average_params_t; + +ts_parameter_t const ts_deviation_average_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_deviation_average_params_t) }; + + +uint_t ts_deviation_average_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_deviation_average_params_t *)c)->k > 0 ? ((ts_deviation_average_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_deviation_average( + 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_deviation_average_p ); + if ( !c ) return -1; + uint_t k = ((ts_deviation_average_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = 0; + uint_t yi = k - 1; + + fp_t mean = 0; + + for( ; xi < k; ++xi ) + { + mean += x[0][xi]; + } + + fp_t rk = _ts_reciprocal( k ); + mean = rk * mean; + + { + fp_t sum = 0; + for( uint_t i = 0; i < k; i++ ) + { + fp_t tmp = x[0][i] - mean; + sum += fabs( tmp ); + } + y[0][yi] = sum * rk; + } + + for( xi = k, yi = k; xi < n; ++xi, ++yi ) + { + mean = mean + ( x[0][xi] - x[0][xi - k] ) * rk; + fp_t sum = 0; + + for( uint_t i = xi - k + 1; i <= xi; i++ ) + { + fp_t tmp = x[0][i] - mean; + sum += fabs( tmp ); + } + + y[0][yi] = sum * rk; + } + return 0; +} + + + diff --git a/lib/deviation_standard.c b/lib/deviation_standard.c new file mode 100644 index 0000000..a2a0a76 --- /dev/null +++ b/lib/deviation_standard.c @@ -0,0 +1,70 @@ +// Moving Standard Deviation +// +// standard_deviation - sd +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_deviation_standard_params_t; + +ts_parameter_t const ts_deviation_standard_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_deviation_standard_params_t) }; + + +uint_t ts_deviation_standard_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_deviation_standard_params_t *)c)->k > 0 ? ((ts_deviation_standard_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_deviation_standard( + 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_deviation_standard_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_deviation_standard_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = 0; + uint_t yi = k; + + fp_t mean = 0; // Mean + fp_t mean2 = 0; // Mean of squares + + for( ; xi < k; ++xi ) + { + mean += x[0][xi]; + mean2 += _ts_square( x[0][xi] ); + } + + mean /= k; + mean2 /= k; + + fp_t variance = mean2 - _ts_square( mean ); + y[0][k - 1] = variance >= 0 ? sqrt( variance ) : 0; + + fp_t rk = _ts_reciprocal( k ); + + for( ; xi < n; ++xi, ++yi ) + { + mean = mean + ( x[0][xi] - x[0][xi - k] ) * rk; + mean2 = mean2 + ( _ts_square( x[0][xi] ) - _ts_square( x[0][xi - k] ) ) * rk; + + variance = mean2 - _ts_square( mean ); + y[0][yi] = variance >= 0 ? sqrt( variance ) : 0; + } + return 0; +} + + + diff --git a/lib/deviation_standard_average_exponential.c b/lib/deviation_standard_average_exponential.c new file mode 100644 index 0000000..8c484f5 --- /dev/null +++ b/lib/deviation_standard_average_exponential.c @@ -0,0 +1,57 @@ +// Exponential Moving Standard Deviation +// +// standard_deviation_exponential - sde +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +typedef struct { + fp_t a; +} ts_deviation_standard_average_exponential_params_t; + +ts_parameter_t const ts_deviation_standard_average_exponential_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_deviation_standard_average_exponential_params_t) }; + + +uint_t ts_deviation_standard_average_exponential_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_deviation_standard_average_exponential( + 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_deviation_standard_average_exponential_p ); + if ( !c ) return -1; + if (n == 0) return -1; + + fp_t a = ((ts_deviation_standard_average_exponential_params_t *)c)->a; + if (a == 0) return -1; + + y[0][0] = x[0][0]; + + fp_t delta; + fp_t ema = x[0][0]; + fp_t variance = 0; + + for( uint_t i = 1; i < n; ++i ) + { + delta = x[0][i] - ema; + ema = ema + a * delta; + variance = ( 1 - a ) * variance + a * _ts_square( delta ); + y[0][i] = variance >= 0 ? sqrt( variance ) : 0; + } + return 0; +} + + + diff --git a/lib/deviation_vector.c b/lib/deviation_vector.c new file mode 100644 index 0000000..4f10037 --- /dev/null +++ b/lib/deviation_vector.c @@ -0,0 +1,61 @@ +// Vector Standard Deviation +// +// deviation_vector - std_dev +// +// Rolling population standard deviation over period k +// +// Inputs: 1 +// Outputs: 1 (stddev) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_deviation_vector_params_t; + +ts_parameter_t const ts_deviation_vector_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_deviation_vector_params_t) }; + +uint_t ts_deviation_vector_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_deviation_vector_params_t *)c)->k > 0 ? ((ts_deviation_vector_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_deviation_vector( + 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_deviation_vector_p ); + if ( !c ) return -1; + uint_t k = ((ts_deviation_vector_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for (uint_t i = 0; i < n; ++i) + { + if (i < k - 1) + { + y[0][i] = 0; + } + else + { + fp_t sum = 0; + fp_t sum2 = 0; + for (uint_t j = i - k + 1; j <= i; ++j) + { + sum += x[0][j]; + sum2 += x[0][j] * x[0][j]; + } + fp_t mean = sum / k; + fp_t variance = sum2 / k - mean * mean; + y[0][i] = variance >= 0 ? sqrt(variance) : 0; + } + } + return 0; +} + + + diff --git a/lib/di_minus.c b/lib/di_minus.c new file mode 100644 index 0000000..95b0559 --- /dev/null +++ b/lib/di_minus.c @@ -0,0 +1,69 @@ +// Minus Directional Indicator +// +// di_minus - DI- +// +// 100 * EMA(-DM) / (EMA(+DM) + EMA(-DM)), measures downward pressure +// +// Inputs: 4 (OHLC) +// Outputs: 1 (DI-) +// Constants: 1 (period) + +#include <math.h> +#include <stdlib.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_di_minus_params_t; + +ts_parameter_t const ts_di_minus_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_di_minus_params_t) }; + +uint_t ts_di_minus_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_di_minus_params_t *)c)->k : 0 ); +} + +int ts_di_minus( + 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_di_minus_p ); + if ( !c ) return -1; + uint_t k = ((ts_di_minus_params_t *)c)->k; + if (k == 0 || n < 2) return -1; + fp_t *ema_minus = calloc( n, sizeof( fp_t ) ); + fp_t *ema_plus = calloc( n, sizeof( fp_t ) ); + if( !ema_minus || !ema_plus ) { free( ema_minus ); free( ema_plus ); return -1; } + + for( uint_t i = 1; i < n; ++i ) + { + fp_t hdmd = ts_h( x, i ) - ts_h( x, i - 1 ); + fp_t ldml = ts_l( x, i - 1 ) - ts_l( x, i ); + + fp_t minus_dm = ldml > hdmd && ldml > 0 ? ldml : 0; + fp_t plus_dm = hdmd > ldml && hdmd > 0 ? hdmd : 0; + + ema_minus[i] = i == 1 ? minus_dm + : ema_minus[i - 1] + ( 1.0 / k ) * ( minus_dm - ema_minus[i - 1] ); + ema_plus[i] = i == 1 ? plus_dm + : ema_plus[i - 1] + ( 1.0 / k ) * ( plus_dm - ema_plus[i - 1] ); + } + + for (uint_t j = 0; j < n && j < k; ++j) y[0][j] = 0; + + for( uint_t i = k; i < n; ++i ) + { + fp_t denom = ema_minus[i] + ema_plus[i]; + y[0][i] = denom != 0 ? 100.0 * ema_minus[i] / denom : 0; + } + + free( ema_minus ); + free( ema_plus ); + return 0; +} + + + diff --git a/lib/di_plus.c b/lib/di_plus.c new file mode 100644 index 0000000..fb3c076 --- /dev/null +++ b/lib/di_plus.c @@ -0,0 +1,69 @@ +// Plus Directional Indicator +// +// di_plus - DI+ +// +// 100 * EMA(+DM) / (EMA(+DM) + EMA(-DM)), measures upward pressure +// +// Inputs: 4 (OHLC) +// Outputs: 1 (DI+) +// Constants: 1 (period) + +#include <math.h> +#include <stdlib.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_di_plus_params_t; + +ts_parameter_t const ts_di_plus_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_di_plus_params_t) }; + +uint_t ts_di_plus_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_di_plus_params_t *)c)->k : 0 ); +} + +int ts_di_plus( + 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_di_plus_p ); + if ( !c ) return -1; + uint_t k = ((ts_di_plus_params_t *)c)->k; + if (k == 0 || n < 2) return -1; + fp_t *ema_plus = calloc( n, sizeof( fp_t ) ); + fp_t *ema_minus = calloc( n, sizeof( fp_t ) ); + if( !ema_plus || !ema_minus ) { free( ema_plus ); free( ema_minus ); return -1; } + + for( uint_t i = 1; i < n; ++i ) + { + fp_t hdmd = ts_h( x, i ) - ts_h( x, i - 1 ); + fp_t ldml = ts_l( x, i - 1 ) - ts_l( x, i ); + + fp_t plus_dm = hdmd > ldml && hdmd > 0 ? hdmd : 0; + fp_t minus_dm = ldml > hdmd && ldml > 0 ? ldml : 0; + + ema_plus[i] = i == 1 ? plus_dm + : ema_plus[i - 1] + ( 1.0 / k ) * ( plus_dm - ema_plus[i - 1] ); + ema_minus[i] = i == 1 ? minus_dm + : ema_minus[i - 1] + ( 1.0 / k ) * ( minus_dm - ema_minus[i - 1] ); + } + + for (uint_t j = 0; j < n && j < k; ++j) y[0][j] = 0; + + for( uint_t i = k; i < n; ++i ) + { + fp_t denom = ema_plus[i] + ema_minus[i]; + y[0][i] = denom != 0 ? 100.0 * ema_plus[i] / denom : 0; + } + + free( ema_plus ); + free( ema_minus ); + return 0; +} + + + diff --git a/lib/digamma.c b/lib/digamma.c new file mode 100644 index 0000000..267fefc --- /dev/null +++ b/lib/digamma.c @@ -0,0 +1,72 @@ +// Digamma Function +// +// digamma - ψ(z) +// +// Logarithmic derivative of the gamma function: ψ(z) = Γ'(z) / Γ(z) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + +static fp_t digamma_impl( fp_t z ) +{ + if (z > 7.0) + { + fp_t sum = log(z) - 1.0 / (2.0 * z) - 1.0 / (12.0 * z * z); + return sum; + } + + fp_t sum = 0.0; + if (z > 0.0 && z < 7.0) + { + fp_t tmp = z; + while (tmp < 7.0) + { + sum -= 1.0 / tmp; + tmp += 1.0; + } + return sum + digamma_impl(tmp); + } + else if (z == 0.0) + { + return -INFINITY; + } + else if (z < 0.0) + { + fp_t n = floor(z); + fp_t frac = z - n; + return digamma_impl(1.0 - frac) - PI / tan(PI * frac); + } + + return digamma_impl(z + 1.0) - 1.0 / z; +} + + +ts_parameter_t const ts_digamma_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_digamma_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_digamma( + 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_digamma_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = digamma_impl( x[0][i] ); + } + return 0; +} + + + diff --git a/lib/disparity_index.c b/lib/disparity_index.c new file mode 100644 index 0000000..ebf5e0d --- /dev/null +++ b/lib/disparity_index.c @@ -0,0 +1,58 @@ +// Disparity Index +// +// disparity_index - DI +// +// (Price - SMA) / SMA * 100, deviation from moving average +// +// Inputs: 1 +// Outputs: 1 (DI %) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_disparity_index_params_t; + +ts_parameter_t const ts_disparity_index_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_disparity_index_params_t) }; + +uint_t ts_disparity_index_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_disparity_index_params_t *)c)->k > 0 ? ((ts_disparity_index_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_disparity_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_disparity_index_p ); + if ( !c ) return -1; + uint_t k = ((ts_disparity_index_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t sum = 0; + for ( uint_t i = 0; i < k; ++i ) + { + sum += x[0][i]; + } + + fp_t sma = sum / ( fp_t )k; + + for ( uint_t i = k - 1; i < n; ++i ) + { + if ( i >= k ) + { + sma = sma + ( x[0][i] - x[0][i - k] ) / ( fp_t )k; + } + + y[0][i] = sma != 0 ? ( x[0][i] - sma ) / sma * 100.0 : 0; + } + return 0; +} + + + diff --git a/lib/distance.c b/lib/distance.c new file mode 100644 index 0000000..5e473f8 --- /dev/null +++ b/lib/distance.c @@ -0,0 +1,39 @@ +// Euclidean Distance +// +// distance - dist +// +// √(x² + y²), 2D Euclidean distance from origin +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_distance_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_distance_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_distance( + 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_distance_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = sqrt( x[0][i] * x[0][i] + x[1][i] * x[1][i] ); + } + return 0; +} + + + diff --git a/lib/division.c b/lib/division.c new file mode 100644 index 0000000..e132a77 --- /dev/null +++ b/lib/division.c @@ -0,0 +1,41 @@ +// Division +// +// division - div +// +// f( x_0, x_1 ) = x_0 / x_1 +// +// X_n - 2 +// Y_n - 1 +// C_n - 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_division_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_division_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_division( + 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_division_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[1][i] == 0.0 ? 0.0 : x[0][i] / x[1][i]; + } + return 0; +} + + + diff --git a/lib/donchian_channel.c b/lib/donchian_channel.c new file mode 100644 index 0000000..760c396 --- /dev/null +++ b/lib/donchian_channel.c @@ -0,0 +1,60 @@ +// Donchian Channel +// +// donchian_channel - DC +// +// Upper: highest high over k periods +// Lower: lowest low over k periods +// Middle: (Upper + Lower) / 2 +// +// Inputs: 5 (OHLCV) +// Outputs: 3 (Upper, Lower, Middle) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_donchian_channel_params_t; + +ts_parameter_t const ts_donchian_channel_p = { .n_inputs = 4, .n_outputs = 3, .n_constants = 1, .params_size = sizeof(ts_donchian_channel_params_t) }; + +uint_t ts_donchian_channel_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_donchian_channel_params_t *)c)->k > 0 ? ((ts_donchian_channel_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_donchian_channel( + 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_donchian_channel_p ); + if ( !c ) return -1; + uint_t k = ((ts_donchian_channel_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for ( uint_t i = k - 1; i < n; ++i ) + { + fp_t upper = ts_h( x, i - k + 1 ); + fp_t lower = ts_l( x, i - k + 1 ); + + for ( uint_t j = i - k + 1; j <= i; ++j ) + { + if ( ts_h( x, j ) > upper ) + upper = ts_h( x, j ); + if ( ts_l( x, j ) < lower ) + lower = ts_l( x, j ); + } + + y[0][i] = upper; + y[1][i] = lower; + y[2][i] = ( upper + lower ) / 2.0; + } + return 0; +} + + + diff --git a/lib/donchian_width.c b/lib/donchian_width.c new file mode 100644 index 0000000..c69936f --- /dev/null +++ b/lib/donchian_width.c @@ -0,0 +1,56 @@ +// Donchian Width +// +// donchian_width - DW +// +// Highest high - lowest low over k periods +// +// Inputs: 5 (OHLCV) +// Outputs: 1 (Width) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_donchian_width_params_t; + +ts_parameter_t const ts_donchian_width_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_donchian_width_params_t) }; + +uint_t ts_donchian_width_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_donchian_width_params_t *)c)->k > 0 ? ((ts_donchian_width_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_donchian_width( + 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_donchian_width_p ); + if ( !c ) return -1; + uint_t k = ((ts_donchian_width_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for ( uint_t i = k - 1; i < n; ++i ) + { + fp_t upper = ts_h( x, i - k + 1 ); + fp_t lower = ts_l( x, i - k + 1 ); + + for ( uint_t j = i - k + 1; j <= i; ++j ) + { + if ( ts_h( x, j ) > upper ) + upper = ts_h( x, j ); + if ( ts_l( x, j ) < lower ) + lower = ts_l( x, j ); + } + + y[0][i] = upper - lower; + } + return 0; +} + + + diff --git a/lib/dpo.c b/lib/dpo.c new file mode 100644 index 0000000..5bf069b --- /dev/null +++ b/lib/dpo.c @@ -0,0 +1,78 @@ +// Detrended Price Oscillator +// +// dpo - DPO +// +// Price[t] - SMA[k][t - k/2 - 1], centerless moving average +// +// Inputs: 1 +// Outputs: 1 (DPO) +// Constants: 1 (period) + +#include <math.h> +#include <stdlib.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_dpo_params_t; + +ts_parameter_t const ts_dpo_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_dpo_params_t) }; + +uint_t ts_dpo_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_dpo_params_t *)c)->k / 2 + 1 : 0 ); +} + +int ts_dpo( + 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_dpo_p ); + if ( !c ) return -1; + uint_t k = ((ts_dpo_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t sma_period = k; + uint_t offset = k / 2 + 1; + + if (n < sma_period) return -1; + + fp_t sum = 0; + for ( uint_t i = 0; i < sma_period; ++i ) + { + sum += x[0][i]; + } + + fp_t *sma_values = calloc( n, sizeof( fp_t ) ); + if ( !sma_values ) return -1; + + for (uint_t i = 0; i < offset; ++i) y[0][i] = 0; + + uint_t sma_idx = 0; + + for ( uint_t i = sma_period - 1; i < n; ++i ) + { + if ( i == sma_period - 1 ) + { + sma_values[sma_idx] = sum / ( fp_t )sma_period; + } + else + { + sma_values[sma_idx] = sma_values[sma_idx - 1] + ( x[0][i] - x[0][i - sma_period] ) / ( fp_t )sma_period; + } + sma_idx++; + + if ( i >= offset ) + { + y[0][i] = x[0][i] - sma_values[i - offset]; + } + } + + free( sma_values ); + return 0; +} + + diff --git a/lib/dx.c b/lib/dx.c new file mode 100644 index 0000000..b4552fa --- /dev/null +++ b/lib/dx.c @@ -0,0 +1,79 @@ +// Directional Movement Index +// +// dx - DX +// +// 100 * |DI+ - DI-| / (DI+ + DI-), trend strength without smoothing +// +// Inputs: 4 (OHLC) +// Outputs: 1 (DX) +// Constants: 1 (period) + +#include <math.h> +#include <stdlib.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_dx_params_t; + +ts_parameter_t const ts_dx_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_dx_params_t) }; + +uint_t ts_dx_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_dx_params_t *)c)->k : 0 ); +} + +int ts_dx( + 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_dx_p ); + if ( !c ) return -1; + uint_t k = ((ts_dx_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t *plus_dm_arr = calloc( n, sizeof( fp_t ) ); + fp_t *minus_dm_arr = calloc( n, sizeof( fp_t ) ); + fp_t *tr_arr = calloc( n, sizeof( fp_t ) ); + if( !plus_dm_arr || !minus_dm_arr || !tr_arr ) { free( plus_dm_arr ); free( minus_dm_arr ); free( tr_arr ); return -1; } + + y[0][0] = 0; + + for( uint_t i = 1; i < n; ++i ) + { + fp_t hdmd = ts_h( x, i ) - ts_h( x, i - 1 ); + fp_t ldml = ts_l( x, i - 1 ) - ts_l( x, i ); + + fp_t plus_dm = hdmd > ldml && hdmd > 0 ? hdmd : 0; + fp_t minus_dm = ldml > hdmd && ldml > 0 ? ldml : 0; + + fp_t tr = fmax( ts_h( x, i ) - ts_l( x, i ), + fmax( fabs( ts_h( x, i ) - ts_c( x, i - 1 ) ), + fabs( ts_l( x, i ) - ts_c( x, i - 1 ) ) ) ); + + plus_dm_arr[i] = i == 1 ? plus_dm + : plus_dm_arr[i - 1] + ( 1.0 / k ) * ( plus_dm - plus_dm_arr[i - 1] ); + minus_dm_arr[i] = i == 1 ? minus_dm + : minus_dm_arr[i - 1] + ( 1.0 / k ) * ( minus_dm - minus_dm_arr[i - 1] ); + tr_arr[i] = i == 1 ? tr + : tr_arr[i - 1] + ( 1.0 / k ) * ( tr - tr_arr[i - 1] ); + } + + for( uint_t i = k; i < n; ++i ) + { + fp_t di_plus = tr_arr[i] != 0 ? 100.0 * plus_dm_arr[i] / tr_arr[i] : 0; + fp_t di_minus = tr_arr[i] != 0 ? 100.0 * minus_dm_arr[i] / tr_arr[i] : 0; + fp_t sum = di_plus + di_minus; + y[0][i] = sum != 0 ? 100.0 * fabs( di_plus - di_minus ) / sum : 0; + } + + free( plus_dm_arr ); + free( minus_dm_arr ); + free( tr_arr ); + return 0; +} + + diff --git a/lib/ease_of_movement.c b/lib/ease_of_movement.c new file mode 100644 index 0000000..d16f32c --- /dev/null +++ b/lib/ease_of_movement.c @@ -0,0 +1,71 @@ +// Ease of Movement +// +// ease_of_movement - EOM +// +// SMA of (midpoint change) / (volume / range), volume-based momentum +// +// Inputs: 5 (OHLCV) +// Outputs: 1 (EOM) +// Constants: 1 (period) + +#include <stdlib.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_ease_of_movement_params_t; + +ts_parameter_t const ts_ease_of_movement_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_ease_of_movement_params_t) }; + +uint_t ts_ease_of_movement_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 3 ); +} + +int ts_ease_of_movement( + 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_ease_of_movement_p ); + if ( !c ) return -1; + uint_t k = ((ts_ease_of_movement_params_t *)c)->k; + if (k == 0 || n <= k) return -1; + + fp_t *eom = calloc( n, sizeof( fp_t ) ); + if( !eom ) return -1; + + for( uint_t i = 1; i < n; ++i ) + { + fp_t hl = ts_h( x, i ) - ts_l( x, i ); + if( hl == 0 ) continue; + fp_t br = ts_v( x, i ) / hl; + if( br == 0 ) continue; + fp_t cur_mid = ( ts_h( x, i ) + ts_l( x, i ) ) / 2.0; + fp_t prev_mid = ( ts_h( x, i - 1 ) + ts_l( x, i - 1 ) ) / 2.0; + eom[i] = ( cur_mid - prev_mid ) / br; + } + + { + for (uint_t i = 0; i < k; ++i) y[0][i] = 0; + + fp_t sum = 0; + for( uint_t i = 1; i <= k; ++i ) + { + sum += eom[i]; + } + y[0][k] = sum / (fp_t)k; + for( uint_t i = k + 1; i < n; ++i ) + { + sum = sum - eom[i - k] + eom[i]; + y[0][i] = sum / (fp_t)k; + } + } + + free( eom ); + return 0; +} + + diff --git a/lib/elder_force_index.c b/lib/elder_force_index.c new file mode 100644 index 0000000..23cce66 --- /dev/null +++ b/lib/elder_force_index.c @@ -0,0 +1,52 @@ +// Elder Force Index +// +// elder_force_index - EFI +// +// EMA((Close - PrevClose) * Volume), volume-weighted price change +// +// Inputs: 5 (OHLCV) +// Outputs: 1 (EFI) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_elder_force_index_params_t; + +ts_parameter_t const ts_elder_force_index_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_elder_force_index_params_t) }; + +uint_t ts_elder_force_index_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 1 ); +} + +int ts_elder_force_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_elder_force_index_p ); + if ( !c ) return -1; + uint_t k = ((ts_elder_force_index_params_t *)c)->k; + if (k == 0 || n < k) return -1; + fp_t a = 1.0 / k; + + fp_t fi = 0; + if ( n > 1 ) + fi = ( ts_c( x, 1 ) - ts_c( x, 0 ) ) * ts_v( x, 1 ); + y[0][0] = fi; + + for( uint_t i = 1; i < n; ++i ) + { + fi = ( ts_c( x, i ) - ts_c( x, i - 1 ) ) * ts_v( x, i ); + y[0][i] = y[0][i - 1] + a * ( fi - y[0][i - 1] ); + } + + return 0; +} + + diff --git a/lib/elder_impulse.c b/lib/elder_impulse.c new file mode 100644 index 0000000..d629e7c --- /dev/null +++ b/lib/elder_impulse.c @@ -0,0 +1,70 @@ +// Elder Impulse System +// +// elder_impulse - EIS +// +// Impulse: Price - SMA(k), Trend: SMA(Impulse, k) +// +// Inputs: 1 +// Outputs: 2 (Impulse, Trend) +// Constants: 1 (period) + +#include <stdlib.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_elder_impulse_params_t; + +ts_parameter_t const ts_elder_impulse_p = { .n_inputs = 1, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_elder_impulse_params_t) }; + +uint_t ts_elder_impulse_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? 2 * ((ts_elder_impulse_params_t *)c)->k - 1 : 0 ); +} + +int ts_elder_impulse( + 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_elder_impulse_p ); + if ( !c ) return -1; + uint_t k = ((ts_elder_impulse_params_t *)c)->k; + if (k == 0 || n < 2 * k - 1) return -1; + + fp_t *sma = malloc( n * sizeof( fp_t ) ); + fp_t *impulse = malloc( n * sizeof( fp_t ) ); + if ( !sma || !impulse ) { free( sma ); free( impulse ); return -1; } + + for (uint_t i = 0; i < 2 * k - 1; ++i) { y[0][i] = 0; y[1][i] = 0; } + + for ( uint_t i = k - 1; i < n; ++i ) + { + fp_t sum = 0; + for ( uint_t j = 0; j < k; ++j ) + { + sum += x[0][i - j]; + } + sma[i] = sum / (fp_t)k; + impulse[i] = x[0][i] - sma[i]; + } + + for ( uint_t i = 2 * k - 1; i < n; ++i ) + { + y[0][i] = impulse[i]; + + fp_t sum = 0; + for ( uint_t j = 0; j < k; ++j ) + { + sum += impulse[i - j]; + } + y[1][i] = sum / (fp_t)k; + } + + free( sma ); free( impulse ); + return 0; +} + + diff --git a/lib/elder_ray.c b/lib/elder_ray.c new file mode 100644 index 0000000..a0f330f --- /dev/null +++ b/lib/elder_ray.c @@ -0,0 +1,58 @@ +// Elder Ray Index +// +// elder_ray - ERI +// +// Bull Power: High - EMA(Close) +// Bear Power: Low - EMA(Close) +// +// Inputs: 4 (OHLC) +// Outputs: 2 (Bull Power, Bear Power) +// Constants: 1 (EMA period) + +#include <math.h> +#include <stdlib.h> +#include "ts.h" + +typedef struct { + fp_t k; +} ts_elder_ray_params_t; + +ts_parameter_t const ts_elder_ray_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_elder_ray_params_t) }; + +uint_t ts_elder_ray_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_elder_ray( + 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_elder_ray_p ); + if ( !c ) return -1; + fp_t k = ((ts_elder_ray_params_t *)c)->k; + if (k == 0 || n < k) return -1; + fp_t a = 1.0 / k; + fp_t *ema = calloc( n, sizeof( fp_t ) ); + if( !ema ) return -1; + + ema[0] = ts_c( x, 0 ); + + for( uint_t i = 0; i < n; ++i ) + { + if( i > 0 ) + { + ema[i] = ema[i - 1] + a * ( ts_c( x, i ) - ema[i - 1] ); + } + y[0][i] = ts_h( x, i ) - ema[i]; + y[1][i] = ts_l( x, i ) - ema[i]; + } + + free( ema ); + return 0; +} + + diff --git a/lib/ellint_1.c b/lib/ellint_1.c new file mode 100644 index 0000000..8e0bab7 --- /dev/null +++ b/lib/ellint_1.c @@ -0,0 +1,65 @@ +// Complete Elliptic Integral of the First Kind +// +// ellint_1 - K(m) +// +// K(m) = ∫₀^(π/2) dθ / √(1 - m*sin²(θ)), computed via AGM +// +// Inputs: 1 (parameter m) +// Outputs: 1 (K(m)) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_ellint_1_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_ellint_1_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_ellint_1( + 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_ellint_1_p ); + (void)c; + /* Complete elliptic integral of the first kind K(m) */ + for (uint_t i = 0; i < n; ++i) + { + fp_t m = x[0][i]; + if (m <= 0.0) + { + y[0][i] = PI / 2.0; + } + else if (m >= 1.0) + { + y[0][i] = INFINITY; + } + else + { + /* Arithmetic-geometric mean method */ + fp_t a = 1.0; + fp_t b = sqrt(1.0 - m); + fp_t cn = (a - b) / 2.0; + for (uint_t j = 0; j < 30; ++j) + { + fp_t a_new = (a + b) / 2.0; + fp_t b_new = sqrt(a * b); + fp_t cn_new = (a_new - b_new) / 2.0; + a = a_new; + b = b_new; + cn = cn_new; + if (cn / a < 1e-15) break; + } + y[0][i] = PI / (2.0 * a); + } + } + return 0; +} + + diff --git a/lib/ellint_2.c b/lib/ellint_2.c new file mode 100644 index 0000000..59660cd --- /dev/null +++ b/lib/ellint_2.c @@ -0,0 +1,64 @@ +// Complete Elliptic Integral of the Second Kind +// +// ellint_2 - E(m) +// +// E(m) = ∫₀^(π/2) √(1 - m*sin²(θ)) dθ, computed via AGM +// +// Inputs: 1 (parameter m) +// Outputs: 1 (E(m)) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_ellint_2_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_ellint_2_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_ellint_2( + 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_ellint_2_p ); + (void)c; + for (uint_t i = 0; i < n; ++i) + { + fp_t m = x[0][i]; + if (m <= 0.0) + { + y[0][i] = PI / 2.0; + } + else if (m >= 1.0) + { + y[0][i] = 1.0; + } + else + { + fp_t a = 1.0; + fp_t b = sqrt(1.0 - m); + fp_t s = 0.0; + fp_t scale = 0.5; + for (uint_t j = 0; j < 30; ++j) + { + fp_t a_new = (a + b) / 2.0; + fp_t b_new = sqrt(a * b); + fp_t c_new = (a - b) / 2.0; + s += scale * c_new * c_new; + a = a_new; + b = b_new; + scale *= 2.0; + if (c_new < 1e-15) break; + } + y[0][i] = (PI / (2.0 * a)) * (1.0 - s); + } + } + return 0; +} + diff --git a/lib/ema_variable.c b/lib/ema_variable.c new file mode 100644 index 0000000..c20fee2 --- /dev/null +++ b/lib/ema_variable.c @@ -0,0 +1,48 @@ +// Variable EMA +// +// ema_variable - EMA +// +// EMA with alpha = 2/(k+1): y = prev + alpha * (x - prev) +// +// Inputs: 1 +// Outputs: 1 (EMA) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + fp_t k; +} ts_ema_variable_params_t; + +ts_parameter_t const ts_ema_variable_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_ema_variable_params_t) }; + +uint_t ts_ema_variable_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_ema_variable( + 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_ema_variable_p ); + if ( !c ) return -1; + fp_t k = ((ts_ema_variable_params_t *)c)->k; + if (k <= 0) return -1; + if (n == 0) return -1; + + fp_t alpha = 2.0 / (k + 1.0); + y[0][0] = x[0][0]; + + for (uint_t i = 1; i < n; ++i) + { + y[0][i] = y[0][i - 1] + alpha * (x[0][i] - y[0][i - 1]); + } + return 0; +} + + diff --git a/lib/envelope.c b/lib/envelope.c new file mode 100644 index 0000000..1ddda0c --- /dev/null +++ b/lib/envelope.c @@ -0,0 +1,60 @@ +// Price Envelope +// +// envelope - ENV +// +// Upper: SMA * (1 + pct), Lower: SMA * (1 - pct) +// +// Inputs: 1 +// Outputs: 2 (Upper, Lower) +// Constants: 2 (period, percentage) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; + fp_t pct; +} ts_envelope_params_t; + +ts_parameter_t const ts_envelope_p = { .n_inputs = 1, .n_outputs = 2, .n_constants = 2, .params_size = sizeof(ts_envelope_params_t) }; + +uint_t ts_envelope_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_envelope_params_t *)c)->k > 0 ? ((ts_envelope_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_envelope( + 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_envelope_p ); + if ( !c ) return -1; + uint_t k = ((ts_envelope_params_t *)c)->k; + fp_t pct = ((ts_envelope_params_t *)c)->pct; + if (k == 0 || n < k) return -1; + + fp_t sum = 0; + for ( uint_t i = 0; i < k; ++i ) + { + sum += x[0][i]; + } + + fp_t sma = sum / ( fp_t )k; + + for ( uint_t i = k - 1; i < n; ++i ) + { + if ( i >= k ) + { + sma = sma + ( x[0][i] - x[0][i - k] ) / ( fp_t )k; + } + + y[0][i] = sma * ( 1.0 + pct ); + y[1][i] = sma * ( 1.0 - pct ); + } + return 0; +} + + diff --git a/lib/erf.c b/lib/erf.c new file mode 100644 index 0000000..54bf625 --- /dev/null +++ b/lib/erf.c @@ -0,0 +1,38 @@ +// Error Function +// +// erf - error function +// +// erf(x) = (2/√π) * ∫₀ˣ e^(-t²) dt +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_erf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_erf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_erf( + 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_erf_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = erf( x[0][i] ); + } + return 0; +} + + diff --git a/lib/erfc.c b/lib/erfc.c new file mode 100644 index 0000000..e6e1492 --- /dev/null +++ b/lib/erfc.c @@ -0,0 +1,38 @@ +// Complementary Error Function +// +// erfc - complementary error function +// +// erfc(x) = 1 - erf(x) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_erfc_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_erfc_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_erfc( + 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_erfc_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = erfc( x[0][i] ); + } + return 0; +} + + diff --git a/lib/euclidean_norm.c b/lib/euclidean_norm.c new file mode 100644 index 0000000..6de406d --- /dev/null +++ b/lib/euclidean_norm.c @@ -0,0 +1,38 @@ +// Euclidean Norm +// +// euclidean_norm - L2 norm +// +// √(x² + y²), 2D vector magnitude +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_euclidean_norm_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_euclidean_norm_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_euclidean_norm( + 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_euclidean_norm_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = hypot( x[0][i], x[1][i] ); + } + return 0; +} + + diff --git a/lib/exp10.c b/lib/exp10.c new file mode 100644 index 0000000..b4bb568 --- /dev/null +++ b/lib/exp10.c @@ -0,0 +1,40 @@ +// Base-10 Exponential +// +// exp10 - 10^x +// +// y = 10^x +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_exp10_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_exp10_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_exp10( + 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_exp10_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = pow( 10.0, x[0][i] ); + } + return 0; +} + + diff --git a/lib/exp10m1.c b/lib/exp10m1.c new file mode 100644 index 0000000..bf19615 --- /dev/null +++ b/lib/exp10m1.c @@ -0,0 +1,38 @@ +// Base-10 Exponential Minus 1 +// +// exp10m1 - 10^x - 1 +// +// y = 10^x - 1, computed as expm1(x * ln(10)) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_exp10m1_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_exp10m1_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_exp10m1( + 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_exp10m1_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = expm1( x[0][i] * log( 10.0 ) ); + } + return 0; +} + + diff --git a/lib/exp2.c b/lib/exp2.c new file mode 100644 index 0000000..b70bf1c --- /dev/null +++ b/lib/exp2.c @@ -0,0 +1,40 @@ +// Base-2 Exponential +// +// exp2 - 2^x +// +// y = 2^x +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_exp2_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_exp2_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_exp2( + 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_exp2_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = exp2( x[0][i] ); + } + return 0; +} + + diff --git a/lib/exp2m1.c b/lib/exp2m1.c new file mode 100644 index 0000000..d0c6fb1 --- /dev/null +++ b/lib/exp2m1.c @@ -0,0 +1,38 @@ +// Base-2 Exponential Minus 1 +// +// exp2m1 - 2^x - 1 +// +// y = 2^x - 1, computed as expm1(x * ln(2)) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_exp2m1_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_exp2m1_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_exp2m1( + 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_exp2m1_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = expm1( x[0][i] * log( 2.0 ) ); + } + return 0; +} + + diff --git a/lib/expit.c b/lib/expit.c new file mode 100644 index 0000000..e58b528 --- /dev/null +++ b/lib/expit.c @@ -0,0 +1,40 @@ +// Inverse Logit (Expit) +// +// expit - logistic function +// +// y = 1 / (1 + e^(-x)) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_expit_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_expit_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_expit( + 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_expit_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = 1.0 / ( 1.0 + exp( -x[0][i] ) ); + } + return 0; +} + + diff --git a/lib/expm1.c b/lib/expm1.c new file mode 100644 index 0000000..c6cb7a2 --- /dev/null +++ b/lib/expm1.c @@ -0,0 +1,40 @@ +// Exponential Minus 1 +// +// expm1 - e^x - 1 +// +// y = e^x - 1, accurate for small x +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_expm1_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_expm1_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_expm1( + 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_expm1_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = expm1( x[0][i] ); + } + return 0; +} + + diff --git a/lib/exponential.c b/lib/exponential.c new file mode 100644 index 0000000..b3a6205 --- /dev/null +++ b/lib/exponential.c @@ -0,0 +1,49 @@ +// Exponential +// +// exponential - exp +// +// f( x ) = b^x +// +// X_n - 1 +// Y_n - 1 +// C_n - 1 +// +// c[0] = b + + +#include <math.h> +#include "ts.h" + + +typedef struct { + fp_t b; +} ts_exponential_params_t; + +ts_parameter_t const ts_exponential_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_exponential_params_t) }; + + +uint_t ts_exponential_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_exponential( + 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_exponential_p ); + if ( !c ) return -1; + fp_t b = ((ts_exponential_params_t *)c)->b; + if (b <= 0) return -1; + + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = pow( b, x[0][i] ); + } + return 0; +} + + diff --git a/lib/exponential_cdf.c b/lib/exponential_cdf.c new file mode 100644 index 0000000..95c7ba8 --- /dev/null +++ b/lib/exponential_cdf.c @@ -0,0 +1,38 @@ +// Exponential CDF +// +// exponential_cdf - exponential cumulative distribution +// +// F(x) = 1 - e^(-x) for x >= 0, else 0 +// +// Inputs: 1 +// Outputs: 1 (CDF value) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_exponential_cdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_exponential_cdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_exponential_cdf( + 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_exponential_cdf_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] >= 0 ? 1.0 - exp( -x[0][i] ) : 0.0; + } + return 0; +} + + diff --git a/lib/exponential_natural.c b/lib/exponential_natural.c new file mode 100644 index 0000000..61a217c --- /dev/null +++ b/lib/exponential_natural.c @@ -0,0 +1,41 @@ +// Natural Exponential +// +// exponential_natural - expn +// +// f( x ) = e^x +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_exponential_natural_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_exponential_natural_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_exponential_natural( + 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_exponential_natural_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = exp( x[0][i] ); + } + return 0; +} + + diff --git a/lib/exponential_pdf.c b/lib/exponential_pdf.c new file mode 100644 index 0000000..ccb942a --- /dev/null +++ b/lib/exponential_pdf.c @@ -0,0 +1,38 @@ +// Exponential PDF +// +// exponential_pdf - exponential probability density +// +// f(x) = e^(-x) for x >= 0, else 0 +// +// Inputs: 1 +// Outputs: 1 (PDF value) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_exponential_pdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_exponential_pdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_exponential_pdf( + 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_exponential_pdf_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] >= 0 ? exp( -x[0][i] ) : 0.0; + } + return 0; +} + + diff --git a/lib/factorial.c b/lib/factorial.c new file mode 100644 index 0000000..8e64fa3 --- /dev/null +++ b/lib/factorial.c @@ -0,0 +1,47 @@ +// Factorial +// +// factorial - n! +// +// n! = 1 * 2 * ... * n, capped at 170! +// +// Inputs: 1 (n) +// Outputs: 1 (n!) +// Constants: 0 + +#include "ts.h" + + + +ts_parameter_t const ts_factorial_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_factorial_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_factorial( + 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_factorial_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + if (x[0][i] < 0) { y[0][i] = NAN; continue; } + fp_t result = 1.0; + uint_t k = (uint_t)x[0][i]; + if (k > 170) k = 170; + for( uint_t j = 1; j <= k; ++j ) + { + result *= (fp_t)j; + } + y[0][i] = result; + } + return 0; +} + + diff --git a/lib/factorial_int.c b/lib/factorial_int.c new file mode 100644 index 0000000..51250aa --- /dev/null +++ b/lib/factorial_int.c @@ -0,0 +1,45 @@ +// Integer Factorial +// +// factorial_int - n! +// +// n! = 1 * 2 * ... * n, capped at 170! +// +// Inputs: 1 (n) +// Outputs: 1 (n!) +// Constants: 0 + +#include "ts.h" + + +ts_parameter_t const ts_factorial_int_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_factorial_int_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_factorial_int( + 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_factorial_int_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + if (x[0][i] < 0) { y[0][i] = NAN; continue; } + uint_t n_val = (uint_t)x[0][i]; + if (n_val > 170) n_val = 170; + fp_t result = 1.0; + for( uint_t k = 2; k <= n_val; ++k ) + { + result *= (fp_t)k; + } + y[0][i] = result; + } + return 0; +} + + diff --git a/lib/fdim_2input.c b/lib/fdim_2input.c new file mode 100644 index 0000000..8d841ad --- /dev/null +++ b/lib/fdim_2input.c @@ -0,0 +1,38 @@ +// Positive Difference +// +// fdim_2input - fdim(x, 0) +// +// max(x - 0, 0), positive part of x +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_fdim_2input_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_fdim_2input_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_fdim_2input( + 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_fdim_2input_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = fdim( x[0][i], 0.0 ); + } + return 0; +} + + diff --git a/lib/fibonacci.c b/lib/fibonacci.c new file mode 100644 index 0000000..43cd9a0 --- /dev/null +++ b/lib/fibonacci.c @@ -0,0 +1,49 @@ +// Fibonacci Number +// +// fibonacci - F(n) +// +// F(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2) +// +// Inputs: 1 (n) +// Outputs: 1 (F(n)) +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_fibonacci_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_fibonacci_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_fibonacci( + 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_fibonacci_p ); + (void)c; + for (uint_t i = 0; i < n; ++i) + { + if (x[0][i] < 0) { y[0][i] = 0; continue; } + uint_t k = (uint_t)floor(x[0][i]); + if (k == 0) { y[0][i] = 0; continue; } + if (k == 1) { y[0][i] = 1; continue; } + fp_t a = 0, b = 1, cv = 0; + for (uint_t j = 2; j <= k; ++j) + { + cv = a + b; + a = b; + b = cv; + } + y[0][i] = cv; + } + return 0; +} + + diff --git a/lib/fill_indicator.c b/lib/fill_indicator.c new file mode 100644 index 0000000..9cb9cbc --- /dev/null +++ b/lib/fill_indicator.c @@ -0,0 +1,63 @@ +// Fill Indicator +// +// fill_indicator - FI +// +// SMA of |C-O|/(H-L)*100, measures candle body fill ratio +// +// Inputs: 4 (OHLC) +// Outputs: 1 (FI) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_fill_indicator_params_t; + +ts_parameter_t const ts_fill_indicator_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_fill_indicator_params_t) }; + +uint_t ts_fill_indicator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_fill_indicator_params_t *)c)->k > 0 ? ((ts_fill_indicator_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_fill_indicator( + 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_fill_indicator_p ); + if ( !c ) return -1; + uint_t k = ((ts_fill_indicator_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = 0; + uint_t yi = k - 1; + + fp_t sum = 0; + + for( ; xi < k; ++xi ) + { + fp_t range = ts_h( x, xi ) - ts_l( x, xi ); + if (range != 0) + sum += fabs( ts_c( x, xi ) - ts_o( x, xi ) ) / range * 100; + } + + y[0][yi] = sum / k; + ++yi; + + for( ; xi < n; ++xi, ++yi ) + { + fp_t range = ts_h( x, xi ) - ts_l( x, xi ); + fp_t fv = range != 0 ? fabs( ts_c( x, xi ) - ts_o( x, xi ) ) / range * 100 : 0; + fp_t range_old = ts_h( x, xi - k ) - ts_l( x, xi - k ); + fp_t fo = range_old != 0 ? fabs( ts_c( x, xi - k ) - ts_o( x, xi - k ) ) / range_old * 100 : 0; + y[0][yi] = y[0][yi - 1] + ( fv - fo ) / k; + } + return 0; +} + + diff --git a/lib/fisher_transform.c b/lib/fisher_transform.c new file mode 100644 index 0000000..2b416ba --- /dev/null +++ b/lib/fisher_transform.c @@ -0,0 +1,78 @@ +// Fisher Transform +// +// fisher_transform - FT +// +// 0.5 * log(price_position / (1 - price_position)), normalized to range +// +// Inputs: 4 (OHLC) +// Outputs: 2 (Transform, Trigger) +// Constants: 1 (period) + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_fisher_transform_params_t; + +ts_parameter_t const ts_fisher_transform_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_fisher_transform_params_t) }; + +uint_t ts_fisher_transform_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_fisher_transform_params_t *)c)->k - 1 : 0 ); +} + +int ts_fisher_transform( + 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_fisher_transform_p ); + if ( !c ) return -1; + uint_t k = ((ts_fisher_transform_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for (uint_t i = k - 1; i < n; ++i) + { + /* Find high and low over window */ + fp_t hh = x[1][i - k + 1]; + fp_t ll = x[2][i - k + 1]; + for (uint_t j = i - k + 2; j <= i; ++j) + { + if (x[1][j] > hh) hh = x[1][j]; + if (x[2][j] < ll) ll = x[2][j]; + } + + fp_t range = hh - ll; + fp_t val = range != 0 ? (x[3][i] - ll) / range : 0.5; + + /* Clamp to [0.01, 0.99] to avoid log(0) */ + if (val < 0.01) val = 0.01; + if (val > 0.99) val = 0.99; + + fp_t fisher = 0.5 * log(val / (1.0 - val)); + + /* Smooth with previous value (skip first output) */ + uint_t out_i = i; + if (i > k - 1) + { + fisher = fisher + 0.5 * y[0][out_i - 1]; + } + y[0][out_i] = fisher; + + /* Trigger line = previous fisher */ + if (out_i > 0) + { + y[1][out_i] = y[0][out_i - 1]; + } + else + { + y[1][out_i] = 0; + } + } + return 0; +} + + diff --git a/lib/floor.c b/lib/floor.c new file mode 100644 index 0000000..0a77858 --- /dev/null +++ b/lib/floor.c @@ -0,0 +1,41 @@ +// Floor +// +// floor - floor +// +// f( x ) = ⌊ x ⌋ +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_floor_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_floor_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_floor( + 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_floor_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = floor( x[0][i] ); + } + return 0; +} + + diff --git a/lib/fma.c b/lib/fma.c new file mode 100644 index 0000000..795dc08 --- /dev/null +++ b/lib/fma.c @@ -0,0 +1,38 @@ +// Fused Multiply-Add +// +// fma - fused multiply-add +// +// x * y + z, computed in single precision +// +// Inputs: 3 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_fma_p = { .n_inputs = 3, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_fma_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_fma( + 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_fma_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = fma( x[0][i], x[1][i], x[2][i] ); + } + return 0; +} + + diff --git a/lib/fmax.c b/lib/fmax.c new file mode 100644 index 0000000..63eb5a7 --- /dev/null +++ b/lib/fmax.c @@ -0,0 +1,38 @@ +// Maximum +// +// fmax - max(x, y) +// +// Returns the maximum of two values +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_fmax_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_fmax_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_fmax( + 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_fmax_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = fmax( x[0][i], x[1][i] ); + } + return 0; +} + + diff --git a/lib/fmax_2input.c b/lib/fmax_2input.c new file mode 100644 index 0000000..b29eee5 --- /dev/null +++ b/lib/fmax_2input.c @@ -0,0 +1,38 @@ +// Maximum with Zero +// +// fmax_2input - max(x, 0) +// +// Returns the maximum of x and 0 +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_fmax_2input_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_fmax_2input_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_fmax_2input( + 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_fmax_2input_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = fmax( x[0][i], 0.0 ); + } + return 0; +} + + diff --git a/lib/fmin.c b/lib/fmin.c new file mode 100644 index 0000000..5820841 --- /dev/null +++ b/lib/fmin.c @@ -0,0 +1,38 @@ +// Minimum +// +// fmin - min(x, y) +// +// Returns the minimum of two values +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_fmin_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_fmin_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_fmin( + 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_fmin_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = fmin( x[0][i], x[1][i] ); + } + return 0; +} + + diff --git a/lib/fmin_2input.c b/lib/fmin_2input.c new file mode 100644 index 0000000..ba4cd5c --- /dev/null +++ b/lib/fmin_2input.c @@ -0,0 +1,38 @@ +// Minimum with Zero +// +// fmin_2input - min(x, 0) +// +// Returns the minimum of x and 0 +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_fmin_2input_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_fmin_2input_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_fmin_2input( + 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_fmin_2input_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = fmin( x[0][i], 0.0 ); + } + return 0; +} + + diff --git a/lib/fmod.c b/lib/fmod.c new file mode 100644 index 0000000..75317bd --- /dev/null +++ b/lib/fmod.c @@ -0,0 +1,38 @@ +// Floating Modulo +// +// fmod - floating-point remainder +// +// x mod y, remainder of x/y +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_fmod_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_fmod_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_fmod( + 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_fmod_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = fmod( x[0][i], x[1][i] ); + } + return 0; +} + + diff --git a/lib/fobv.c b/lib/fobv.c new file mode 100644 index 0000000..7134cca --- /dev/null +++ b/lib/fobv.c @@ -0,0 +1,43 @@ +// On-Balance Volume +// +// fobv - OBV +// +// Cumulative volume: add on up days, subtract on down days +// +// Inputs: 5 (OHLCV) +// Outputs: 1 (OBV) +// Constants: 0 + +#include "ts.h" + + +ts_parameter_t const ts_fobv_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_fobv_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 1 ); +} + +int ts_fobv( + 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_fobv_p ); + (void)c; + if (n > 0) y[0][0] = 0; + fp_t obv = 0; + + for (uint_t i = 1; i < n; ++i) + { + if (x[3][i] > x[3][i - 1]) + obv += x[4][i]; + else if (x[3][i] < x[3][i - 1]) + obv -= x[4][i]; + y[0][i] = obv; + } + return 0; +} + diff --git a/lib/fractal_chaos_bands.c b/lib/fractal_chaos_bands.c new file mode 100644 index 0000000..57bbf00 --- /dev/null +++ b/lib/fractal_chaos_bands.c @@ -0,0 +1,74 @@ +// Fractal Chaos Bands +// +// fractal_chaos_bands +// +// Elder's Fractal Chaos Bands using fractal channels +// +// Upper/Lower: fractal-based channel boundaries +// +// Inputs: 4 +// Outputs: 2 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_fractal_chaos_bands_params_t; + +ts_parameter_t const ts_fractal_chaos_bands_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_fractal_chaos_bands_params_t) }; + +uint_t ts_fractal_chaos_bands_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_fractal_chaos_bands_params_t *)c)->k / 2 : 0 ); +} + +int ts_fractal_chaos_bands( + 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_fractal_chaos_bands_p ); + if ( !c ) return -1; + uint_t k = ((ts_fractal_chaos_bands_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t alpha = 2.0 / (k + 1.0); + uint_t half_k = k / 2; + + fp_t ema_upper = 0; + fp_t ema_lower = 0; + uint_t ema_count = 0; + + for (uint_t i = half_k; i < n - half_k; ++i) + { + fp_t fh = x[1][i]; + fp_t fl = x[2][i]; + for (int_t j = -(int_t)half_k; j <= (int_t)half_k; ++j) + { + uint_t idx = (uint_t)((int_t)i + j); + if (x[1][idx] > fh) fh = x[1][idx]; + if (x[2][idx] < fl) fl = x[2][idx]; + } + + if (ema_count == 0) + { + ema_upper = fh; + ema_lower = fl; + } + else + { + ema_upper = ema_upper + alpha * (fh - ema_upper); + ema_lower = ema_lower + alpha * (fl - ema_lower); + } + ema_count++; + + y[0][i] = ema_upper; + y[1][i] = ema_lower; + } + return 0; +} + diff --git a/lib/fractal_chaos_oscillator.c b/lib/fractal_chaos_oscillator.c new file mode 100644 index 0000000..5c845d3 --- /dev/null +++ b/lib/fractal_chaos_oscillator.c @@ -0,0 +1,73 @@ +// Fractal Chaos Oscillator +// +// fractal_chaos_oscillator +// +// Fractal Chaos Oscillator +// +// Oscillator derived from fractal chaos bands +// +// Inputs: 4 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_fractal_chaos_oscillator_params_t; + +ts_parameter_t const ts_fractal_chaos_oscillator_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_fractal_chaos_oscillator_params_t) }; + +uint_t ts_fractal_chaos_oscillator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_fractal_chaos_oscillator_params_t *)c)->k / 2 : 0 ); +} + +int ts_fractal_chaos_oscillator( + 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_fractal_chaos_oscillator_p ); + if ( !c ) return -1; + uint_t k = ((ts_fractal_chaos_oscillator_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t alpha = 2.0 / (k + 1.0); + fp_t ema_upper = 0; + fp_t ema_lower = 0; + uint_t half_k = k / 2; + uint_t init = 0; + + for (uint_t i = half_k; i < n - half_k; ++i) + { + fp_t fh = x[1][i]; + fp_t fl = x[2][i]; + for (int_t j = -(int_t)half_k; j <= (int_t)half_k; ++j) + { + uint_t idx = (uint_t)((int_t)i + j); + if (x[1][idx] > fh) fh = x[1][idx]; + if (x[2][idx] < fl) fl = x[2][idx]; + } + + if (!init) + { + ema_upper = fh; + ema_lower = fl; + init = 1; + } + else + { + ema_upper = ema_upper + alpha * (fh - ema_upper); + ema_lower = ema_lower + alpha * (fl - ema_lower); + } + + fp_t denom = ema_upper + ema_lower; + y[0][i] = (denom != 0) ? (ema_upper - ema_lower) / denom * 100.0 : 0; + } + return 0; +} + diff --git a/lib/gamma_pdf.c b/lib/gamma_pdf.c new file mode 100644 index 0000000..977f8b7 --- /dev/null +++ b/lib/gamma_pdf.c @@ -0,0 +1,48 @@ +// Gamma Pdf +// +// gamma_pdf +// +// Gamma probability density function +// +// f(x; α, β) = β^α * x^(α-1) * e^(-βx) / Γ(α) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + fp_t shape; +} ts_gamma_pdf_params_t; + +ts_parameter_t const ts_gamma_pdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_gamma_pdf_params_t) }; + +uint_t ts_gamma_pdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_gamma_pdf( + 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_gamma_pdf_p ); + if ( !c ) return -1; + fp_t shape = ((ts_gamma_pdf_params_t *)c)->shape; + if (shape <= 0.0) return -1; + + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + y[0][i] = xi > 0 ? pow( xi, shape - 1.0 ) * exp( -xi ) / tgamma( shape ) : 0.0; + } + return 0; +} + + diff --git a/lib/gator_oscillator.c b/lib/gator_oscillator.c new file mode 100644 index 0000000..02bbc59 --- /dev/null +++ b/lib/gator_oscillator.c @@ -0,0 +1,64 @@ +// Gator Oscillator +// +// gator_oscillator +// +// Gator Oscillator from Alligator lines +// +// Histogram of Alligator Teeth-Lips and Jaw-Teeth +// +// Inputs: 1 +// Outputs: 2 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_gator_oscillator_p = { .n_inputs = 1, .n_outputs = 2, .n_constants = 0, .params_size = 0 }; + +uint_t ts_gator_oscillator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 12 ); +} + +int ts_gator_oscillator( + 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_gator_oscillator_p ); + (void)c; + /* Gator Oscillator uses Alligator lines: + * Lips = SMA(5), Teeth = SMA(8), Jaw = SMA(13) + * Upper = |Lips - Teeth|, Lower = |Jaw - Teeth| + * Offset 12 because Jaw (SMA13) starts at index 12 + */ + for (uint_t j = 0; j < n && j < 12; ++j) { y[0][j] = 0; y[1][j] = 0; } + for (uint_t i = 12; i < n; ++i) + { + /* SMA(5) - Lips */ + fp_t lips = 0; + for (uint_t j = i - 4; j <= i; ++j) lips += x[0][j]; + lips /= 5; + + /* SMA(8) - Teeth */ + fp_t teeth = 0; + for (uint_t j = i - 7; j <= i; ++j) teeth += x[0][j]; + teeth /= 8; + + /* SMA(13) - Jaw */ + fp_t jaw = 0; + for (uint_t j = i - 12; j <= i; ++j) jaw += x[0][j]; + jaw /= 13; + + y[0][i] = fabs(lips - teeth); + y[1][i] = fabs(jaw - teeth); + } + return 0; +} + + + diff --git a/lib/gaussian_cdf.c b/lib/gaussian_cdf.c new file mode 100644 index 0000000..2111aae --- /dev/null +++ b/lib/gaussian_cdf.c @@ -0,0 +1,43 @@ +// Gaussian Cdf +// +// gaussian_cdf +// +// Gaussian cumulative distribution function +// +// F(x) = 0.5 * (1 + erf(x/√2)) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_gaussian_cdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_gaussian_cdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_gaussian_cdf( + 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_gaussian_cdf_p ); + (void)c; + /* CDF = 0.5 * (1 + erf(x / sqrt(2))) */ + for (uint_t i = 0; i < n; ++i) + { + y[0][i] = 0.5 * (1.0 + erf(x[0][i] / sqrt(2.0))); + } + return 0; +} + + + diff --git a/lib/gaussian_pdf.c b/lib/gaussian_pdf.c new file mode 100644 index 0000000..01acc34 --- /dev/null +++ b/lib/gaussian_pdf.c @@ -0,0 +1,42 @@ +// Gaussian Pdf +// +// gaussian_pdf +// +// Gaussian probability density function +// +// f(x) = (1/√(2π)) * e^(-x²/2) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_gaussian_pdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_gaussian_pdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_gaussian_pdf( + 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_gaussian_pdf_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = exp( -0.5 * x[0][i] * x[0][i] ) / sqrt( 2.0 * PI ); + } + return 0; +} + + + diff --git a/lib/gaussian_quantile.c b/lib/gaussian_quantile.c new file mode 100644 index 0000000..337262c --- /dev/null +++ b/lib/gaussian_quantile.c @@ -0,0 +1,94 @@ +// Gaussian Quantile +// +// gaussian_quantile +// +// Gaussian quantile function (inverse CDF) +// +// Q(p) = Φ^(-1)(p) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_gaussian_quantile_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_gaussian_quantile_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_gaussian_quantile( + 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_gaussian_quantile_p ); + (void)c; + /* Peter Acklam's approximation for inverse normal CDF */ + /* Coefficients for rational approximation */ + fp_t const a[] = { + -3.969683028665376e+01, 2.209460984245205e+02, + -2.759285104469687e+02, 1.383577518672690e+02, + -3.066479806614716e+01, 2.506628277459239e+00 + }; + fp_t const b[] = { + -5.447609879822406e+01, 1.615858368580409e+02, + -1.556989798598866e+02, 6.680131188771972e+01, + -1.328068155288572e+01 + }; + fp_t const cc[] = { + -7.784894002430993e-03, 3.223964580411365e-01, + -2.400758277161838e+00, -2.549732539343734e+00, + 4.374664141464968e+00, 2.938163982698783e+00 + }; + fp_t const d[] = { + 7.784695709041462e-03, 3.224671290700398e-01, + 2.445134137142996e+00, 3.754408661907416e+00 + }; + + fp_t const p_low = 0.02425; + fp_t const p_high = 1.0 - p_low; + + for (uint_t i = 0; i < n; ++i) + { + fp_t p = x[0][i]; + if (p <= 0.0) + { + y[0][i] = -INFINITY; + continue; + } + if (p >= 1.0) + { + y[0][i] = INFINITY; + continue; + } + + fp_t q, r; + + if (p < p_low) { + q = sqrt(-2.0 * log(p)); + y[0][i] = -(((((cc[0]*q + cc[1])*q + cc[2])*q + cc[3])*q + cc[4])*q + cc[5]) / + ((((d[0]*q + d[1])*q + d[2])*q + d[3])*q + 1.0); + } else if (p <= p_high) { + q = p - 0.5; + r = q * q; + y[0][i] = (((((a[0]*r + a[1])*r + a[2])*r + a[3])*r + a[4])*r + a[5])*q / + (((((b[0]*r + b[1])*r + b[2])*r + b[3])*r + b[4])*r + 1.0); + } else { + q = sqrt(-2.0 * log(1.0 - p)); + y[0][i] = (((((cc[0]*q + cc[1])*q + cc[2])*q + cc[3])*q + cc[4])*q + cc[5]) / + ((((d[0]*q + d[1])*q + d[2])*q + d[3])*q + 1.0); + } + } + return 0; +} + + + diff --git a/lib/gcd.c b/lib/gcd.c new file mode 100644 index 0000000..44068cf --- /dev/null +++ b/lib/gcd.c @@ -0,0 +1,50 @@ +// Gcd +// +// gcd +// +// Greatest common divisor +// +// gcd(a, b) via Euclidean algorithm +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_gcd_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_gcd_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_gcd( + 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_gcd_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + long a = (long)fabs(x[0][i]); + long b = (long)fabs(x[1][i]); + while( b ) + { + long t = b; + b = a % b; + a = t; + } + y[0][i] = (fp_t)a; + } + return 0; +} + + + diff --git a/lib/gopalakrishnan_range_index.c b/lib/gopalakrishnan_range_index.c new file mode 100644 index 0000000..80da0b4 --- /dev/null +++ b/lib/gopalakrishnan_range_index.c @@ -0,0 +1,64 @@ +// Gopalakrishnan Range Index +// +// gopalakrishnan_range_index +// +// Gopalakrishnan Range Index +// +// Measures price range relative to ATR +// +// Inputs: 4 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_gopalakrishnan_range_index_params_t; + +ts_parameter_t const ts_gopalakrishnan_range_index_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_gopalakrishnan_range_index_params_t) }; + +uint_t ts_gopalakrishnan_range_index_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_gopalakrishnan_range_index_params_t *)c)->k : 0 ); +} + +int ts_gopalakrishnan_range_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_gopalakrishnan_range_index_p ); + if ( !c ) return -1; + uint_t k = ((ts_gopalakrishnan_range_index_params_t *)c)->k; + if (k == 0 || n <= k) return -1; + + fp_t sum_abs = 0; + fp_t sum_range = 0; + + for (uint_t j = 1; j <= k; ++j) + { + sum_abs += fabs( ts_c( x, j ) - ts_c( x, j - 1 ) ); + sum_range += ts_h( x, j ) - ts_l( x, j ); + } + + y[0][k] = sum_range != 0 ? sum_abs / sum_range : 0; + + for (uint_t i = k + 1; i < n; ++i) + { + uint_t dj = i - k; + sum_abs -= fabs( ts_c( x, dj ) - ts_c( x, dj - 1 ) ); + sum_range -= ts_h( x, dj ) - ts_l( x, dj ); + sum_abs += fabs( ts_c( x, i ) - ts_c( x, i - 1 ) ); + sum_range += ts_h( x, i ) - ts_l( x, i ); + y[0][i] = sum_range != 0 ? sum_abs / sum_range : 0; + } + return 0; +} + + + diff --git a/lib/hard_sigmoid.c b/lib/hard_sigmoid.c new file mode 100644 index 0000000..f54d4af --- /dev/null +++ b/lib/hard_sigmoid.c @@ -0,0 +1,47 @@ +// Hard Sigmoid +// +// hard_sigmoid - Hard Sigmoid activation +// +// y[t] = x[t] <= -3 ? 0 : x[t] >= 3 ? 1 : x[t]/6 + 0.5 +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_hard_sigmoid_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_hard_sigmoid_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_hard_sigmoid( + 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_hard_sigmoid_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + if ( xi <= -3 ) + y[0][i] = 0; + else if ( xi >= 3 ) + y[0][i] = 1; + else + y[0][i] = xi / 6 + 0.5; + } + return 0; +} + + + diff --git a/lib/hard_swish.c b/lib/hard_swish.c new file mode 100644 index 0000000..458ba8d --- /dev/null +++ b/lib/hard_swish.c @@ -0,0 +1,47 @@ +// Hard Swish +// +// hard_swish - Hard Swish activation +// +// y[t] = x[t] <= -3 ? 0 : x[t] >= 3 ? x[t] : x[t] * ( x[t] + 3 ) / 6 +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_hard_swish_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_hard_swish_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_hard_swish( + 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_hard_swish_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + if ( xi <= -3 ) + y[0][i] = 0; + else if ( xi >= 3 ) + y[0][i] = xi; + else + y[0][i] = xi * ( xi + 3 ) / 6; + } + return 0; +} + + + diff --git a/lib/hard_tanh.c b/lib/hard_tanh.c new file mode 100644 index 0000000..36301d3 --- /dev/null +++ b/lib/hard_tanh.c @@ -0,0 +1,48 @@ +// Hard Tanh +// +// hard_tanh - Hard Tanh activation +// +// y[t] = clamp( x[t], -1, 1 ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_hard_tanh_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_hard_tanh_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_hard_tanh( + 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_hard_tanh_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + if ( xi < -1 ) + y[0][i] = -1; + else if ( xi > 1 ) + y[0][i] = 1; + else + y[0][i] = xi; + } + return 0; +} + + + diff --git a/lib/harmonic.c b/lib/harmonic.c new file mode 100644 index 0000000..2c69ee8 --- /dev/null +++ b/lib/harmonic.c @@ -0,0 +1,50 @@ +// Harmonic +// +// harmonic +// +// Harmonic mean +// +// H = n / Σ(1/x_i) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_harmonic_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_harmonic_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_harmonic( + 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_harmonic_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + if (x[0][i] < 0) { y[0][i] = NAN; continue; } + uint_t n_val = (uint_t)x[0][i]; + if (n_val > 10000000) n_val = 10000000; + fp_t sum = 0.0; + for( uint_t k = 1; k <= n_val; ++k ) + { + sum += 1.0 / (fp_t)k; + } + y[0][i] = sum; + } + return 0; +} + + + diff --git a/lib/hermite.c b/lib/hermite.c new file mode 100644 index 0000000..0418c6b --- /dev/null +++ b/lib/hermite.c @@ -0,0 +1,64 @@ +// Hermite +// +// hermite +// +// Hermite polynomial +// +// H_n(x) via recurrence relation +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_hermite_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_hermite_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_hermite( + 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_hermite_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xv = x[0][i]; + if (x[1][i] < 0 || x[1][i] > 10000) { y[0][i] = 0; continue; } + uint_t n_val = (uint_t)x[1][i]; + if( n_val == 0 ) + { + y[0][i] = 1.0; + } + else if( n_val == 1 ) + { + y[0][i] = 2.0 * xv; + } + else + { + fp_t h0 = 1.0; + fp_t h1 = 2.0 * xv; + for( uint_t k = 2; k <= n_val; ++k ) + { + fp_t h2 = 2.0 * xv * h1 - 2.0 * (fp_t)(k - 1) * h0; + h0 = h1; + h1 = h2; + } + y[0][i] = h1; + } + } + return 0; +} + + + diff --git a/lib/high_low_bands.c b/lib/high_low_bands.c new file mode 100644 index 0000000..544796f --- /dev/null +++ b/lib/high_low_bands.c @@ -0,0 +1,71 @@ +// High Low Bands +// +// high_low_bands +// +// High-Low Bands +// +// Upper: highest high, Lower: lowest low over period +// +// Inputs: 4 +// Outputs: 2 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_high_low_bands_params_t; + +ts_parameter_t const ts_high_low_bands_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_high_low_bands_params_t) }; + +uint_t ts_high_low_bands_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? 2 * ((ts_high_low_bands_params_t *)c)->k - 2 : 0 ); +} + +int ts_high_low_bands( + 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_high_low_bands_p ); + if ( !c ) return -1; + uint_t k = ((ts_high_low_bands_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = 2 * k - 2; i < n; ++i ) + { + y[0][i] = 0; + y[1][i] = 0; + for( uint_t j = i - 2 * k + 2; j <= i - k + 1; ++j ) + { + uint_t start = (j >= k - 1) ? j - k + 1 : 0; + + fp_t hh = x[1][start]; + for( uint_t m = start + 1; m <= j; ++m ) + { + if( x[1][m] > hh ) + hh = x[1][m]; + } + y[0][i] += hh; + + fp_t ll = x[2][start]; + for( uint_t m = start + 1; m <= j; ++m ) + { + if( x[2][m] < ll ) + ll = x[2][m]; + } + y[1][i] += ll; + } + y[0][i] /= k; + y[1][i] /= k; + } + return 0; +} + + + diff --git a/lib/high_minus_low.c b/lib/high_minus_low.c new file mode 100644 index 0000000..b38fcbb --- /dev/null +++ b/lib/high_minus_low.c @@ -0,0 +1,42 @@ +// High Minus Low +// +// high_minus_low +// +// High minus Low +// +// H - L +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_high_minus_low_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_high_minus_low_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_high_minus_low( + 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_high_minus_low_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[1][i] - x[2][i]; + } + return 0; +} + + + diff --git a/lib/highest_high.c b/lib/highest_high.c new file mode 100644 index 0000000..d3ac753 --- /dev/null +++ b/lib/highest_high.c @@ -0,0 +1,67 @@ +// Highest High +// +// highest_high +// +// Highest high over rolling window +// +// HH = max(H[t-k+1..t]) +// +// Inputs: 5 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_highest_high_params_t; + +ts_parameter_t const ts_highest_high_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_highest_high_params_t) }; + +uint_t ts_highest_high_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_highest_high_params_t *)c)->k > 0 ? ((ts_highest_high_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_highest_high( + 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_highest_high_p ); + if ( !c ) return -1; + uint_t k = ((ts_highest_high_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t max_val = ts_h( x, 0 ); + for( uint_t j = 1; j < k; ++j ) + { + fp_t val = ts_h( x, j ); + if( val > max_val ) + max_val = val; + } + y[0][k - 1] = max_val; + + for( uint_t i = k; i < n; ++i ) + { + fp_t new_val = ts_h( x, i ); + fp_t old_val = ts_h( x, i - k ); + if ( new_val > max_val ) max_val = new_val; + if ( old_val == max_val ) + { + max_val = ts_h( x, i - k + 1 ); + for( uint_t j = i - k + 2; j <= i; ++j ) + { + fp_t val = ts_h( x, j ); + if( val > max_val ) max_val = val; + } + } + y[0][i] = max_val; + } + return 0; +} + diff --git a/lib/historical_volatility.c b/lib/historical_volatility.c new file mode 100644 index 0000000..cde0d91 --- /dev/null +++ b/lib/historical_volatility.c @@ -0,0 +1,62 @@ +// Historical Volatility +// +// historical_volatility +// +// Historical volatility of log returns +// +// stddev(log(C[t]/C[t-1])) over period +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_historical_volatility_params_t; + +ts_parameter_t const ts_historical_volatility_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_historical_volatility_params_t) }; + +uint_t ts_historical_volatility_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_historical_volatility_params_t *)c)->k > 0 ? ((ts_historical_volatility_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_historical_volatility( + 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_historical_volatility_p ); + if ( !c ) return -1; + uint_t k = ((ts_historical_volatility_params_t *)c)->k; + if (k == 0 || n < k + 1) return -1; + + for ( uint_t d = k - 1; d < n - 1; ++d ) + { + fp_t sum = 0; + fp_t sum2 = 0; + for ( uint_t j = d - k + 1; j <= d; ++j ) + { + fp_t lr = 0; + if ( x[0][j] > 0 && x[0][j + 1] > 0 ) + lr = log( x[0][j + 1] / x[0][j] ); + sum += lr; + sum2 += lr * lr; + } + fp_t mean = sum / ( fp_t )k; + fp_t variance = sum2 / ( fp_t )k - mean * mean; + y[0][d] = variance > 0 ? sqrt( variance ) * sqrt( 252.0 ) : 0; + } + + y[0][n - 1] = 0; + return 0; +} + + + diff --git a/lib/hull_ma.c b/lib/hull_ma.c new file mode 100644 index 0000000..e412a6f --- /dev/null +++ b/lib/hull_ma.c @@ -0,0 +1,89 @@ +// Hull Ma +// +// hull_ma +// +// Hull Moving Average +// +// HMA = WMA(2*WMA(n/2) - WMA(n), √n) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include <stdlib.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_hull_ma_params_t; + +ts_parameter_t const ts_hull_ma_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_hull_ma_params_t) }; + +uint_t ts_hull_ma_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_hull_ma_params_t *)c)->k + (uint_t)sqrt((fp_t)((ts_hull_ma_params_t *)c)->k) - 2 : 0 ); +} + +int ts_hull_ma( + 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_hull_ma_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_hull_ma_params_t *)c)->k; + if (k < 2) return -1; + + uint_t half_k = k / 2; + uint_t sqrt_k = (uint_t)sqrt((fp_t)k); + if (sqrt_k < 1) sqrt_k = 1; + + fp_t *wma_half = calloc( n, sizeof( fp_t ) ); + fp_t *wma_full = calloc( n, sizeof( fp_t ) ); + if ( !wma_half || !wma_full ) { free( wma_half ); free( wma_full ); return -1; } + + /* WMA(n/2) */ + fp_t wt_half = (fp_t)half_k * ((fp_t)half_k + 1.0) / 2.0; + for ( uint_t i = half_k - 1; i < n; ++i ) + { + fp_t s = 0; + for ( uint_t j = 0; j < half_k; ++j ) + s += x[0][i - j] * (fp_t)(half_k - j); + wma_half[i] = s / wt_half; + } + + /* WMA(n) */ + fp_t wt_full = (fp_t)k * ((fp_t)k + 1.0) / 2.0; + for ( uint_t i = k - 1; i < n; ++i ) + { + fp_t s = 0; + for ( uint_t j = 0; j < k; ++j ) + s += x[0][i - j] * (fp_t)(k - j); + wma_full[i] = s / wt_full; + } + + /* HMA = WMA(sqrt(n), 2*WMA(n/2) - WMA(n)) */ + fp_t wt_sqrt = (fp_t)sqrt_k * ((fp_t)sqrt_k + 1.0) / 2.0; + uint_t offset = k + sqrt_k - 2; + for (uint_t j = 0; j < n && j < offset; ++j) y[0][j] = NAN; + for ( uint_t i = offset; i < n; ++i ) + { + fp_t s = 0; + for ( uint_t j = 0; j < sqrt_k; ++j ) + { + fp_t diff = 2.0 * wma_half[i - j] - wma_full[i - j]; + s += diff * (fp_t)(sqrt_k - j); + } + y[0][i] = s / wt_sqrt; + } + + free( wma_half ); + free( wma_full ); + return 0; +} + diff --git a/lib/hurst_exponent.c b/lib/hurst_exponent.c new file mode 100644 index 0000000..aa58036 --- /dev/null +++ b/lib/hurst_exponent.c @@ -0,0 +1,122 @@ +// Hurst Exponent +// +// hurst_exponent +// +// Hurst exponent via R/S analysis +// +// H = slope of linear regression of log(R/S) vs log(n) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_hurst_exponent_params_t; + +ts_parameter_t const ts_hurst_exponent_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_hurst_exponent_params_t) }; + +uint_t ts_hurst_exponent_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_hurst_exponent( + 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_hurst_exponent_p ); + if ( !c ) return -1; + uint_t k = ((ts_hurst_exponent_params_t *)c)->k; + if (k == 0 || k > n) return -1; + + for ( uint_t i = 0; i < n; ++i ) + { + if (i + 1 < k) { + y[0][i] = 0; + continue; + } + + uint_t data_len = i + 1; + uint_t num_lags = 0; + fp_t sum_log_s = 0; + fp_t sum_log_rs = 0; + fp_t sum_log_s2 = 0; + fp_t sum_log_s_log_rs = 0; + + for ( uint_t s = 2; s <= k && s <= data_len / 2; ++s ) + { + uint_t ns = data_len / s; + if (ns == 0) continue; + + fp_t total_log_rs = 0; + uint_t valid_segs = 0; + + for ( uint_t seg = 0; seg < ns; ++seg ) + { + uint_t start = seg * s; + uint_t end = start + s; + if (end > data_len) break; + + fp_t mean = 0; + for ( uint_t p = start; p < end; ++p ) + mean += x[0][p]; + mean /= (fp_t)s; + + fp_t cumsum = 0; + fp_t max_dev = 0, min_dev = 0; + for ( uint_t p = start; p < end; ++p ) + { + cumsum += x[0][p] - mean; + if (cumsum > max_dev) max_dev = cumsum; + if (cumsum < min_dev) min_dev = cumsum; + } + + fp_t r = max_dev - min_dev; + fp_t std = 0; + for ( uint_t p = start; p < end; ++p ) + { + fp_t d = x[0][p] - mean; + std += d * d; + } + std = sqrt(std / (fp_t)s); + + if (std > 0 && r > 0) { + total_log_rs += log(r / std); + valid_segs++; + } + } + + if (valid_segs > 0) { + fp_t log_s = log((fp_t)s); + fp_t mean_log_rs = total_log_rs / (fp_t)valid_segs; + sum_log_s += log_s; + sum_log_rs += mean_log_rs; + sum_log_s2 += log_s * log_s; + sum_log_s_log_rs += log_s * mean_log_rs; + num_lags++; + } + } + + if (num_lags >= 2) { + fp_t denom = (fp_t)num_lags * sum_log_s2 - sum_log_s * sum_log_s; + if (fabs(denom) > 1e-300) { + fp_t h = ((fp_t)num_lags * sum_log_s_log_rs - sum_log_s * sum_log_rs) / denom; + y[0][i] = h; + } else { + y[0][i] = 0; + } + } else { + y[0][i] = 0; + } + } + return 0; +} + diff --git a/lib/hypot.c b/lib/hypot.c new file mode 100644 index 0000000..42fafa7 --- /dev/null +++ b/lib/hypot.c @@ -0,0 +1,42 @@ +// Hypot +// +// hypot +// +// Hypotenuse +// +// √(x² + y²) +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_hypot_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_hypot_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_hypot( + 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_hypot_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = hypot( x[0][i], x[1][i] ); + } + return 0; +} + + + diff --git a/lib/ichimoku.c b/lib/ichimoku.c new file mode 100644 index 0000000..76f85e6 --- /dev/null +++ b/lib/ichimoku.c @@ -0,0 +1,113 @@ +// Ichimoku +// +// ichimoku +// +// Ichimoku Cloud +// +// Tenkan, Kijun, Senkou Span A/B, Chikou +// +// Inputs: 4 +// Outputs: 5 +// Constants: 3 (tenkan, kijun, senkou) + + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t tenkan; + uint_t kijun; + uint_t senkou; +} ts_ichimoku_params_t; + +ts_parameter_t const ts_ichimoku_p = { .n_inputs = 4, .n_outputs = 5, .n_constants = 3, .params_size = sizeof(ts_ichimoku_params_t) }; + +uint_t ts_ichimoku_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 52 ); +} + +int ts_ichimoku( + 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_ichimoku_p ); + uint_t tenkan = 9; + uint_t kijun = 26; + uint_t senkou = 52; + + if ( c ) + { + ts_ichimoku_params_t *p = (ts_ichimoku_params_t *)c; + if ( p->tenkan > 0 ) tenkan = p->tenkan; + if ( p->kijun > 0 ) kijun = p->kijun; + if ( p->senkou > 0 ) senkou = p->senkou; + } + + if ( tenkan == 0 || kijun == 0 || senkou == 0 ) return -1; + + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = 0; + y[1][i] = 0; + y[2][i] = 0; + y[3][i] = 0; + y[4][i] = 0; + } + + for( uint_t i = tenkan - 1; i < n; ++i ) + { + fp_t hh = ts_h( x, i - tenkan + 1 ); + fp_t ll = ts_l( x, i - tenkan + 1 ); + for( uint_t j = i - tenkan + 1; j <= i; ++j ) + { + if( ts_h( x, j ) > hh ) hh = ts_h( x, j ); + if( ts_l( x, j ) < ll ) ll = ts_l( x, j ); + } + y[0][i] = ( hh + ll ) / 2.0; + } + + for( uint_t i = kijun - 1; i < n; ++i ) + { + fp_t hh = ts_h( x, i - kijun + 1 ); + fp_t ll = ts_l( x, i - kijun + 1 ); + for( uint_t j = i - kijun + 1; j <= i; ++j ) + { + if( ts_h( x, j ) > hh ) hh = ts_h( x, j ); + if( ts_l( x, j ) < ll ) ll = ts_l( x, j ); + } + y[1][i] = ( hh + ll ) / 2.0; + } + + for( uint_t i = kijun - 1; i < n; ++i ) + { + uint_t idx = i + kijun; + if( idx < n ) + y[2][idx] = ( y[0][i] + y[1][i] ) / 2.0; + } + + for( uint_t i = senkou - 1; i < n; ++i ) + { + fp_t hh = ts_h( x, i - senkou + 1 ); + fp_t ll = ts_l( x, i - senkou + 1 ); + for( uint_t j = i - senkou + 1; j <= i; ++j ) + { + if( ts_h( x, j ) > hh ) hh = ts_h( x, j ); + if( ts_l( x, j ) < ll ) ll = ts_l( x, j ); + } + uint_t idx = i + kijun; + if( idx < n ) + y[3][idx] = ( hh + ll ) / 2.0; + } + + for( uint_t i = kijun; i < n; ++i ) + { + y[4][i] = ts_c( x, i - kijun ); + } + return 0; +} + diff --git a/lib/ilogb.c b/lib/ilogb.c new file mode 100644 index 0000000..82cda70 --- /dev/null +++ b/lib/ilogb.c @@ -0,0 +1,42 @@ +// Ilogb +// +// ilogb +// +// Integer logarithm base +// +// exponent of the floating-point representation +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_ilogb_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_ilogb_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_ilogb( + 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_ilogb_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = (fp_t)ilogb( x[0][i] ); + } + return 0; +} + + + diff --git a/lib/intraday_momentum_index.c b/lib/intraday_momentum_index.c new file mode 100644 index 0000000..79209bd --- /dev/null +++ b/lib/intraday_momentum_index.c @@ -0,0 +1,57 @@ +// Intraday Momentum Index +// +// intraday_momentum_index +// +// Intraday Momentum Index +// +// SMA of up moves / total moves +// +// Inputs: 4 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_intraday_momentum_index_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_intraday_momentum_index_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 3 ); +} + +int ts_intraday_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_intraday_momentum_index_p ); + (void)c; + uint_t k = 3; + + for (uint_t i = 0; i < k; ++i) y[0][i] = 0; + + for( uint_t i = k; i < n; ++i ) + { + fp_t sum_up = 0; + fp_t sum_down = 0; + + for( uint_t j = 0; j < k; ++j ) + { + fp_t diff = ts_o( x, i - k + 1 + j ) - ts_c( x, i - k + j ); + if( diff > 0 ) + sum_up += diff; + else if( diff < 0 ) + sum_down += (-diff); + } + + y[0][i] = (sum_up + sum_down) == 0 ? 0 : sum_up / (sum_up + sum_down); + } + return 0; +} + + + diff --git a/lib/is_prime.c b/lib/is_prime.c new file mode 100644 index 0000000..119c9a4 --- /dev/null +++ b/lib/is_prime.c @@ -0,0 +1,69 @@ +// Is Prime +// +// is_prime +// +// Prime number test +// +// 1 if prime, 0 otherwise +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_is_prime_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_is_prime_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_is_prime( + 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_is_prime_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t v = x[0][i]; + if (v > 1e15 || v < -1e15) { y[0][i] = 0.0; continue; } + long n_val = (long)v; + if( n_val < 2 ) + { + y[0][i] = 0.0; + continue; + } + if( n_val == 2 ) + { + y[0][i] = 1.0; + continue; + } + if( n_val % 2 == 0 ) + { + y[0][i] = 0.0; + continue; + } + int prime = 1; + for( long d = 3; d <= n_val / d; d += 2 ) + { + if( n_val % d == 0 ) + { + prime = 0; + break; + } + } + y[0][i] = prime ? 1.0 : 0.0; + } + return 0; +} + + + diff --git a/lib/jaccard_similarity.c b/lib/jaccard_similarity.c new file mode 100644 index 0000000..b2ffee6 --- /dev/null +++ b/lib/jaccard_similarity.c @@ -0,0 +1,45 @@ +// Jaccard Similarity +// +// jaccard_similarity +// +// Jaccard similarity coefficient +// +// +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_jaccard_similarity_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_jaccard_similarity_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_jaccard_similarity( + 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_jaccard_similarity_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t const a = x[0][i]; + fp_t const b = x[1][i]; + fp_t const m = fmax( a, b ); + y[0][i] = m == 0.0 ? 0.0 : ( a + b ) / ( 2.0 * m ); + } + return 0; +} + + + diff --git a/lib/kalman_filter.c b/lib/kalman_filter.c new file mode 100644 index 0000000..f7adf6f --- /dev/null +++ b/lib/kalman_filter.c @@ -0,0 +1,63 @@ +// Kalman Filter +// +// kalman_filter +// +// Kalman Filter +// +// Optimal state estimation via predict-update cycle +// +// Inputs: 1 +// Outputs: 1 +// Constants: 2 + + +#include <math.h> +#include "ts.h" + +typedef struct { + fp_t Q; + fp_t R; +} ts_kalman_filter_params_t; + +ts_parameter_t const ts_kalman_filter_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_kalman_filter_params_t) }; + +uint_t ts_kalman_filter_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_kalman_filter( + 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_kalman_filter_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + fp_t Q = ((ts_kalman_filter_params_t *)c)->Q; + fp_t R = ((ts_kalman_filter_params_t *)c)->R; + + if (Q < 0 || R < 0) return -1; + if (isnan(Q) || isnan(R)) return -1; + if (n == 0) return -1; + fp_t x_est = x[0][0]; + /* NOTE: P=1.0 is a reasonable default for normalized data. + * For price data in the range of 100-3000, consider initializing + * P to the variance of the first few samples. */ + fp_t P = 1.0; + + y[0][0] = x_est; + for ( uint_t i = 1; i < n; ++i ) + { + P = P + Q; + fp_t denom = P + R; + fp_t K = denom != 0 ? P / denom : 0; + x_est = x_est + K * (x[0][i] - x_est); + P = (1 - K) * P; + y[0][i] = x_est; + } + return 0; +} + diff --git a/lib/kaufman_adaptive_ma.c b/lib/kaufman_adaptive_ma.c new file mode 100644 index 0000000..f56c6a1 --- /dev/null +++ b/lib/kaufman_adaptive_ma.c @@ -0,0 +1,61 @@ +// Kaufman Adaptive Ma +// +// kaufman_adaptive_ma +// +// Kaufman Adaptive Moving Average +// +// AMA based on efficiency ratio +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_kaufman_adaptive_ma_params_t; + +ts_parameter_t const ts_kaufman_adaptive_ma_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_kaufman_adaptive_ma_params_t) }; + +uint_t ts_kaufman_adaptive_ma_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_kaufman_adaptive_ma_params_t *)c)->k : 0 ); +} + +int ts_kaufman_adaptive_ma( + 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_kaufman_adaptive_ma_p ); + if ( !c ) return -1; + uint_t k = ((ts_kaufman_adaptive_ma_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t ama = x[0][0]; + fp_t sm = 2.0 / ((fp_t)k + 1.0); + fp_t sn = 2.0 / (sqrt((fp_t)k) + 1.0); + + for (uint_t i = k; i < n; ++i) + { + fp_t price_change = fabs(x[0][i] - x[0][i - k]); + fp_t noise = 0; + for (uint_t j = i - k + 1; j <= i; ++j) + noise += fabs(x[0][j] - x[0][j - 1]); + + fp_t er = noise != 0 ? price_change / noise : 0; + fp_t er_sq = er * er; + fp_t sc = er_sq * (sn - sm) + sm; + sc = sc * sc; + + ama = ama + sc * (x[0][i] - ama); + y[0][i] = ama; + } + return 0; +} + diff --git a/lib/keltner_channel.c b/lib/keltner_channel.c new file mode 100644 index 0000000..259be03 --- /dev/null +++ b/lib/keltner_channel.c @@ -0,0 +1,78 @@ +// Keltner Channel +// +// keltner_channel +// +// Keltner Channel +// +// Middle: EMA, Upper/Lower: EMA ± mult*ATR +// +// Inputs: 4 +// Outputs: 3 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_keltner_channel_params_t; + +ts_parameter_t const ts_keltner_channel_p = { .n_inputs = 4, .n_outputs = 3, .n_constants = 1, .params_size = sizeof(ts_keltner_channel_params_t) }; + +uint_t ts_keltner_channel_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_keltner_channel_params_t *)c)->k : 0 ); +} + +int ts_keltner_channel( + 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_keltner_channel_p ); + if ( !c ) return -1; + uint_t k = ((ts_keltner_channel_params_t *)c)->k; + if (k == 0 || n <= k) return -1; + + fp_t a = 2.0 / ((fp_t)k + 1.0); + + fp_t ema_tp = ( ts_h( x, 0 ) + ts_l( x, 0 ) + ts_c( x, 0 ) ) / 3.0; + + fp_t tr = ts_h( x, 1 ) - ts_l( x, 1 ); + fp_t tr2 = fabs( ts_h( x, 1 ) - ts_c( x, 0 ) ); + fp_t tr3 = fabs( ts_l( x, 1 ) - ts_c( x, 0 ) ); + if( tr2 > tr ) tr = tr2; + if( tr3 > tr ) tr = tr3; + fp_t atr = tr; + + for (uint_t i = 0; i < k; ++i) { y[0][i] = 0; y[1][i] = 0; y[2][i] = 0; } + + for( uint_t i = 1; i < n; ++i ) + { + fp_t tp = ( ts_h( x, i ) + ts_l( x, i ) + ts_c( x, i ) ) / 3.0; + ema_tp = ema_tp + a * ( tp - ema_tp ); + + tr = ts_h( x, i ) - ts_l( x, i ); + tr2 = fabs( ts_h( x, i ) - ts_c( x, i - 1 ) ); + tr3 = fabs( ts_l( x, i ) - ts_c( x, i - 1 ) ); + if( tr2 > tr ) tr = tr2; + if( tr3 > tr ) tr = tr3; + + if( i >= 2 ) + atr = atr + (tr - atr) / k; + + if( i >= k ) + { + y[0][i] = ema_tp; + y[1][i] = ema_tp + 2.0 * atr; + y[2][i] = ema_tp - 2.0 * atr; + } + } + return 0; +} + + + diff --git a/lib/kvo.c b/lib/kvo.c new file mode 100644 index 0000000..229fad8 --- /dev/null +++ b/lib/kvo.c @@ -0,0 +1,105 @@ +// Kvo +// +// kvo +// +// Klinger Volume Oscillator +// +// Volume-weighted price direction oscillator +// +// Inputs: 5 +// Outputs: 2 +// Constants: 2 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k1; + fp_t f0; +} ts_kvo_params_t; + +ts_parameter_t const ts_kvo_p = { .n_inputs = 5, .n_outputs = 2, .n_constants = 2, .params_size = sizeof(ts_kvo_params_t) }; + +uint_t ts_kvo_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_kvo_params_t *)c)->k1 > 10 ? ((ts_kvo_params_t *)c)->k1 : 10 : 0 ); +} + +int ts_kvo( + 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_kvo_p ); + if ( !c ) return -1; + uint_t k1 = ((ts_kvo_params_t *)c)->k1; + fp_t f0_raw = ((ts_kvo_params_t *)c)->f0; + if (isnan(f0_raw) || isinf(f0_raw) || f0_raw < 0) return -1; + uint_t k10 = (uint_t)f0_raw; + if (k1 == 0) return -1; + k10 = k1 > 10 ? k1 : 10; + + fp_t ema_short_dvm = 0; + fp_t ema_long_absdvm = 0; + fp_t ema_signal = 0; + fp_t kvo_val = 0; + + fp_t short_a = 2.0 / (k1 + 1); + fp_t long_a = 2.0 / (k10 + 1); + fp_t sig_a = 2.0 / (k1 + 1); + + uint_t offset = k10; + + for (uint_t i = 0; i < offset; ++i) { y[0][i] = 0; y[1][i] = 0; } + + for( uint_t i = offset; i < n; ++i ) + { + fp_t dvm_i = 0; + fp_t absdvm_i = 0; + + if( i >= 1 ) + { + fp_t dm = (ts_c(x, i) - ts_o(x, i)) - (ts_c(x, i-1) - ts_o(x, i-1)); + fp_t vol = ts_v(x, i); + if( dm > 0 ) + { + dvm_i = dm * vol; + absdvm_i = dm * vol; + } + else if( dm < 0 ) + { + dvm_i = dm * vol; + absdvm_i = (-dm) * vol; + } + } + + if( i == offset ) + { + ema_short_dvm = dvm_i; + ema_long_absdvm = absdvm_i; + } + else + { + ema_short_dvm = ema_short_dvm + short_a * (dvm_i - ema_short_dvm); + ema_long_absdvm = ema_long_absdvm + long_a * (absdvm_i - ema_long_absdvm); + } + + if( ema_long_absdvm != 0 ) + kvo_val = ema_short_dvm / ema_long_absdvm; + + if( i == offset ) + ema_signal = kvo_val; + else + ema_signal = ema_signal + sig_a * (kvo_val - ema_signal); + + y[0][i] = kvo_val; + y[1][i] = ema_signal; + } + return 0; +} + + + diff --git a/lib/lag.c b/lib/lag.c new file mode 100644 index 0000000..1e3f657 --- /dev/null +++ b/lib/lag.c @@ -0,0 +1,54 @@ +// Lag +// +// lag - lag +// +// DESCRIPTION +// +// Inputs: 1 +// Outputs: 1 +// Constants: 2 + + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; + fp_t insert; +} ts_lag_params_t; + +ts_parameter_t const ts_lag_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_lag_params_t) }; + + +uint_t ts_lag_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_lag_params_t *)c)->k : 0 ); +} + +int ts_lag( + 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_lag_p ); + if ( !c ) return -1; + uint_t k = ((ts_lag_params_t *)c)->k; + if (k == 0) return -1; + + fp_t insert = ((ts_lag_params_t *)c)->insert; + + if (n <= k) return -1; + + for (uint_t i = 0; i < k; ++i) + y[0][i] = insert; + + for (uint_t i = k; i < n; ++i) + y[0][i] = x[0][i - k]; + return 0; +} + + + diff --git a/lib/laguerre.c b/lib/laguerre.c new file mode 100644 index 0000000..b1e1284 --- /dev/null +++ b/lib/laguerre.c @@ -0,0 +1,62 @@ +// Laguerre +// +// laguerre +// +// Laguerre polynomial +// +// L_n(x) via recurrence relation +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_laguerre_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_laguerre_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_laguerre( + 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_laguerre_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xv = x[0][i]; + if (x[1][i] < 0) { y[0][i] = 0; continue; } + uint_t n_val = (uint_t)x[1][i]; + if( n_val == 0 ) + { + y[0][i] = 1.0; + } + else if( n_val == 1 ) + { + y[0][i] = 1.0 - xv; + } + else + { + fp_t l0 = 1.0; + fp_t l1 = 1.0 - xv; + for( uint_t k = 2; k <= n_val; ++k ) + { + fp_t l2 = ((2.0 * (fp_t)k - 1.0 - xv) * l1 - (fp_t)(k - 1) * l0) / (fp_t)k; + l0 = l1; + l1 = l2; + } + y[0][i] = l1; + } + } + return 0; +} + diff --git a/lib/lambert_w.c b/lib/lambert_w.c new file mode 100644 index 0000000..da59199 --- /dev/null +++ b/lib/lambert_w.c @@ -0,0 +1,64 @@ +// Lambert W +// +// lambert_w +// +// Lambert W function +// +// W(x) such that W*e^W = x +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_lambert_w_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_lambert_w_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_lambert_w( + 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_lambert_w_p ); + (void)c; + for (uint_t i = 0; i < n; ++i) + { + fp_t xv = x[0][i]; + if (xv < -1.0/exp(1.0)) + { + y[0][i] = NAN; + continue; + } + if (xv == 0.0) + { + y[0][i] = 0.0; + continue; + } + /* Halley iteration for W(x) */ + fp_t w = xv < 1.0 ? log(xv + 1.0) : log(xv); + for (uint_t j = 0; j < 10; ++j) + { + fp_t ew = exp(w); + fp_t f = w * ew - xv; + fp_t f1 = ew * (w + 1.0); + if (f1 == 0) break; + fp_t f2 = f1 * (w + 2.0); + w = w - f / f1 * (1.0 + f * f2 / (2.0 * f1 * f1)); + } + y[0][i] = w; + } + return 0; +} + + + diff --git a/lib/laplace_cdf.c b/lib/laplace_cdf.c new file mode 100644 index 0000000..7a70882 --- /dev/null +++ b/lib/laplace_cdf.c @@ -0,0 +1,43 @@ +// Laplace Cdf +// +// laplace_cdf +// +// Laplace cumulative distribution +// +// F(x) = 0.5 + 0.5*sign(x)*(1-e^(-|x|)) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_laplace_cdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_laplace_cdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_laplace_cdf( + 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_laplace_cdf_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + y[0][i] = xi < 0 ? 0.5 * exp( xi ) : 1.0 - 0.5 * exp( -xi ); + } + return 0; +} + + + diff --git a/lib/laplace_pdf.c b/lib/laplace_pdf.c new file mode 100644 index 0000000..d741aa4 --- /dev/null +++ b/lib/laplace_pdf.c @@ -0,0 +1,42 @@ +// Laplace Pdf +// +// laplace_pdf +// +// Laplace probability density +// +// f(x) = 0.5 * e^(-|x|) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_laplace_pdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_laplace_pdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_laplace_pdf( + 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_laplace_pdf_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = exp( -fabs( x[0][i] ) ) / 2.0; + } + return 0; +} + + + diff --git a/lib/lcm.c b/lib/lcm.c new file mode 100644 index 0000000..c8b52ef --- /dev/null +++ b/lib/lcm.c @@ -0,0 +1,62 @@ +// Lcm +// +// lcm +// +// Least common multiple +// +// lcm(a,b) = |a*b| / gcd(a,b) +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_lcm_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_lcm_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_lcm( + 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_lcm_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t ax = fabs(x[0][i]); + fp_t bx = fabs(x[1][i]); + if (ax > 1e15 || bx > 1e15) { y[0][i] = 0.0; continue; } + long a = (long)ax; + long b = (long)bx; + if( !a || !b ) + { + y[0][i] = 0.0; + } + else + { + long ta = a; + long tb = b; + while( tb ) + { + long t = tb; + tb = ta % tb; + ta = t; + } + y[0][i] = (fp_t)(a / ta) * (fp_t)b; + } + } + return 0; +} + + + diff --git a/lib/leaky_relu.c b/lib/leaky_relu.c new file mode 100644 index 0000000..51651bc --- /dev/null +++ b/lib/leaky_relu.c @@ -0,0 +1,42 @@ +// Leaky ReLU +// +// leaky_relu - Leaky Rectified Linear Unit +// +// y[t] = x[t] > 0 ? x[t] : 0.01 * x[t] +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_leaky_relu_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_leaky_relu_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_leaky_relu( + 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_leaky_relu_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + y[0][i] = xi > 0 ? xi : 0.01 * xi; + } + return 0; +} + + + diff --git a/lib/legendre.c b/lib/legendre.c new file mode 100644 index 0000000..6ba4644 --- /dev/null +++ b/lib/legendre.c @@ -0,0 +1,64 @@ +// Legendre +// +// legendre +// +// Legendre polynomial +// +// P_n(x) via recurrence relation +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_legendre_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_legendre_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_legendre( + 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_legendre_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xv = x[0][i]; + if (x[1][i] < 0) { y[0][i] = 0; continue; } + uint_t n_val = (uint_t)x[1][i]; + if( n_val == 0 ) + { + y[0][i] = 1.0; + } + else if( n_val == 1 ) + { + y[0][i] = xv; + } + else + { + fp_t p0 = 1.0; + fp_t p1 = xv; + for( uint_t k = 2; k <= n_val; ++k ) + { + fp_t p2 = ((2.0 * (fp_t)k - 1.0) * xv * p1 - (fp_t)(k - 1) * p0) / (fp_t)k; + p0 = p1; + p1 = p2; + } + y[0][i] = p1; + } + } + return 0; +} + + + diff --git a/lib/lerp.c b/lib/lerp.c new file mode 100644 index 0000000..6b284d6 --- /dev/null +++ b/lib/lerp.c @@ -0,0 +1,42 @@ +// Lerp +// +// lerp +// +// Linear interpolation +// +// a + t*(b-a) +// +// Inputs: 3 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_lerp_p = { .n_inputs = 3, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_lerp_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_lerp( + 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_lerp_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] + x[1][i] * ( x[2][i] - x[0][i] ); + } + return 0; +} + + + diff --git a/lib/lgamma.c b/lib/lgamma.c new file mode 100644 index 0000000..02ac593 --- /dev/null +++ b/lib/lgamma.c @@ -0,0 +1,52 @@ +// Lgamma +// +// lgamma +// +// Natural log of gamma function +// +// ln(|Γ(x)|) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_lgamma_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_lgamma_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_lgamma( + 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_lgamma_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xv = x[0][i]; + if( xv <= 0.0 ) + { + fp_t intpart; + if (modf(xv, &intpart) != 0.0) + y[0][i] = lgamma(xv); + else + y[0][i] = NAN; + } + else + y[0][i] = lgamma( xv ); + } + return 0; +} + + + diff --git a/lib/linear_regression.c b/lib/linear_regression.c new file mode 100644 index 0000000..5d595bc --- /dev/null +++ b/lib/linear_regression.c @@ -0,0 +1,86 @@ +// Linear Regression +// +// linear_regression +// +// Linear regression line +// +// y = a + b*x via least squares +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_linear_regression_params_t; + +ts_parameter_t const ts_linear_regression_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_linear_regression_params_t) }; + +uint_t ts_linear_regression_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_linear_regression_params_t *)c)->k - 1 : 0 ); +} + +int ts_linear_regression( + 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_linear_regression_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_linear_regression_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + // Precompute constant x sums (x values are always 0..k-1) + fp_t sum_x = 0, sum_x2 = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t xv = (fp_t)j; + sum_x += xv; + sum_x2 += xv * xv; + } + fp_t denom = (fp_t)k * sum_x2 - sum_x * sum_x; + fp_t fk = (fp_t)k; + + // Initial window + fp_t sum_y = 0, sum_xy = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t yv = x[0][j]; + sum_y += yv; + sum_xy += (fp_t)j * yv; + } + if (denom == 0) { + y[0][k - 1] = sum_y / fk; + } else { + fp_t slope = (fk * sum_xy - sum_x * sum_y) / denom; + fp_t intercept = (sum_y - slope * sum_x) / fk; + y[0][k - 1] = intercept + slope * (fp_t)(k - 1); + } + + // Sliding window: sum_xy_new = sum_xy_old - sum_y_new + k * y_new + for ( uint_t i = k; i < n; ++i ) + { + fp_t y_new = x[0][i]; + fp_t y_old = x[0][i - k]; + fp_t sum_y_old = sum_y; + sum_y = sum_y - y_old + y_new; + sum_xy = sum_xy - sum_y_old + y_old + (fk - 1) * y_new; + if (denom == 0) { + y[0][i] = sum_y / fk; + } else { + fp_t slope = (fk * sum_xy - sum_x * sum_y) / denom; + fp_t intercept = (sum_y - slope * sum_x) / fk; + y[0][i] = intercept + slope * (fp_t)(k - 1); + } + } + return 0; +} + diff --git a/lib/linear_regression_angle.c b/lib/linear_regression_angle.c new file mode 100644 index 0000000..22928bc --- /dev/null +++ b/lib/linear_regression_angle.c @@ -0,0 +1,80 @@ +// Linear Regression Angle +// +// linear_regression_angle +// +// Linear regression angle +// +// atan(slope) in degrees +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_linear_regression_angle_params_t; + +ts_parameter_t const ts_linear_regression_angle_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_linear_regression_angle_params_t) }; + +uint_t ts_linear_regression_angle_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_linear_regression_angle_params_t *)c)->k - 1 : 0 ); +} + +int ts_linear_regression_angle( + 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_linear_regression_angle_p ); + if ( !c ) return -1; + uint_t k = ((ts_linear_regression_angle_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t sum_x = 0, sum_x2 = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t xv = (fp_t)j; + sum_x += xv; + sum_x2 += xv * xv; + } + fp_t denom = (fp_t)k * sum_x2 - sum_x * sum_x; + fp_t fk = (fp_t)k; + + fp_t sum_y = 0, sum_xy = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t yv = x[0][j]; + sum_y += yv; + sum_xy += (fp_t)j * yv; + } + if (denom == 0) { + y[0][k - 1] = 0; + } else { + fp_t slope = (fk * sum_xy - sum_x * sum_y) / denom; + y[0][k - 1] = atan(slope) * 180.0 / PI; + } + + for ( uint_t i = k; i < n; ++i ) + { + fp_t y_new = x[0][i]; + fp_t y_old = x[0][i - k]; + fp_t sum_y_old = sum_y; + sum_y = sum_y - y_old + y_new; + sum_xy = sum_xy - sum_y_old + y_old + (fk - 1) * y_new; + if (denom == 0) { + y[0][i] = 0; + } else { + fp_t slope = (fk * sum_xy - sum_x * sum_y) / denom; + y[0][i] = atan(slope) * 180.0 / PI; + } + } + return 0; +} + diff --git a/lib/linear_regression_forecast.c b/lib/linear_regression_forecast.c new file mode 100644 index 0000000..02a78a8 --- /dev/null +++ b/lib/linear_regression_forecast.c @@ -0,0 +1,82 @@ +// Linear Regression Forecast +// +// linear_regression_forecast +// +// Linear regression forecast +// +// Forecast = intercept + slope * period +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_linear_regression_forecast_params_t; + +ts_parameter_t const ts_linear_regression_forecast_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_linear_regression_forecast_params_t) }; + +uint_t ts_linear_regression_forecast_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_linear_regression_forecast_params_t *)c)->k - 1 : 0 ); +} + +int ts_linear_regression_forecast( + 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_linear_regression_forecast_p ); + if ( !c ) return -1; + uint_t k = ((ts_linear_regression_forecast_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t sum_x = 0, sum_x2 = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t xv = (fp_t)j; + sum_x += xv; + sum_x2 += xv * xv; + } + fp_t denom = (fp_t)k * sum_x2 - sum_x * sum_x; + fp_t fk = (fp_t)k; + + fp_t sum_y = 0, sum_xy = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t yv = x[0][j]; + sum_y += yv; + sum_xy += (fp_t)j * yv; + } + if (denom == 0) { + y[0][k - 1] = sum_y / fk; + } else { + fp_t slope = (fk * sum_xy - sum_x * sum_y) / denom; + fp_t intercept = (sum_y - slope * sum_x) / fk; + y[0][k - 1] = intercept + slope * fk; + } + + for ( uint_t i = k; i < n; ++i ) + { + fp_t y_new = x[0][i]; + fp_t y_old = x[0][i - k]; + fp_t sum_y_old = sum_y; + sum_y = sum_y - y_old + y_new; + sum_xy = sum_xy - sum_y_old + y_old + (fk - 1) * y_new; + if (denom == 0) { + y[0][i] = sum_y / fk; + } else { + fp_t slope = (fk * sum_xy - sum_x * sum_y) / denom; + fp_t intercept = (sum_y - slope * sum_x) / fk; + y[0][i] = intercept + slope * fk; + } + } + return 0; +} + diff --git a/lib/linear_regression_intercept.c b/lib/linear_regression_intercept.c new file mode 100644 index 0000000..2b26478 --- /dev/null +++ b/lib/linear_regression_intercept.c @@ -0,0 +1,79 @@ +// Linear Regression Intercept +// +// linear_regression_intercept +// +// Linear regression intercept +// +// a = ȳ - b*x̄ +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_linear_regression_intercept_params_t; + +ts_parameter_t const ts_linear_regression_intercept_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_linear_regression_intercept_params_t) }; + +uint_t ts_linear_regression_intercept_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_linear_regression_intercept_params_t *)c)->k - 1 : 0 ); +} + +int ts_linear_regression_intercept( + 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_linear_regression_intercept_p ); + if ( !c ) return -1; + uint_t k = ((ts_linear_regression_intercept_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t sum_x = 0, sum_x2 = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t xv = (fp_t)j; + sum_x += xv; + sum_x2 += xv * xv; + } + fp_t denom = (fp_t)k * sum_x2 - sum_x * sum_x; + fp_t fk = (fp_t)k; + + fp_t sum_y = 0, sum_xy = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t yv = x[0][j]; + sum_y += yv; + sum_xy += (fp_t)j * yv; + } + if (denom == 0) { + y[0][k - 1] = sum_y / fk; + } else { + fp_t slope = (fk * sum_xy - sum_x * sum_y) / denom; + y[0][k - 1] = (sum_y - slope * sum_x) / fk; + } + + for ( uint_t i = k; i < n; ++i ) + { + fp_t y_new = x[0][i]; + fp_t y_old = x[0][i - k]; + fp_t sum_y_old = sum_y; + sum_y = sum_y - y_old + y_new; + sum_xy = sum_xy - sum_y_old + y_old + (fk - 1) * y_new; + if (denom == 0) { + y[0][i] = sum_y / fk; + } else { + fp_t slope = (fk * sum_xy - sum_x * sum_y) / denom; + y[0][i] = (sum_y - slope * sum_x) / fk; + } + } + return 0; +} + diff --git a/lib/linear_regression_r2.c b/lib/linear_regression_r2.c new file mode 100644 index 0000000..5cec662 --- /dev/null +++ b/lib/linear_regression_r2.c @@ -0,0 +1,88 @@ +// Linear Regression R2 +// +// linear_regression_r2 +// +// Linear regression R-squared +// +// R² = 1 - SS_res/SS_tot +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_linear_regression_r2_params_t; + +ts_parameter_t const ts_linear_regression_r2_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_linear_regression_r2_params_t) }; + +uint_t ts_linear_regression_r2_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_linear_regression_r2_params_t *)c)->k - 1 : 0 ); +} + +int ts_linear_regression_r2( + 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_linear_regression_r2_p ); + if ( !c ) return -1; + uint_t k = ((ts_linear_regression_r2_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t sum_x = 0, sum_x2 = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t xv = (fp_t)j; + sum_x += xv; + sum_x2 += xv * xv; + } + fp_t fk = (fp_t)k; + fp_t denom_x = fk * sum_x2 - sum_x * sum_x; + + fp_t sum_y = 0, sum_xy = 0, sum_y2 = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t yv = x[0][j]; + sum_y += yv; + sum_xy += (fp_t)j * yv; + sum_y2 += yv * yv; + } + fp_t denom_y = fk * sum_y2 - sum_y * sum_y; + fp_t num = fk * sum_xy - sum_x * sum_y; + if (denom_x == 0 || denom_y == 0) { + y[0][k - 1] = 0; + } else { + fp_t prod = denom_x * denom_y; + fp_t r = prod > 0 ? num / sqrt(prod) : 0; + y[0][k - 1] = r * r; + } + + for ( uint_t i = k; i < n; ++i ) + { + fp_t y_new = x[0][i]; + fp_t y_old = x[0][i - k]; + fp_t sum_y_old = sum_y; + sum_y = sum_y - y_old + y_new; + sum_xy = sum_xy - sum_y_old + y_old + (fk - 1) * y_new; + sum_y2 = sum_y2 - y_old * y_old + y_new * y_new; + denom_y = fk * sum_y2 - sum_y * sum_y; + num = fk * sum_xy - sum_x * sum_y; + if (denom_x == 0 || denom_y == 0) { + y[0][i] = 0; + } else { + fp_t prod = denom_x * denom_y; + fp_t r = prod > 0 ? num / sqrt(prod) : 0; + y[0][i] = r * r; + } + } + return 0; +} + diff --git a/lib/linear_regression_slope.c b/lib/linear_regression_slope.c new file mode 100644 index 0000000..d20ca8e --- /dev/null +++ b/lib/linear_regression_slope.c @@ -0,0 +1,77 @@ +// Linear Regression Slope +// +// linear_regression_slope +// +// Linear regression slope +// +// b = Σ(x-x̄)(y-ȳ) / Σ(x-x̄)² +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_linear_regression_slope_params_t; + +ts_parameter_t const ts_linear_regression_slope_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_linear_regression_slope_params_t) }; + +uint_t ts_linear_regression_slope_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_linear_regression_slope_params_t *)c)->k - 1 : 0 ); +} + +int ts_linear_regression_slope( + 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_linear_regression_slope_p ); + if ( !c ) return -1; + uint_t k = ((ts_linear_regression_slope_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t sum_x = 0, sum_x2 = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t xv = (fp_t)j; + sum_x += xv; + sum_x2 += xv * xv; + } + fp_t denom = (fp_t)k * sum_x2 - sum_x * sum_x; + fp_t fk = (fp_t)k; + + fp_t sum_y = 0, sum_xy = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t yv = x[0][j]; + sum_y += yv; + sum_xy += (fp_t)j * yv; + } + if (denom == 0) { + y[0][k - 1] = 0; + } else { + y[0][k - 1] = (fk * sum_xy - sum_x * sum_y) / denom; + } + + for ( uint_t i = k; i < n; ++i ) + { + fp_t y_new = x[0][i]; + fp_t y_old = x[0][i - k]; + fp_t sum_y_old = sum_y; + sum_y = sum_y - y_old + y_new; + sum_xy = sum_xy - sum_y_old + y_old + (fk - 1) * y_new; + if (denom == 0) { + y[0][i] = 0; + } else { + y[0][i] = (fk * sum_xy - sum_x * sum_y) / denom; + } + } + return 0; +} + diff --git a/lib/linear_weighted_ma.c b/lib/linear_weighted_ma.c new file mode 100644 index 0000000..70f660e --- /dev/null +++ b/lib/linear_weighted_ma.c @@ -0,0 +1,56 @@ +// Linear Weighted Ma +// +// linear_weighted_ma +// +// Linear Weighted Moving Average +// +// LWMA = Σ(i*x_i) / Σ(i) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_linear_weighted_ma_params_t; + +ts_parameter_t const ts_linear_weighted_ma_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_linear_weighted_ma_params_t) }; + +uint_t ts_linear_weighted_ma_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_linear_weighted_ma_params_t *)c)->k - 1 : 0 ); +} + +int ts_linear_weighted_ma( + 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_linear_weighted_ma_p ); + if ( !c ) return -1; + uint_t k = ((ts_linear_weighted_ma_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t w_sum = 0; + for( uint_t j = 1; j <= k; ++j ) + { + w_sum += (fp_t)j; + } + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t sum = 0; + for( uint_t j = 0; j < k; ++j ) + { + sum += (fp_t)(j + 1) * x[0][i - k + 1 + j]; + } + y[0][i] = sum / w_sum; + } + return 0; +} + diff --git a/lib/log1p.c b/lib/log1p.c new file mode 100644 index 0000000..dc49223 --- /dev/null +++ b/lib/log1p.c @@ -0,0 +1,41 @@ +// Log1p +// +// log1p +// +// Log(1+x) +// +// ln(1+x), accurate for small x +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + +ts_parameter_t const ts_log1p_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_log1p_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_log1p( + 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_log1p_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xv = x[0][i]; + if( xv < -1.0 ) { y[0][i] = 0; continue; } + y[0][i] = log1p( xv ); + } + return 0; +} + diff --git a/lib/log1pm1.c b/lib/log1pm1.c new file mode 100644 index 0000000..ea9281a --- /dev/null +++ b/lib/log1pm1.c @@ -0,0 +1,41 @@ +// Log1pm1 +// +// log1pm1 +// +// Log(1+x) - 1 +// +// ln(1+x) - 1 +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + +ts_parameter_t const ts_log1pm1_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_log1pm1_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_log1pm1( + 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_log1pm1_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xv = x[0][i]; + if( xv < -1.0 ) { y[0][i] = 0; continue; } + y[0][i] = log1p( xv ) - 1.0; + } + return 0; +} + diff --git a/lib/log_return.c b/lib/log_return.c new file mode 100644 index 0000000..2aa8334 --- /dev/null +++ b/lib/log_return.c @@ -0,0 +1,50 @@ +// Log Return +// +// log_return +// +// Logarithmic return +// +// ln(C[t] / C[t-1]) +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_log_return_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_log_return_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 3 ); +} + +int ts_log_return( + 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_log_return_p ); + (void)c; + if (n < 3) return -1; + for (uint_t i = 0; i < 3; ++i) y[0][i] = 0; + + for( uint_t i = 3; i < n; ++i ) + { + if ( x[0][i - 3] <= 0 || x[0][i] <= 0 ) + { + y[0][i] = NAN; + } + else + { + y[0][i] = log( x[0][i] / x[0][i - 3] ); + } + } + return 0; +} + diff --git a/lib/logarithm.c b/lib/logarithm.c new file mode 100755 index 0000000..7451976 --- /dev/null +++ b/lib/logarithm.c @@ -0,0 +1,50 @@ +// Logarithm +// +// logarithm - log +// +// f( x ) = log_b( x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 1 +// +// c[0] = b + + +#include <math.h> +#include "ts.h" + + +typedef struct { + fp_t b; +} ts_logarithm_params_t; + +ts_parameter_t const ts_logarithm_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_logarithm_params_t) }; + + +uint_t ts_logarithm_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_logarithm( + 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_logarithm_p ); + if ( !c ) return -1; + fp_t b = ((ts_logarithm_params_t *)c)->b; + if (b == 0 || b == 1.0) return -1; + + b = _ts_reciprocal( log( b ) ); + + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] > 0 ? log( x[0][i] ) * b : 0; + } + return 0; +} + diff --git a/lib/logarithm_binary.c b/lib/logarithm_binary.c new file mode 100644 index 0000000..1c6900d --- /dev/null +++ b/lib/logarithm_binary.c @@ -0,0 +1,44 @@ +// Binary Logarithm +// +// logarithm_binary - logb, lb +// +// f( x ) = log_2( x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_logarithm_binary_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_logarithm_binary_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_logarithm_binary( + 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_logarithm_binary_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + if (x[0][i] <= 0) { + y[0][i] = 0; + } else { + y[0][i] = log2( x[0][i] ); + } + } + return 0; +} + diff --git a/lib/logarithm_decimal.c b/lib/logarithm_decimal.c new file mode 100644 index 0000000..39afb47 --- /dev/null +++ b/lib/logarithm_decimal.c @@ -0,0 +1,44 @@ +// Decimal Logarithm +// +// logarithm_decimal - logd, ld +// +// f( x ) = log_10( x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_logarithm_decimal_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_logarithm_decimal_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_logarithm_decimal( + 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_logarithm_decimal_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + if (x[0][i] <= 0) { + y[0][i] = 0; + } else { + y[0][i] = log10( x[0][i] ); + } + } + return 0; +} + diff --git a/lib/logarithm_natural.c b/lib/logarithm_natural.c new file mode 100644 index 0000000..b76d67d --- /dev/null +++ b/lib/logarithm_natural.c @@ -0,0 +1,45 @@ +// Natural Logarithm +// +// logarithm_natural - logn, ln +// +// f( x ) = log_e( x ) +// = ln( x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_logarithm_natural_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_logarithm_natural_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_logarithm_natural( + 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_logarithm_natural_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + if (x[0][i] <= 0) { + y[0][i] = 0; + } else { + y[0][i] = log( x[0][i] ); + } + } + return 0; +} + diff --git a/lib/logb.c b/lib/logb.c new file mode 100644 index 0000000..7f1b66e --- /dev/null +++ b/lib/logb.c @@ -0,0 +1,42 @@ +// Logb +// +// logb +// +// Logarithm base of floating point +// +// exponent of the floating-point representation +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_logb_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_logb_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_logb( + 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_logb_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xv = x[0][i]; + if( xv == 0.0 ) { y[0][i] = 0; continue; } + y[0][i] = (fp_t)logb( xv ); + } + return 0; +} + diff --git a/lib/lowest_low.c b/lib/lowest_low.c new file mode 100644 index 0000000..d8ac284 --- /dev/null +++ b/lib/lowest_low.c @@ -0,0 +1,66 @@ +// Lowest Low +// +// lowest_low +// +// Lowest low over rolling window +// +// LL = min(L[t-k+1..t]) +// +// Inputs: 5 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_lowest_low_params_t; + +ts_parameter_t const ts_lowest_low_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_lowest_low_params_t) }; + +uint_t ts_lowest_low_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_lowest_low_params_t *)c)->k - 1 : 0 ); +} + +int ts_lowest_low( + 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_lowest_low_p ); + if ( !c ) return -1; + uint_t k = ((ts_lowest_low_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t min_val = ts_l( x, 0 ); + for( uint_t j = 1; j < k; ++j ) + { + fp_t val = ts_l( x, j ); + if( val < min_val ) + min_val = val; + } + y[0][k - 1] = min_val; + + for( uint_t i = k; i < n; ++i ) + { + fp_t new_val = ts_l( x, i ); + fp_t old_val = ts_l( x, i - k ); + if ( new_val < min_val ) min_val = new_val; + if ( old_val == min_val ) + { + min_val = ts_l( x, i - k + 1 ); + for( uint_t j = i - k + 2; j <= i; ++j ) + { + fp_t val = ts_l( x, j ); + if( val < min_val ) min_val = val; + } + } + y[0][i] = min_val; + } + return 0; +} + diff --git a/lib/macd.c b/lib/macd.c new file mode 100644 index 0000000..362f251 --- /dev/null +++ b/lib/macd.c @@ -0,0 +1,87 @@ +// Macd +// +// macd +// +// Moving Average Convergence Divergence +// +// MACD = EMA(fast) - EMA(slow), Signal = EMA(MACD) +// +// Inputs: 1 +// Outputs: 3 +// Constants: 3 + + +#include <math.h> +#include "ts.h" + +typedef struct { + fp_t fast_k; + fp_t slow_k; + fp_t signal_k; +} ts_macd_params_t; + +ts_parameter_t const ts_macd_p = { .n_inputs = 1, .n_outputs = 3, .n_constants = 3, .params_size = sizeof(ts_macd_params_t) }; + +uint_t ts_macd_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? (uint_t)(((ts_macd_params_t *)c)->slow_k + ((ts_macd_params_t *)c)->signal_k - 2) : 0 ); +} + +int ts_macd( + 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_macd_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + fp_t fast_k = ((ts_macd_params_t *)c)->fast_k; + fp_t slow_k = ((ts_macd_params_t *)c)->slow_k; + fp_t signal_k = ((ts_macd_params_t *)c)->signal_k; + + if (fast_k < 1 || slow_k < 1 || signal_k < 1) return -1; + if (isnan(fast_k) || isnan(slow_k) || isnan(signal_k)) return -1; + if (n == 0) return -1; + + fp_t fast_a = 2.0 / (fast_k + 1.0); + fp_t slow_a = 2.0 / (slow_k + 1.0); + fp_t signal_a = 2.0 / (signal_k + 1.0); + + fp_t fast_ema = x[0][0]; + fp_t slow_ema = x[0][0]; + + uint_t total_offset = (uint_t)(slow_k + signal_k - 2); + if (n <= total_offset) return -1; + + // Compute EMAs up to total_offset + for( uint_t i = 1; i <= total_offset; ++i ) + { + fast_ema = fast_ema + fast_a * ( x[0][i] - fast_ema ); + slow_ema = slow_ema + slow_a * ( x[0][i] - slow_ema ); + } + + fp_t macd_line = fast_ema - slow_ema; + fp_t signal_ema = macd_line; + + y[0][total_offset] = macd_line; + y[1][total_offset] = signal_ema; + y[2][total_offset] = 0; + + for( uint_t i = total_offset + 1; i < n; ++i ) + { + fast_ema = fast_ema + fast_a * ( x[0][i] - fast_ema ); + slow_ema = slow_ema + slow_a * ( x[0][i] - slow_ema ); + + macd_line = fast_ema - slow_ema; + signal_ema = signal_ema + signal_a * ( macd_line - signal_ema ); + + y[0][i] = macd_line; + y[1][i] = signal_ema; + y[2][i] = macd_line - signal_ema; + } + + return 0; +} + diff --git a/lib/manhattan_distance.c b/lib/manhattan_distance.c new file mode 100644 index 0000000..caa5ee4 --- /dev/null +++ b/lib/manhattan_distance.c @@ -0,0 +1,40 @@ +// Manhattan Distance +// +// manhattan_distance +// +// Manhattan distance (L1 norm) +// +// +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_manhattan_distance_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_manhattan_distance_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_manhattan_distance( + 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_manhattan_distance_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = fabs( x[0][i] ) + fabs( x[1][i] ); + } + return 0; +} + diff --git a/lib/manhattan_norm.c b/lib/manhattan_norm.c new file mode 100644 index 0000000..10ca769 --- /dev/null +++ b/lib/manhattan_norm.c @@ -0,0 +1,40 @@ +// Manhattan Norm +// +// manhattan_norm +// +// Manhattan norm (L1) +// +// +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + +ts_parameter_t const ts_manhattan_norm_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_manhattan_norm_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_manhattan_norm( + 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_manhattan_norm_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = fabs( x[0][i] ) + fabs( x[1][i] ); + } + return 0; +} + diff --git a/lib/market_facilitation_index.c b/lib/market_facilitation_index.c new file mode 100644 index 0000000..09c3feb --- /dev/null +++ b/lib/market_facilitation_index.c @@ -0,0 +1,39 @@ +// Market Facilitation Index +// +// market_facilitation_index +// +// Market Facilitation Index +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_market_facilitation_index_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_market_facilitation_index_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_market_facilitation_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_market_facilitation_index_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = (x[4][i] != 0) ? (x[1][i] - x[2][i]) / x[4][i] : 0; + } + return 0; +} + diff --git a/lib/mass_index.c b/lib/mass_index.c new file mode 100644 index 0000000..1985fab --- /dev/null +++ b/lib/mass_index.c @@ -0,0 +1,91 @@ +// Mass Index +// +// mass_index +// +// Mass Index +// +// SMA of EMA(H/L) ratio, reversal when > threshold +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include <stdlib.h> +#include "ts.h" + + +ts_parameter_t const ts_mass_index_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_mass_index_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 26 ); +} + +int ts_mass_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_mass_index_p ); + (void)c; + uint_t ema_period = 9; + uint_t sum_period = 26; + + if (n < sum_period) return -1; + + fp_t *hl = calloc( n, sizeof( fp_t ) ); + fp_t *ema1 = calloc( n, sizeof( fp_t ) ); + fp_t *ema2 = calloc( n, sizeof( fp_t ) ); + fp_t *ratio = calloc( n, sizeof( fp_t ) ); + if ( !hl || !ema1 || !ema2 || !ratio ) + { + free( hl ); free( ema1 ); free( ema2 ); free( ratio ); + return -1; + } + + fp_t a1 = 2.0 / ( ( fp_t )ema_period + 1.0 ); + + for ( uint_t i = 0; i < n; ++i ) + { + hl[i] = ts_h( x, i ) - ts_l( x, i ); + } + + ema1[0] = hl[0]; + for ( uint_t i = 1; i < n; ++i ) + { + ema1[i] = ema1[i - 1] + a1 * ( hl[i] - ema1[i - 1] ); + } + + ema2[0] = ema1[0]; + for ( uint_t i = 1; i < n; ++i ) + { + ema2[i] = ema2[i - 1] + a1 * ( ema1[i] - ema2[i - 1] ); + } + + for ( uint_t i = 0; i < n; ++i ) + { + ratio[i] = ema2[i] != 0 ? ema1[i] / ema2[i] : 0; + } + + fp_t sum = 0; + for ( uint_t i = 0; i < sum_period; ++i ) + { + sum += ratio[i]; + } + + for ( uint_t j = 0; j < sum_period - 1; ++j ) y[0][j] = 0; + y[0][sum_period - 1] = sum; + + for ( uint_t i = sum_period; i < n; ++i ) + { + sum = sum - ratio[i - sum_period] + ratio[i]; + y[0][i] = sum; + } + + free( hl ); free( ema1 ); free( ema2 ); free( ratio ); + return 0; +} + diff --git a/lib/maximum.c b/lib/maximum.c new file mode 100755 index 0000000..f4d124a --- /dev/null +++ b/lib/maximum.c @@ -0,0 +1,56 @@ +// Maximum +// +// maximum - max +// +// Finds the maximum value in the past k values +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_maximum_params_t; + +ts_parameter_t const ts_maximum_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_maximum_params_t) }; + + +uint_t ts_maximum_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_maximum_params_t *)c)->k - 1 : 0 ); +} + +int ts_maximum( + 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_maximum_p ); + if ( !c ) return -1; + uint_t k = ((ts_maximum_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = k - 1; + uint_t xj = 0; + uint_t yi = k - 1; + + for( ; xi < n; xi++, xj++, yi++ ) + { + y[0][yi] = x[0][xj]; + + for( uint_t i = xj; i <= xi; i++ ) + { + if( x[0][i] > y[0][yi] ) + { + y[0][yi] = x[0][i]; + } + } + } + return 0; +} + diff --git a/lib/median_price.c b/lib/median_price.c new file mode 100644 index 0000000..7df202f --- /dev/null +++ b/lib/median_price.c @@ -0,0 +1,39 @@ +// Median Price +// +// median_price +// +// Median Price +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_median_price_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_median_price_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_median_price( + 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_median_price_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = ( x[1][i] + x[2][i] ) / 2; + } + return 0; +} + diff --git a/lib/mesa_sine_wave.c b/lib/mesa_sine_wave.c new file mode 100644 index 0000000..8ed5fa6 --- /dev/null +++ b/lib/mesa_sine_wave.c @@ -0,0 +1,112 @@ +// Mesa Sine Wave +// +// mesa_sine_wave +// +// Mesa Sine Wave +// +// Adaptive sine wave following price trends +// +// Inputs: 1 +// Outputs: 2 +// Constants: 1 + + +#include <math.h> +#include <stdlib.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_mesa_sine_wave_params_t; + +ts_parameter_t const ts_mesa_sine_wave_p = { .n_inputs = 1, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_mesa_sine_wave_params_t) }; + +uint_t ts_mesa_sine_wave_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_mesa_sine_wave_params_t *)c)->k : 0 ); +} + +int ts_mesa_sine_wave( + 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_mesa_sine_wave_p ); + if ( !c ) return -1; + uint_t k = ((ts_mesa_sine_wave_params_t *)c)->k; + if (k < 2 || n < k) return -1; + + fp_t *sma = calloc(n, sizeof(fp_t)); + if (!sma) return -1; + + for (uint_t i = 0; i < n; ++i) + { + if (i < k - 1) + { + fp_t sum = 0; + for (uint_t j = 0; j <= i; ++j) + sum += x[0][j]; + sma[i] = sum / (i + 1); + } + else + { + fp_t sum = 0; + for (uint_t j = i - k + 1; j <= i; ++j) + sum += x[0][j]; + sma[i] = sum / k; + } + } + + fp_t ema_roc = 0; + uint_t ema_period = 5; + fp_t ema_a = 2.0 / (ema_period + 1); + fp_t phase = 0; + int_t first = 1; + + for (uint_t j = 0; j < n && j < k; ++j) { y[0][j] = 0; y[1][j] = 0; } + for (uint_t i = k; i < n; ++i) + { + fp_t roc = sma[i] - sma[i - 2]; + + if (first) + { + ema_roc = roc; + first = 0; + } + else + { + ema_roc = ema_roc + ema_a * (roc - ema_roc); + } + + fp_t smoothed = ema_roc; + if (smoothed > 1.0) smoothed = 1.0; + if (smoothed < 0.01) smoothed = 0.01; + + fp_t wperiod = 2 * PI / smoothed; + if (wperiod < 5) wperiod = 5; + if (wperiod > 12) wperiod = 12; + + if (smoothed >= 1.0) + { + phase = 0; + } + else if (smoothed <= 0.01) + { + phase = 2 * PI; + } + else + { + phase += 2 * PI / wperiod; + } + while (phase > 2 * PI) phase -= 2 * PI; + + y[0][i] = cos(phase); + y[1][i] = cos(phase + PI / 2); + } + + free(sma); + return 0; +} + diff --git a/lib/mfi.c b/lib/mfi.c new file mode 100644 index 0000000..c93803c --- /dev/null +++ b/lib/mfi.c @@ -0,0 +1,84 @@ +// Mfi +// +// mfi +// +// Money Flow Index +// +// 100 - 100/(1 + MF_ratio), volume-weighted RSI +// +// Inputs: 5 +// Outputs: 1 +// Constants: 1 + + +#include <stdlib.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_mfi_params_t; + +ts_parameter_t const ts_mfi_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_mfi_params_t) }; + +uint_t ts_mfi_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_mfi_params_t *)c)->k : 0 ); +} + +int ts_mfi( + 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_mfi_p ); + if ( !c ) return -1; + uint_t k = ((ts_mfi_params_t *)c)->k; + if (k == 0 || n <= k) return -1; + + fp_t *tp = calloc( n, sizeof( fp_t ) ); + if ( !tp ) return -1; + + for( uint_t i = 0; i < n; ++i ) + { + tp[i] = ( ts_h( x, i ) + ts_l( x, i ) + ts_c( x, i ) ) / 3.0; + } + + fp_t pos_sum = 0; + fp_t neg_sum = 0; + + for (uint_t i = 0; i < k; ++i) y[0][i] = 0; + + for( uint_t i = 1; i <= k; ++i ) + { + fp_t raw_mf = tp[i] * ts_v( x, i ); + if( tp[i] > tp[i - 1] ) + pos_sum += raw_mf; + else + neg_sum += raw_mf; + } + + y[0][k] = ( neg_sum == 0 ) ? 100.0 : 100.0 - 100.0 / ( 1.0 + pos_sum / neg_sum ); + + for( uint_t i = k + 1; i < n; ++i ) + { + fp_t cur_raw_mf = tp[i] * ts_v( x, i ); + if( tp[i] > tp[i - 1] ) + pos_sum += cur_raw_mf; + else + neg_sum += cur_raw_mf; + + fp_t old_raw_mf = tp[i - k] * ts_v( x, i - k ); + if( tp[i - k] > tp[i - k - 1] ) + pos_sum -= old_raw_mf; + else + neg_sum -= old_raw_mf; + + y[0][i] = ( neg_sum == 0 ) ? 100.0 : 100.0 - 100.0 / ( 1.0 + pos_sum / neg_sum ); + } + + free( tp ); + return 0; +} + diff --git a/lib/midpoint.c b/lib/midpoint.c new file mode 100644 index 0000000..c28cdff --- /dev/null +++ b/lib/midpoint.c @@ -0,0 +1,53 @@ +// Midpoint +// +// midpoint +// +// Midpoint over rolling window +// +// (highest_high + lowest_low) / 2 +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_midpoint_params_t; + +ts_parameter_t const ts_midpoint_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_midpoint_params_t) }; + +uint_t ts_midpoint_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_midpoint_params_t *)c)->k - 1 : 0 ); +} + +int ts_midpoint( + 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_midpoint_p ); + if ( !c ) return -1; + uint_t k = ((ts_midpoint_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t max_val = x[0][i]; + fp_t min_val = x[0][i]; + for( uint_t j = 1; j < k; ++j ) + { + fp_t val = x[0][i - j]; + if( val > max_val ) max_val = val; + if( val < min_val ) min_val = val; + } + y[0][i] = ( max_val + min_val ) / 2; + } + return 0; +} + diff --git a/lib/midprice.c b/lib/midprice.c new file mode 100644 index 0000000..d26a58e --- /dev/null +++ b/lib/midprice.c @@ -0,0 +1,53 @@ +// Midprice +// +// midprice +// +// Midprice +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_midprice_params_t; + +ts_parameter_t const ts_midprice_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_midprice_params_t) }; + +uint_t ts_midprice_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_midprice_params_t *)c)->k - 1 : 0 ); +} + +int ts_midprice( + 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_midprice_p ); + if ( !c ) return -1; + uint_t k = ((ts_midprice_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t max_val = x[0][i]; + fp_t min_val = x[0][i]; + for( uint_t j = 1; j < k; ++j ) + { + fp_t val = x[0][i - j]; + if( val > max_val ) max_val = val; + if( val < min_val ) min_val = val; + } + y[0][i] = ( max_val + min_val ) / 2; + } + return 0; +} + diff --git a/lib/minimum.c b/lib/minimum.c new file mode 100755 index 0000000..d2ba15f --- /dev/null +++ b/lib/minimum.c @@ -0,0 +1,56 @@ +// Minimum +// +// minimum - min +// +// Finds the minimum value in the past k data points +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_minimum_params_t; + +ts_parameter_t const ts_minimum_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_minimum_params_t) }; + + +uint_t ts_minimum_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_minimum_params_t *)c)->k - 1 : 0 ); +} + +int ts_minimum( + 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_minimum_p ); + if ( !c ) return -1; + uint_t k = ((ts_minimum_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = k - 1; + uint_t xj = 0; + uint_t yi = k - 1; + + for( ; xi < n; xi++, xj++, yi++ ) + { + y[0][yi] = x[0][xj]; + + for( uint_t i = xj; i <= xi; i++ ) + { + if( x[0][i] < y[0][yi] ) + { + y[0][yi] = x[0][i]; + } + } + } + return 0; +} + diff --git a/lib/minmax.c b/lib/minmax.c new file mode 100644 index 0000000..4bee598 --- /dev/null +++ b/lib/minmax.c @@ -0,0 +1,53 @@ +// Minmax +// +// minmax +// +// Min and Max over rolling window +// +// min(x[t-k+1..t]), max(x[t-k+1..t]) +// +// Inputs: 1 +// Outputs: 2 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_minmax_params_t; + +ts_parameter_t const ts_minmax_p = { .n_inputs = 1, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_minmax_params_t) }; + +uint_t ts_minmax_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_minmax_params_t *)c)->k - 1 : 0 ); +} + +int ts_minmax( + 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_minmax_p ); + if ( !c ) return -1; + uint_t k = ((ts_minmax_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t min_val = x[0][i - k + 1]; + fp_t max_val = x[0][i - k + 1]; + for( uint_t j = i - k + 2; j <= i; ++j ) + { + if( x[0][j] < min_val ) min_val = x[0][j]; + if( x[0][j] > max_val ) max_val = x[0][j]; + } + y[0][i] = min_val; + y[1][i] = max_val; + } + return 0; +} + diff --git a/lib/missing_bar_count.c b/lib/missing_bar_count.c new file mode 100644 index 0000000..e6f548e --- /dev/null +++ b/lib/missing_bar_count.c @@ -0,0 +1,51 @@ +// Missing Bar Count +// +// missing_bar_count +// +// Missing bar counter +// +// Counts consecutive missing data bars +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + fp_t threshold; +} ts_missing_bar_count_params_t; + +ts_parameter_t const ts_missing_bar_count_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_missing_bar_count_params_t) }; + +uint_t ts_missing_bar_count_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_missing_bar_count( + 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_missing_bar_count_p ); + if ( !c ) return -1; + if (n == 0) return -1; + fp_t threshold = ((ts_missing_bar_count_params_t *)c)->threshold; + + y[0][0] = 0; + + for( uint_t i = 1; i < n; ++i ) + { + if( fabs( x[0][i] - x[0][i - 1] ) < threshold ) + y[0][i] = y[0][i - 1] + 1; + else + y[0][i] = 0; + } + return 0; +} + diff --git a/lib/momentum.c b/lib/momentum.c new file mode 100644 index 0000000..f0d89fd --- /dev/null +++ b/lib/momentum.c @@ -0,0 +1,46 @@ +// Momentum +// +// momentum +// +// Momentum +// +// C[t] - C[t-k] +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_momentum_params_t; + +ts_parameter_t const ts_momentum_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_momentum_params_t) }; + +uint_t ts_momentum_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_momentum_params_t *)c)->k : 0 ); +} + +int ts_momentum( + 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_momentum_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_momentum_params_t *)c)->k; + + for( uint_t i = k; i < n; ++i ) + { + y[0][i] = x[0][i] - x[0][i - k]; + } + + return 0; +} + diff --git a/lib/money_flow_multiplier.c b/lib/money_flow_multiplier.c new file mode 100644 index 0000000..f00707c --- /dev/null +++ b/lib/money_flow_multiplier.c @@ -0,0 +1,42 @@ +// Money Flow Multiplier +// +// money_flow_multiplier +// +// Money Flow Multiplier +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_money_flow_multiplier_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +// ( ( c - l ) - ( h - c ) ) / ( h - l ) +uint_t ts_money_flow_multiplier_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_money_flow_multiplier( + 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_money_flow_multiplier_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t denom = x[1][i] - x[2][i]; + y[0][i] = denom != 0 ? ( ( x[3][i] - x[2][i] ) - ( x[1][i] - x[3][i] ) ) / denom : 0; + } + return 0; +} + diff --git a/lib/moving_linear_regression.c b/lib/moving_linear_regression.c new file mode 100644 index 0000000..ceb34d5 --- /dev/null +++ b/lib/moving_linear_regression.c @@ -0,0 +1,83 @@ +// Moving Linear Regression +// +// moving_linear_regression +// +// Moving Linear Regression +// +// Rolling least-squares regression line +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_moving_linear_regression_params_t; + +ts_parameter_t const ts_moving_linear_regression_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_moving_linear_regression_params_t) }; + +uint_t ts_moving_linear_regression_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_moving_linear_regression_params_t *)c)->k - 1 : 0 ); +} + +int ts_moving_linear_regression( + 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_moving_linear_regression_p ); + if ( !c ) return -1; + uint_t k = ((ts_moving_linear_regression_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t sum_x = 0, sum_x2 = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t xv = (fp_t)j; + sum_x += xv; + sum_x2 += xv * xv; + } + fp_t denom = (fp_t)k * sum_x2 - sum_x * sum_x; + fp_t fk = (fp_t)k; + + fp_t sum_y = 0, sum_xy = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t yv = x[0][j]; + sum_y += yv; + sum_xy += (fp_t)j * yv; + } + if (denom == 0) { + y[0][k - 1] = sum_y / fk; + } else { + fp_t slope = (fk * sum_xy - sum_x * sum_y) / denom; + fp_t intercept = (sum_y - slope * sum_x) / fk; + fp_t x_last = (fp_t)(k - 1); + y[0][k - 1] = intercept + slope * x_last; + } + + for ( uint_t i = k; i < n; ++i ) + { + fp_t y_new = x[0][i]; + fp_t y_old = x[0][i - k]; + fp_t sum_y_old = sum_y; + sum_y = sum_y - y_old + y_new; + sum_xy = sum_xy - sum_y_old + y_old + (fk - 1) * y_new; + if (denom == 0) { + y[0][i] = sum_y / fk; + } else { + fp_t slope = (fk * sum_xy - sum_x * sum_y) / denom; + fp_t intercept = (sum_y - slope * sum_x) / fk; + fp_t x_last = (fp_t)(k - 1); + y[0][i] = intercept + slope * x_last; + } + } + return 0; +} + diff --git a/lib/moving_linear_regression_r2.c b/lib/moving_linear_regression_r2.c new file mode 100644 index 0000000..3015a25 --- /dev/null +++ b/lib/moving_linear_regression_r2.c @@ -0,0 +1,88 @@ +// Moving Linear Regression R2 +// +// moving_linear_regression_r2 +// +// Moving Linear Regression R² +// +// Rolling coefficient of determination +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_moving_linear_regression_r2_params_t; + +ts_parameter_t const ts_moving_linear_regression_r2_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_moving_linear_regression_r2_params_t) }; + +uint_t ts_moving_linear_regression_r2_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_moving_linear_regression_r2_params_t *)c)->k - 1 : 0 ); +} + +int ts_moving_linear_regression_r2( + 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_moving_linear_regression_r2_p ); + if ( !c ) return -1; + uint_t k = ((ts_moving_linear_regression_r2_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t sum_x = 0, sum_x2 = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t xv = (fp_t)j; + sum_x += xv; + sum_x2 += xv * xv; + } + fp_t fk = (fp_t)k; + fp_t denom_x = fk * sum_x2 - sum_x * sum_x; + + fp_t sum_y = 0, sum_xy = 0, sum_y2 = 0; + for ( uint_t j = 0; j < k; ++j ) + { + fp_t yv = x[0][j]; + sum_y += yv; + sum_xy += (fp_t)j * yv; + sum_y2 += yv * yv; + } + fp_t denom_y = fk * sum_y2 - sum_y * sum_y; + fp_t num = fk * sum_xy - sum_x * sum_y; + if (denom_x == 0 || denom_y == 0) { + y[0][k - 1] = 0; + } else { + fp_t prod = denom_x * denom_y; + fp_t r = prod > 0 ? num / sqrt(prod) : 0; + y[0][k - 1] = r * r; + } + + for ( uint_t i = k; i < n; ++i ) + { + fp_t y_new = x[0][i]; + fp_t y_old = x[0][i - k]; + fp_t sum_y_old = sum_y; + sum_y = sum_y - y_old + y_new; + sum_xy = sum_xy - sum_y_old + y_old + (fk - 1) * y_new; + sum_y2 = sum_y2 - y_old * y_old + y_new * y_new; + denom_y = fk * sum_y2 - sum_y * sum_y; + num = fk * sum_xy - sum_x * sum_y; + if (denom_x == 0 || denom_y == 0) { + y[0][i] = 0; + } else { + fp_t prod = denom_x * denom_y; + fp_t r = prod > 0 ? num / sqrt(prod) : 0; + y[0][i] = r * r; + } + } + return 0; +} + diff --git a/lib/multiplication.c b/lib/multiplication.c new file mode 100644 index 0000000..74a7985 --- /dev/null +++ b/lib/multiplication.c @@ -0,0 +1,39 @@ +// Multiplication +// +// multiplication - mul +// +// f( x_0, x_1 ) = x_0 * x_1 +// +// X_n - 2 +// Y_n - 1 +// C_n - 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_multiplication_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_multiplication_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_multiplication( + 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_multiplication_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] * x[1][i]; + } + return 0; +} + diff --git a/lib/nan_fn.c b/lib/nan_fn.c new file mode 100644 index 0000000..cd93069 --- /dev/null +++ b/lib/nan_fn.c @@ -0,0 +1,41 @@ +// NaN Function +// +// nan_fn - Returns NaN for all inputs +// +// y[t] = NaN +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_nan_fn_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_nan_fn_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_nan_fn( + 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_nan_fn_p ); + (void)c; + ( void ) x; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = NAN; + } + return 0; +} + diff --git a/lib/natr.c b/lib/natr.c new file mode 100644 index 0000000..ce58bb1 --- /dev/null +++ b/lib/natr.c @@ -0,0 +1,57 @@ +// Natr +// +// natr +// +// Normalized ATR +// +// +// +// Inputs: 4 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_natr_params_t; + +ts_parameter_t const ts_natr_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_natr_params_t) }; + + +uint_t ts_natr_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_natr_params_t *)c)->k : 0 ); +} + +int ts_natr( + 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_natr_p ); + if ( !c ) return -1; + uint_t k = ((ts_natr_params_t *)c)->k; + if (k == 0) return -1; + if (n < k + 1) return -1; + + for( uint_t i = k; i < n; ++i ) + { + fp_t tr_sum = 0; + for( uint_t j = 0; j < k; ++j ) + { + uint_t idx = i - k + 1 + j; + fp_t tr = fmax( ts_h( x, idx ) - ts_l( x, idx ), fmax( fabs( ts_h( x, idx ) - ts_c( x, idx - 1 ) ), fabs( ts_l( x, idx ) - ts_c( x, idx - 1 ) ) ) ); + tr_sum += tr; + } + fp_t atr = tr_sum / (fp_t)k; + y[0][i] = ts_c( x, i ) != 0 ? atr / ts_c( x, i ) * 100.0 : 0; + } + return 0; +} + diff --git a/lib/nearbyint.c b/lib/nearbyint.c new file mode 100644 index 0000000..de32777 --- /dev/null +++ b/lib/nearbyint.c @@ -0,0 +1,40 @@ +// Nearbyint +// +// nearbyint +// +// Nearby integer +// +// Rounded to nearest integer per current rounding mode +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_nearbyint_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_nearbyint_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_nearbyint( + 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_nearbyint_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = nearbyint( x[0][i] ); + } + return 0; +} + diff --git a/lib/nextafter.c b/lib/nextafter.c new file mode 100644 index 0000000..8c766e8 --- /dev/null +++ b/lib/nextafter.c @@ -0,0 +1,40 @@ +// Nextafter +// +// nextafter +// +// Next representable float +// +// Next float after x toward y +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_nextafter_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_nextafter_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_nextafter( + 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_nextafter_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = nextafter( x[0][i], x[1][i] ); + } + return 0; +} + diff --git a/lib/nexttoward.c b/lib/nexttoward.c new file mode 100644 index 0000000..740dd91 --- /dev/null +++ b/lib/nexttoward.c @@ -0,0 +1,40 @@ +// Nexttoward +// +// nexttoward +// +// Next representable double +// +// Next double after x toward y +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_nexttoward_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_nexttoward_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_nexttoward( + 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_nexttoward_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = nexttoward( x[0][i], (long double)x[1][i] ); + } + return 0; +} + diff --git a/lib/none.c b/lib/none.c new file mode 100644 index 0000000..c9449d5 --- /dev/null +++ b/lib/none.c @@ -0,0 +1,36 @@ +// None (Identity) +// +// none - identity function +// +// Passes input through unchanged: y = x +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include <string.h> +#include "ts.h" + + + +ts_parameter_t const ts_none_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_none_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_none( + 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_none_p ); + (void)c; + memcpy( y[0], x[0], sizeof( fp_t ) * n ); + return 0; +} + diff --git a/lib/nvi.c b/lib/nvi.c new file mode 100644 index 0000000..f4d3397 --- /dev/null +++ b/lib/nvi.c @@ -0,0 +1,51 @@ +// Nvi +// +// nvi +// +// Negative Volume Index +// +// Accumulates price change on declining volume +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_nvi_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_nvi_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_nvi( + 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_nvi_p ); + (void)c; + if (n == 0) return -1; + + fp_t nvi = 1000; + + y[0][0] = nvi; + + for( uint_t i = 1; i < n; ++i ) + { + if( x[4][i] < x[4][i - 1] && x[3][i - 1] != 0 ) + { + fp_t r = ( x[3][i] - x[3][i - 1] ) / x[3][i - 1]; + nvi = nvi * ( 1 + r ); + } + y[0][i] = nvi; + } + + return 0; +} + diff --git a/lib/obv.c b/lib/obv.c new file mode 100644 index 0000000..3765ba3 --- /dev/null +++ b/lib/obv.c @@ -0,0 +1,54 @@ +// Obv +// +// obv +// +// On-Balance Volume +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_obv_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_obv_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 1 ); +} + +int ts_obv( + 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_obv_p ); + (void)c; + TS_CHECK_INPUT(x, x_n, n); + if (n == 0) return -1; + + fp_t obv = 0; + y[0][0] = 0; + + for( uint_t i = 1; i < n; ++i ) + { + if( x[3][i] > x[3][i - 1] ) + { + obv += x[4][i]; + } + else if( x[3][i] < x[3][i - 1] ) + { + obv -= x[4][i]; + } + y[0][i] = obv; + } + + return 0; +} + diff --git a/lib/on_balance_volume_rate.c b/lib/on_balance_volume_rate.c new file mode 100644 index 0000000..7183c23 --- /dev/null +++ b/lib/on_balance_volume_rate.c @@ -0,0 +1,74 @@ +// On Balance Volume Rate +// +// on_balance_volume_rate +// +// OBV Rate of Change +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 1 + + +#include <stdlib.h> +#include "ts.h" + +typedef struct { + fp_t f0; +} ts_on_balance_volume_rate_params_t; + +ts_parameter_t const ts_on_balance_volume_rate_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_on_balance_volume_rate_params_t) }; + +uint_t ts_on_balance_volume_rate_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? (uint_t)((ts_on_balance_volume_rate_params_t *)c)->f0 + 1 : 0 ); +} + +int ts_on_balance_volume_rate( + 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_on_balance_volume_rate_p ); + if ( !c ) return -1; + uint_t k = (uint_t)((ts_on_balance_volume_rate_params_t *)c)->f0; + if (k == 0 || k >= n) return -1; + + fp_t obv = 0; + + fp_t *obv_history = NULL; + if( n > 0 ) + { + obv_history = calloc( n, sizeof( fp_t ) ); + if( !obv_history ) return -1; + } + + for( uint_t i = 1; i < n; ++i ) + { + if( x[3][i] > x[3][i - 1] ) + { + obv += x[4][i]; + } + else if( x[3][i] < x[3][i - 1] ) + { + obv -= x[4][i]; + } + obv_history[i] = obv; + } + + for (uint_t i = 0; i <= k; ++i) y[0][i] = 0; + + for( uint_t i = k + 1; i < n; ++i ) + { + fp_t obv_prev = obv_history[i - k]; + y[0][i] = obv_prev != 0 ? ( obv_history[i] - obv_prev ) / obv_prev * 100 : 0; + } + + free( obv_history ); + + return 0; +} + diff --git a/lib/open_interest.c b/lib/open_interest.c new file mode 100644 index 0000000..a3d23aa --- /dev/null +++ b/lib/open_interest.c @@ -0,0 +1,40 @@ +// Open Interest +// +// open_interest +// +// Open Interest change +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_open_interest_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_open_interest_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_open_interest( + 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_open_interest_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i]; + } + + return 0; +} + diff --git a/lib/open_minus_close.c b/lib/open_minus_close.c new file mode 100644 index 0000000..2aaca32 --- /dev/null +++ b/lib/open_minus_close.c @@ -0,0 +1,39 @@ +// Open Minus Close +// +// open_minus_close +// +// Open minus Close +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_open_minus_close_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_open_minus_close_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_open_minus_close( + 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_open_minus_close_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] - x[3][i]; + } + return 0; +} + diff --git a/lib/oscillator_cross.c b/lib/oscillator_cross.c new file mode 100644 index 0000000..0c6c5f8 --- /dev/null +++ b/lib/oscillator_cross.c @@ -0,0 +1,70 @@ +// Oscillator Cross +// +// oscillator_cross +// +// Oscillator crossover detector +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 2 + + +#include "ts.h" + +typedef struct { + fp_t fast; + fp_t slow; +} ts_oscillator_cross_params_t; + +ts_parameter_t const ts_oscillator_cross_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_oscillator_cross_params_t) }; + +uint_t ts_oscillator_cross_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? (uint_t)((ts_oscillator_cross_params_t *)c)->slow : 0 ); +} + +int ts_oscillator_cross( + 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_oscillator_cross_p ); + if ( !c ) return -1; + fp_t const fast = ((ts_oscillator_cross_params_t *)c)->fast; + fp_t const slow = ((ts_oscillator_cross_params_t *)c)->slow; + if (fast == 0 || slow == 0) return -1; + if (n == 0) return -1; + fp_t const fast_a = 1.0 / fast; + fp_t const slow_a = 1.0 / slow; + fp_t fast_e = x[0][0]; + fp_t slow_e = x[0][0]; + uint_t const offset = (uint_t)slow; + if (offset >= n) return -1; + + for( uint_t i = 0; i < offset; ++i ) + y[0][i] = 0; + + for( uint_t i = 1; i < n; ++i ) + { + fp_t pf = fast_e; + fp_t ps = slow_e; + fast_e = fast_e + fast_a * ( x[0][i] - fast_e ); + slow_e = slow_e + slow_a * ( x[0][i] - slow_e ); + + if( i >= offset ) + { + if( fast_e > slow_e && pf <= ps ) + y[0][i] = 1; + else if( fast_e < slow_e && pf >= ps ) + y[0][i] = -1; + else + y[0][i] = 0; + } + } + return 0; +} + diff --git a/lib/osma.c b/lib/osma.c new file mode 100644 index 0000000..a5a2756 --- /dev/null +++ b/lib/osma.c @@ -0,0 +1,78 @@ +// Osma +// +// osma +// +// Oscillator Moving Average +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 3 + + +#include "ts.h" + +typedef struct { + fp_t fast_k; + fp_t slow_k; + fp_t signal_k; +} ts_osma_params_t; + +ts_parameter_t const ts_osma_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 3, .params_size = sizeof(ts_osma_params_t) }; + +uint_t ts_osma_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? (uint_t)((ts_osma_params_t *)c)->slow_k : 0 ); +} + +int ts_osma( + 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_osma_p ); + if ( !c ) return -1; + fp_t fast_k = ((ts_osma_params_t *)c)->fast_k; + fp_t slow_k = ((ts_osma_params_t *)c)->slow_k; + fp_t signal_k = ((ts_osma_params_t *)c)->signal_k; + + if (fast_k == 0 || slow_k == 0 || signal_k == 0) return -1; + if (n == 0) return -1; + + fp_t fast_a = 1.0 / fast_k; + fp_t slow_a = 1.0 / slow_k; + fp_t signal_a = 1.0 / signal_k; + + fp_t fast_ema = x[0][0]; + fp_t slow_ema = x[0][0]; + + uint_t slow_offset = (uint_t)(slow_k - 1); + if (n <= slow_offset + 1) return -1; + + for( uint_t i = 1; i <= slow_offset; ++i ) + { + fast_ema = fast_ema + fast_a * ( x[0][i] - fast_ema ); + slow_ema = slow_ema + slow_a * ( x[0][i] - slow_ema ); + } + + fp_t macd_line = fast_ema - slow_ema; + fp_t signal_ema = macd_line; + + for( uint_t i = slow_offset + 1; i < n; ++i ) + { + fast_ema = fast_ema + fast_a * ( x[0][i] - fast_ema ); + slow_ema = slow_ema + slow_a * ( x[0][i] - slow_ema ); + + macd_line = fast_ema - slow_ema; + signal_ema = signal_ema + signal_a * ( macd_line - signal_ema ); + + y[0][i] = macd_line - signal_ema; + } + + return 0; +} + + diff --git a/lib/parabolic_sar.c b/lib/parabolic_sar.c new file mode 100644 index 0000000..ff84834 --- /dev/null +++ b/lib/parabolic_sar.c @@ -0,0 +1,99 @@ +// Parabolic Sar +// +// parabolic_sar +// +// Parabolic SAR +// +// +// +// Inputs: 4 +// Outputs: 2 +// Constants: 2 + + +#include <math.h> +#include "ts.h" + +typedef struct { + fp_t step; + fp_t max_af; +} ts_parabolic_sar_params_t; + +ts_parameter_t const ts_parabolic_sar_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 2, .params_size = sizeof(ts_parabolic_sar_params_t) }; + +uint_t ts_parabolic_sar_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_parabolic_sar( + 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_parabolic_sar_p ); + if ( !c ) return -1; + fp_t step = ((ts_parabolic_sar_params_t *)c)->step; + fp_t max_af = ((ts_parabolic_sar_params_t *)c)->max_af; + if (step <= 0 || max_af <= 0) return -1; + if (isnan(step) || isnan(max_af)) return -1; + if (step > max_af) return -1; + if (n == 0) return -1; + + int_t trend = 1; + fp_t sar = ts_l( x, 0 ); + fp_t ep = ts_h( x, 0 ); + fp_t af = step; + + for ( uint_t i = 0; i < n; ++i ) + { + y[0][i] = sar; + y[1][i] = (fp_t)(trend > 0); + + if (i == 0) continue; + + if (trend > 0) + { + sar = sar + af * (ep - sar); + if (ts_l( x, i ) < sar) + { + trend = -1; + sar = ep; + ep = ts_l( x, i ); + af = step; + } + else + { + if (ts_h( x, i ) > ep) + { + ep = ts_h( x, i ); + af = af + step; + if (af > max_af) af = max_af; + } + } + } + else + { + sar = sar + af * (ep - sar); + if (ts_h( x, i ) > sar) + { + trend = 1; + sar = ep; + ep = ts_h( x, i ); + af = step; + } + else + { + if (ts_l( x, i ) < ep) + { + ep = ts_l( x, i ); + af = af + step; + if (af > max_af) af = max_af; + } + } + } + } + return 0; +} diff --git a/lib/performance_index.c b/lib/performance_index.c new file mode 100644 index 0000000..c211379 --- /dev/null +++ b/lib/performance_index.c @@ -0,0 +1,39 @@ +// Performance Index +// +// performance_index +// +// Performance Index +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_performance_index_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_performance_index_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_performance_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_performance_index_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] != 0 ? ( x[3][i] - x[0][i] ) / x[0][i] * 100 : 0; + } + return 0; +} + diff --git a/lib/performance_ratio.c b/lib/performance_ratio.c new file mode 100644 index 0000000..ffd0ece --- /dev/null +++ b/lib/performance_ratio.c @@ -0,0 +1,50 @@ +// Performance Ratio +// +// performance_ratio +// +// Performance Ratio +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_performance_ratio_params_t; + +ts_parameter_t const ts_performance_ratio_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_performance_ratio_params_t) }; + +uint_t ts_performance_ratio_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_performance_ratio_params_t *)c)->k : 0 ); +} + +int ts_performance_ratio( + 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_performance_ratio_p ); + if ( !c ) return -1; + uint_t k = ((ts_performance_ratio_params_t *)c)->k; + if (k <= 1 || n == 0) return -1; + + fp_t factor = (fp_t)k / (k - 1); + + for( uint_t i = k; i < n; ++i ) + { + fp_t v = x[0][i - k + 1]; + fp_t inner = v * v - 1; + y[0][i] = inner >= 0 ? sqrt( factor * inner ) : 0; + } + return 0; +} + diff --git a/lib/pivot_points.c b/lib/pivot_points.c new file mode 100644 index 0000000..b86c44a --- /dev/null +++ b/lib/pivot_points.c @@ -0,0 +1,51 @@ +// Pivot Points +// +// pivot_points +// +// Pivot Points +// +// +// +// Inputs: 5 +// Outputs: 5 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_pivot_points_p = { .n_inputs = 4, .n_outputs = 5, .n_constants = 0, .params_size = 0 }; + +uint_t ts_pivot_points_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 1 ); +} + +int ts_pivot_points( + 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_pivot_points_p ); + (void)c; + if (n > 0) { y[0][0] = 0; y[1][0] = 0; y[2][0] = 0; y[3][0] = 0; y[4][0] = 0; } + for( uint_t i = 1; i < n; ++i ) + { + fp_t prev_h = ts_h( x, i - 1 ); + fp_t prev_l = ts_l( x, i - 1 ); + fp_t prev_c = ts_c( x, i - 1 ); + + fp_t p = ( prev_h + prev_l + prev_c ) / 3.0; + fp_t range = prev_h - prev_l; + + y[0][i] = p; + y[1][i] = 2.0 * p - prev_l; + y[2][i] = 2.0 * p - prev_h; + y[3][i] = p + range; + y[4][i] = p - range; + } + return 0; +} + diff --git a/lib/plot.c b/lib/plot.c new file mode 100644 index 0000000..f459b05 --- /dev/null +++ b/lib/plot.c @@ -0,0 +1,39 @@ +// Plot +// +// plot +// +// Plot indicator +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_plot_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_plot_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_plot( + 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_plot_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i]; + } + return 0; +} + diff --git a/lib/poisson_pdf.c b/lib/poisson_pdf.c new file mode 100644 index 0000000..e1e2d59 --- /dev/null +++ b/lib/poisson_pdf.c @@ -0,0 +1,48 @@ +// Poisson Pdf +// +// poisson_pdf +// +// Poisson probability density +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + fp_t lambda; +} ts_poisson_pdf_params_t; + +ts_parameter_t const ts_poisson_pdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_poisson_pdf_params_t) }; + +uint_t ts_poisson_pdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_poisson_pdf( + 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_poisson_pdf_p ); + if ( !c ) return -1; + fp_t lambda = ((ts_poisson_pdf_params_t *)c)->lambda; + if (lambda < 0.0 || isnan(lambda) || isinf(lambda)) return -1; + for( uint_t i = 0; i < n; ++i ) + { + fp_t k_val = x[0][i]; + if( k_val < 0 ) { y[0][i] = 0; continue; } + uint_t k = (uint_t)k_val; + y[0][i] = pow( lambda, k ) * exp( -lambda ) / tgamma( k + 1.0 ); + } + return 0; +} + diff --git a/lib/polynomial.c b/lib/polynomial.c new file mode 100644 index 0000000..2914fe6 --- /dev/null +++ b/lib/polynomial.c @@ -0,0 +1,41 @@ +// Polynomial Power +// +// polynomial - pow(x, y) +// +// x raised to the power y +// +// Inputs: 2 (base, exponent) +// Outputs: 1 +// Constants: 0 + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_polynomial_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_polynomial_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_polynomial( + 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_polynomial_p ); + (void)c; + /* x[0] = base, x[1] = exponent */ + for (uint_t i = 0; i < n; ++i) + { + fp_t base = x[0][i]; + fp_t exponent = x[1][i]; + if( base < 0.0 && exponent != (fp_t)(long)exponent ) { y[0][i] = 0; continue; } + y[0][i] = pow(base, exponent); + } + return 0; +} + diff --git a/lib/power.c b/lib/power.c new file mode 100755 index 0000000..41bb644 --- /dev/null +++ b/lib/power.c @@ -0,0 +1,71 @@ +// Power +// +// power - pow +// +// f( x ) = x^r +// +// X_n - 1 +// Y_n - 1 +// C_n - 1 +// +// c[0] = r + + +#include <math.h> +#include "ts.h" + + +typedef struct { + fp_t r; +} ts_power_params_t; + +ts_parameter_t const ts_power_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_power_params_t) }; + + +uint_t ts_power_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_power( + 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_power_p ); + if ( !c ) return -1; + fp_t r = ((ts_power_params_t *)c)->r; + + for( uint_t i = 0; i < n; ++i ) + { + fp_t base = x[0][i]; + if ( base > 0 ) + { + y[0][i] = pow( base, r ); + } + else if ( base < 0 ) + { + fp_t intpart; + if ( modf( r, &intpart ) == 0 ) + { + fp_t result = pow( -base, r ); + long ip = (long)intpart; + y[0][i] = (ip >= 0 && (ip & 1) != 0) ? -result : result; + } + else + { + y[0][i] = 0; + } + } + else + { + if (r > 0.0) y[0][i] = 0.0; + else if (r < 0.0) y[0][i] = INFINITY; + else y[0][i] = 1.0; + } + } + return 0; +} + diff --git a/lib/ppo.c b/lib/ppo.c new file mode 100644 index 0000000..b2b3bbf --- /dev/null +++ b/lib/ppo.c @@ -0,0 +1,94 @@ +// Ppo +// +// ppo +// +// Percentage Price Oscillator +// +// +// +// Inputs: 5 +// Outputs: 2 +// Constants: 3 + + +#include "ts.h" + +typedef struct { + fp_t fast_k; + fp_t slow_k; + fp_t signal_k; +} ts_ppo_params_t; + +ts_parameter_t const ts_ppo_p = { .n_inputs = 5, .n_outputs = 2, .n_constants = 3, .params_size = sizeof(ts_ppo_params_t) }; + +uint_t ts_ppo_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? (uint_t)(((ts_ppo_params_t *)c)->slow_k + ((ts_ppo_params_t *)c)->signal_k - 2) : 0 ); +} + +int ts_ppo( + 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_ppo_p ); + if ( !c ) return -1; + fp_t fast_k = ((ts_ppo_params_t *)c)->fast_k; + fp_t slow_k = ((ts_ppo_params_t *)c)->slow_k; + fp_t signal_k = ((ts_ppo_params_t *)c)->signal_k; + + if (fast_k == 0 || slow_k == 0 || signal_k == 0) return -1; + if (n == 0) return -1; + + fp_t fast_a = 1.0 / fast_k; + fp_t slow_a = 1.0 / slow_k; + fp_t signal_a = 1.0 / signal_k; + + fp_t fast_ema = x[0][0]; + fp_t slow_ema = x[0][0]; + + uint_t slow_offset = (uint_t)(slow_k - 1); + uint_t signal_offset = (uint_t)(signal_k - 1); + uint_t total_offset = slow_offset + signal_offset; + + if (n <= total_offset) return -1; + + for( uint_t i = 1; i <= slow_offset; ++i ) + { + fast_ema = fast_ema + fast_a * ( x[0][i] - fast_ema ); + slow_ema = slow_ema + slow_a * ( x[0][i] - slow_ema ); + } + + fp_t ppo_val = slow_ema != 0 ? (fast_ema - slow_ema) / slow_ema * 100.0 : 0; + fp_t signal_ema = ppo_val; + + for( uint_t i = slow_offset + 1; i <= total_offset; ++i ) + { + fast_ema = fast_ema + fast_a * ( x[0][i] - fast_ema ); + slow_ema = slow_ema + slow_a * ( x[0][i] - slow_ema ); + + ppo_val = slow_ema != 0 ? (fast_ema - slow_ema) / slow_ema * 100.0 : 0; + signal_ema = signal_ema + signal_a * ( ppo_val - signal_ema ); + } + + y[0][total_offset] = ppo_val; + y[1][total_offset] = signal_ema; + + for( uint_t i = total_offset + 1; i < n; ++i ) + { + fast_ema = fast_ema + fast_a * ( x[0][i] - fast_ema ); + slow_ema = slow_ema + slow_a * ( x[0][i] - slow_ema ); + + ppo_val = slow_ema != 0 ? (fast_ema - slow_ema) / slow_ema * 100.0 : 0; + signal_ema = signal_ema + signal_a * ( ppo_val - signal_ema ); + + y[0][i] = ppo_val; + y[1][i] = signal_ema; + } + + return 0; +} + + diff --git a/lib/pretty_good_oscillator.c b/lib/pretty_good_oscillator.c new file mode 100644 index 0000000..65a05c2 --- /dev/null +++ b/lib/pretty_good_oscillator.c @@ -0,0 +1,64 @@ +// Pretty Good Oscillator +// +// pretty_good_oscillator +// +// Pretty Good Oscillator +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_pretty_good_oscillator_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_pretty_good_oscillator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_pretty_good_oscillator( + 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_pretty_good_oscillator_p ); + (void)c; + if (n == 0) return -1; + fp_t ema14 = x[0][0]; + fp_t ema30 = x[0][0]; + fp_t ema90 = x[0][0]; + fp_t a14 = 15.0 / (19.0 * 14); + fp_t a30 = 15.0 / (19.0 * 30); + fp_t a90 = 15.0 / (19.0 * 90); + + for( uint_t i = 0; i < n; ++i ) + { + if( i > 0 ) + { + ema14 = ema14 + a14 * (x[0][i] - ema14); + ema30 = ema30 + a30 * (x[0][i] - ema30); + ema90 = ema90 + a90 * (x[0][i] - ema90); + } + + fp_t arr[3] = {ema14, ema30, ema90}; + for( uint_t a = 0; a < 2; ++a ) + for( uint_t b = a + 1; b < 3; ++b ) + if( arr[a] > arr[b] ) { fp_t t = arr[a]; arr[a] = arr[b]; arr[b] = t; } + + fp_t median = arr[1]; + + if( median == 0 ) + y[0][i] = 0; + else + y[0][i] = (x[0][i] / median - 1.0); + } + return 0; +} + diff --git a/lib/price_channel.c b/lib/price_channel.c new file mode 100644 index 0000000..9aba070 --- /dev/null +++ b/lib/price_channel.c @@ -0,0 +1,58 @@ +// Price Channel +// +// price_channel +// +// Price Channel +// +// +// +// Inputs: 1 +// Outputs: 3 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_price_channel_params_t; + +ts_parameter_t const ts_price_channel_p = { .n_inputs = 1, .n_outputs = 3, .n_constants = 1, .params_size = sizeof(ts_price_channel_params_t) }; + +uint_t ts_price_channel_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_price_channel_params_t *)c)->k - 1 : 0 ); +} + +int ts_price_channel( + 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_price_channel_p ); + if ( !c ) return -1; + uint_t k = ((ts_price_channel_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t hh = x[0][i - k + 1]; + fp_t ll = x[0][i - k + 1]; + fp_t sum = x[0][i - k + 1]; + + for( uint_t j = i - k + 2; j <= i; ++j ) + { + if( x[0][j] > hh ) hh = x[0][j]; + if( x[0][j] < ll ) ll = x[0][j]; + sum += x[0][j]; + } + + y[0][i] = hh; + y[1][i] = sum / (fp_t)k; + y[2][i] = ll; + } + return 0; +} + diff --git a/lib/price_momentum_oscillator.c b/lib/price_momentum_oscillator.c new file mode 100644 index 0000000..b03f350 --- /dev/null +++ b/lib/price_momentum_oscillator.c @@ -0,0 +1,45 @@ +// Price Momentum Oscillator +// +// price_momentum_oscillator +// +// Price Momentum Oscillator +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_price_momentum_oscillator_params_t; + +ts_parameter_t const ts_price_momentum_oscillator_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_price_momentum_oscillator_params_t) }; + +uint_t ts_price_momentum_oscillator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_price_momentum_oscillator_params_t *)c)->k : 0 ); +} + +int ts_price_momentum_oscillator( + 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_price_momentum_oscillator_p ); + if ( !c ) return -1; + uint_t k = ((ts_price_momentum_oscillator_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for (uint_t i = k; i < n; ++i) + { + y[0][i] = x[0][i - k] != 0 ? ( x[0][i] / x[0][i - k] - 1 ) * 100 : 0; + } + return 0; +} + diff --git a/lib/price_rate_of_change.c b/lib/price_rate_of_change.c new file mode 100644 index 0000000..8f26548 --- /dev/null +++ b/lib/price_rate_of_change.c @@ -0,0 +1,45 @@ +// Price Rate Of Change +// +// price_rate_of_change +// +// Price Rate of Change +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_price_rate_of_change_params_t; + +ts_parameter_t const ts_price_rate_of_change_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_price_rate_of_change_params_t) }; + +uint_t ts_price_rate_of_change_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_price_rate_of_change_params_t *)c)->k : 0 ); +} + +int ts_price_rate_of_change( + 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_price_rate_of_change_p ); + if ( !c ) return -1; + uint_t k = ((ts_price_rate_of_change_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for (uint_t i = k; i < n; ++i) + { + y[0][i] = x[0][i - k] != 0 ? (x[0][i] - x[0][i - k]) / x[0][i - k] * 100 : 0; + } + return 0; +} + diff --git a/lib/prime_number_bands.c b/lib/prime_number_bands.c new file mode 100644 index 0000000..ac94e7b --- /dev/null +++ b/lib/prime_number_bands.c @@ -0,0 +1,58 @@ +// Prime Number Bands +// +// prime_number_bands +// +// Prime Number Bands +// +// +// +// Inputs: 1 +// Outputs: 3 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_prime_number_bands_params_t; + +ts_parameter_t const ts_prime_number_bands_p = { .n_inputs = 1, .n_outputs = 3, .n_constants = 1, .params_size = sizeof(ts_prime_number_bands_params_t) }; + +uint_t ts_prime_number_bands_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_prime_number_bands_params_t *)c)->k - 1 : 0 ); +} + +int ts_prime_number_bands( + 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_prime_number_bands_p ); + if ( !c ) return -1; + uint_t k = ((ts_prime_number_bands_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t sum = 0, sum2 = 0; + for( uint_t j = 0; j < k; ++j ) + { + fp_t v = x[0][i - k + 1 + j]; + sum += v; + sum2 += v * v; + } + fp_t mean = sum / k; + fp_t variance = sum2 / k - mean * mean; + fp_t stddev = variance >= 0 ? sqrt( variance ) : 0; + y[0][i] = mean; + y[1][i] = mean + 2.0 * stddev; + y[2][i] = mean - 2.0 * stddev; + } + return 0; +} + diff --git a/lib/prime_number_oscillator.c b/lib/prime_number_oscillator.c new file mode 100644 index 0000000..a86fa7b --- /dev/null +++ b/lib/prime_number_oscillator.c @@ -0,0 +1,82 @@ +// Prime Number Oscillator +// +// prime_number_oscillator +// +// Prime Number Oscillator +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_prime_number_oscillator_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_prime_number_oscillator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 23 ); +} + +int ts_prime_number_oscillator( + 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_prime_number_oscillator_p ); + (void)c; + fp_t last_gap = 0; + fp_t prev_prime = 0; + bool first_prime = true; + + for( uint_t i = 0; i < n; ++i ) + { + long v = (long)x[0][i]; + bool is_p = false; + + if( v >= 2 ) + { + if( v == 2 ) + is_p = true; + else if( v % 2 != 0 ) + { + is_p = true; + for( long d = 3; d <= v / d; d += 2 ) + { + if( v % d == 0 ) + { + is_p = false; + break; + } + } + } + } + + if( is_p ) + { + if( first_prime ) + { + prev_prime = (fp_t)v; + first_prime = false; + y[0][i] = 0; + } + else + { + last_gap = (fp_t)v - prev_prime; + prev_prime = (fp_t)v; + y[0][i] = last_gap; + } + } + else + { + y[0][i] = last_gap; + } + } + return 0; +} + diff --git a/lib/prings_kst.c b/lib/prings_kst.c new file mode 100644 index 0000000..e33688e --- /dev/null +++ b/lib/prings_kst.c @@ -0,0 +1,79 @@ +// Prings Kst +// +// prings_kst +// +// Prings KST +// +// +// +// Inputs: 1 +// Outputs: 2 +// Constants: 0 + + +#include <stdlib.h> +#include "ts.h" + + +ts_parameter_t const ts_prings_kst_p = { .n_inputs = 1, .n_outputs = 2, .n_constants = 0, .params_size = 0 }; + +uint_t ts_prings_kst_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 8 ); +} + +int ts_prings_kst( + 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_prings_kst_p ); + (void)c; + if (n < 23) return -1; + + fp_t *raw_kst = calloc( n, sizeof( fp_t ) ); + if ( !raw_kst ) return -1; + + for (uint_t i = 0; i < 8; ++i) { y[0][i] = 0; y[1][i] = 0; } + + for( uint_t i = 8; i < n; ++i ) + { + if ( x[0][i - 2] == 0 || x[0][i - 3] == 0 || x[0][i - 5] == 0 || x[0][i - 8] == 0 ) + { + raw_kst[i] = 0; + continue; + } + fp_t r2 = ( x[0][i] - x[0][i - 2] ) / x[0][i - 2] * 100; + fp_t r3 = ( x[0][i] - x[0][i - 3] ) / x[0][i - 3] * 100; + fp_t r5 = ( x[0][i] - x[0][i - 5] ) / x[0][i - 5] * 100; + fp_t r8 = ( x[0][i] - x[0][i - 8] ) / x[0][i - 8] * 100; + raw_kst[i] = r2 + 2 * r3 + 3 * r5 + 4 * r8; + } + + fp_t alpha1 = 2.0 / 11.0; + y[0][8] = raw_kst[8]; + for( uint_t i = 9; i < n; ++i ) + { + y[0][i] = y[0][i - 1] + alpha1 * ( raw_kst[i] - y[0][i - 1] ); + } + + fp_t alpha2 = 2.0 / 16.0; + for( uint_t i = 8; i < 16; ++i ) + y[1][i] = 0; + { + fp_t seed = 0; + for( uint_t i = 8; i <= 16; ++i ) seed += y[0][i]; + seed /= 9.0; + y[1][16] = seed; + } + for( uint_t i = 17; i < n; ++i ) + { + y[1][i] = y[1][i - 1] + alpha2 * ( y[0][i] - y[1][i - 1] ); + } + + free( raw_kst ); + return 0; +} + diff --git a/lib/prings_special_k.c b/lib/prings_special_k.c new file mode 100644 index 0000000..91a40ba --- /dev/null +++ b/lib/prings_special_k.c @@ -0,0 +1,86 @@ +// Prings Special K +// +// prings_special_k +// +// Prings Special K +// +// +// +// Inputs: 4 +// Outputs: 2 +// Constants: 2 + + +#include "ts.h" + +typedef struct { + uint_t k1; + uint_t k2; +} ts_prings_special_k_params_t; + +ts_parameter_t const ts_prings_special_k_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 2, .params_size = sizeof(ts_prings_special_k_params_t) }; + +uint_t ts_prings_special_k_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_prings_special_k_params_t *)c)->k1 > 0 && ((ts_prings_special_k_params_t *)c)->k2 > 0 ? ((ts_prings_special_k_params_t *)c)->k1 + ((ts_prings_special_k_params_t *)c)->k2 - 2 : 0 : 0 ); +} + +int ts_prings_special_k( + 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_prings_special_k_p ); + if ( !c ) return -1; + uint_t k1 = ((ts_prings_special_k_params_t *)c)->k1; + uint_t k2 = ((ts_prings_special_k_params_t *)c)->k2; + if (k1 == 0 || k2 == 0) return -1; + + fp_t ema = 0; + fp_t ema_a = 1.0 / (fp_t)k2; + + for (uint_t j = 0; j < n && j < k1 - 1; ++j) { y[0][j] = 0; y[1][j] = 0; } + for( uint_t i = k1 - 1; i < n; ++i ) + { + fp_t ll = ts_l( x, i ); + for( uint_t j = 1; j < k1; ++j ) + { + fp_t v = ts_l( x, i - j ); + if( v < ll ) ll = v; + } + + fp_t hh = ts_h( x, i ); + for( uint_t j = 1; j < k1; ++j ) + { + fp_t v = ts_h( x, i - j ); + if( v > hh ) hh = v; + } + + fp_t raw = ( hh != ll ) ? 100.0 * ( ts_c( x, i ) - ll ) / ( hh - ll ) : 0; + + if( i == k1 - 1 ) + { + ema = raw; + } + else + { + ema = ema + ema_a * ( raw - ema ); + } + + y[0][i] = ema; + + if( i >= k1 + k2 - 2 ) + { + fp_t d_sum = 0; + for( uint_t j = 0; j < k2; ++j ) + { + d_sum += y[0][i - j]; + } + y[1][i] = d_sum / (fp_t)k2; + } + } + return 0; +} + diff --git a/lib/psychological_line.c b/lib/psychological_line.c new file mode 100644 index 0000000..35fd912 --- /dev/null +++ b/lib/psychological_line.c @@ -0,0 +1,56 @@ +// Psychological Line +// +// psychological_line +// +// Psychological Line +// +// +// +// Inputs: 4 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_psychological_line_params_t; + +ts_parameter_t const ts_psychological_line_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_psychological_line_params_t) }; + +uint_t ts_psychological_line_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_psychological_line_params_t *)c)->k - 1 : 0 ); +} + +int ts_psychological_line( + 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_psychological_line_p ); + if ( !c ) return -1; + uint_t k = ((ts_psychological_line_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t sum = 0; + + for( uint_t i = 0; i < k; ++i ) + { + sum += ( ts_c( x, i ) > ts_o( x, i ) ) ? 100.0 : 0.0; + } + + y[0][k - 1] = sum / (fp_t)k; + + for( uint_t i = k; i < n; ++i ) + { + fp_t s = ( ts_c( x, i ) > ts_o( x, i ) ) ? 100.0 : 0.0; + fp_t s_old = ( ts_c( x, i - k ) > ts_o( x, i - k ) ) ? 100.0 : 0.0; + y[0][i] = y[0][i - 1] + ( s - s_old ) / (fp_t)k; + } + return 0; +} + diff --git a/lib/pvi.c b/lib/pvi.c new file mode 100644 index 0000000..26265d5 --- /dev/null +++ b/lib/pvi.c @@ -0,0 +1,61 @@ +// Pvi +// +// pvi +// +// Positive Volume Index +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_pvi_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_pvi_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_pvi( + 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_pvi_p ); + (void)c; + fp_t pvi = 1000; + + if (n == 0) return -1; + + y[0][0] = pvi; + + if( n > 1 ) + { + if( x[4][1] > x[4][0] && x[3][0] != 0 ) + { + fp_t r = ( x[3][1] - x[3][0] ) / x[3][0]; + pvi = pvi * ( 1 + r ); + } + y[0][1] = pvi; + } + + for( uint_t i = 2; i < n; ++i ) + { + if( x[4][i] > x[4][i - 1] && x[3][i - 1] != 0 ) + { + fp_t r = ( x[3][i] - x[3][i - 1] ) / x[3][i - 1]; + pvi = pvi * ( 1 + r ); + } + y[0][i] = pvi; + } + + return 0; +} + diff --git a/lib/pvt.c b/lib/pvt.c new file mode 100644 index 0000000..f98c288 --- /dev/null +++ b/lib/pvt.c @@ -0,0 +1,46 @@ +// Pvt +// +// pvt +// +// Price Volume Trend +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_pvt_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_pvt_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 1 ); +} + +int ts_pvt( + 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_pvt_p ); + (void)c; + if (n > 0) y[0][0] = 0; + + fp_t pvt = 0; + + for( uint_t i = 1; i < n; ++i ) + { + if( x[3][i - 1] != 0 ) + pvt += ( x[3][i] / x[3][i - 1] - 1 ) * x[4][i]; + y[0][i] = pvt; + } + + return 0; +} + diff --git a/lib/qstick.c b/lib/qstick.c new file mode 100644 index 0000000..d2f4361 --- /dev/null +++ b/lib/qstick.c @@ -0,0 +1,50 @@ +// Qstick +// +// qstick +// +// Q Stick +// +// +// +// Inputs: 4 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_qstick_params_t; + +ts_parameter_t const ts_qstick_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_qstick_params_t) }; + +uint_t ts_qstick_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_qstick_params_t *)c)->k - 1 : 0 ); +} + +int ts_qstick( + 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_qstick_p ); + if ( !c ) return -1; + uint_t k = ((ts_qstick_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t sum = 0; + for( uint_t j = 0; j < k; ++j ) + { + sum += ts_c( x, i - k + 1 + j ) - ts_o( x, i - k + 1 + j ); + } + y[0][i] = sum / (fp_t)k; + } + return 0; +} + diff --git a/lib/radian_degree.c b/lib/radian_degree.c new file mode 100644 index 0000000..046762a --- /dev/null +++ b/lib/radian_degree.c @@ -0,0 +1,39 @@ +// Radian Degree +// +// radian_degree +// +// Radians to Degrees +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_radian_degree_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_radian_degree_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_radian_degree( + 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_radian_degree_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] * 180.0 / PI; + } + return 0; +} + diff --git a/lib/rainbow_ma.c b/lib/rainbow_ma.c new file mode 100644 index 0000000..3311ec9 --- /dev/null +++ b/lib/rainbow_ma.c @@ -0,0 +1,61 @@ +// Rainbow Ma +// +// rainbow_ma +// +// Rainbow Moving Average +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_rainbow_ma_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_rainbow_ma_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 19 ); +} + +int ts_rainbow_ma( + 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_rainbow_ma_p ); + (void)c; + uint_t periods[7] = {3, 5, 7, 9, 11, 13, 15}; + + for( uint_t j = 0; j < n && j < 19; ++j ) y[0][j] = 0; + for( uint_t i = 19; i < n; ++i ) + { + fp_t sma_values[7]; + + for( uint_t p = 0; p < 7; ++p ) + { + fp_t sum = 0; + for( uint_t j = 0; j < periods[p]; ++j ) + sum += x[0][i - j]; + sma_values[p] = sum / periods[p]; + } + + for( uint_t a = 0; a < 6; ++a ) + for( uint_t b = a + 1; b < 7; ++b ) + if( sma_values[a] > sma_values[b] ) + { + fp_t t = sma_values[a]; + sma_values[a] = sma_values[b]; + sma_values[b] = t; + } + + y[0][i] = sma_values[2]; + } + return 0; +} + diff --git a/lib/rainbow_oscillator.c b/lib/rainbow_oscillator.c new file mode 100644 index 0000000..1a56b55 --- /dev/null +++ b/lib/rainbow_oscillator.c @@ -0,0 +1,68 @@ +// Rainbow Oscillator +// +// rainbow_oscillator +// +// Rainbow Oscillator +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_rainbow_oscillator_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_rainbow_oscillator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 13 ); +} + +int ts_rainbow_oscillator( + 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_rainbow_oscillator_p ); + (void)c; + uint_t const periods[] = { 2, 4, 6, 8, 10, 12, 14 }; + uint_t const num_periods = 7; + + for( uint_t j = 0; j < n && j < 13; ++j ) y[0][j] = 0; + for( uint_t i = 13; i < n; ++i ) + { + fp_t ma_values[7]; + + for( uint_t p = 0; p < num_periods; ++p ) + { + fp_t sum = 0; + for( uint_t j = 0; j < periods[p]; ++j ) + { + sum += x[0][i - j]; + } + ma_values[p] = sum / periods[p]; + } + + fp_t min_ma = ma_values[0]; + fp_t max_ma = ma_values[0]; + for( uint_t p = 1; p < num_periods; ++p ) + { + if( ma_values[p] < min_ma ) + min_ma = ma_values[p]; + if( ma_values[p] > max_ma ) + max_ma = ma_values[p]; + } + + if( max_ma == min_ma ) + y[0][i] = 0; + else + y[0][i] = ( x[0][i] - min_ma ) / ( max_ma - min_ma ) * 100.0; + } + return 0; +} + diff --git a/lib/random_walk_index.c b/lib/random_walk_index.c new file mode 100644 index 0000000..b4375e5 --- /dev/null +++ b/lib/random_walk_index.c @@ -0,0 +1,64 @@ +// Random Walk Index +// +// random_walk_index +// +// Random Walk Index +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_random_walk_index_params_t; + +ts_parameter_t const ts_random_walk_index_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_random_walk_index_params_t) }; + +uint_t ts_random_walk_index_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_random_walk_index_params_t *)c)->k : 0 ); +} + +int ts_random_walk_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_random_walk_index_p ); + if ( !c ) return -1; + uint_t k = ((ts_random_walk_index_params_t *)c)->k; + if (k == 0 || n < k + 1) return -1; + + fp_t sum_abs = 0; + fp_t sum_net = 0; + + for ( uint_t i = 0; i < k; ++i ) + { + fp_t change = x[0][i + 1] - x[0][i]; + sum_abs += fabs( change ); + sum_net += change; + } + + y[0][k] = sum_net == 0 ? 0 : sum_abs / sum_net; + + for ( uint_t i = k + 1; i < n; ++i ) + { + fp_t change_new = x[0][i] - x[0][i - 1]; + fp_t change_old = x[0][i - k] - x[0][i - k - 1]; + + sum_abs = sum_abs - fabs( change_old ) + fabs( change_new ); + sum_net = sum_net - change_old + change_new; + + y[0][i] = sum_net == 0 ? 0 : sum_abs / sum_net; + } + return 0; +} + diff --git a/lib/rank.c b/lib/rank.c new file mode 100644 index 0000000..392b63f --- /dev/null +++ b/lib/rank.c @@ -0,0 +1,54 @@ +// Rank +// +// rank +// +// Percentile rank +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_rank_params_t; + +ts_parameter_t const ts_rank_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_rank_params_t) }; + +uint_t ts_rank_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_rank_params_t *)c)->k - 1 : 0 ); +} + +int ts_rank( + 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_rank_p ); + if ( !c ) return -1; + uint_t k = ((ts_rank_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + uint_t count = 0; + fp_t current = x[0][i]; + + for( uint_t j = i - k + 1; j <= i; ++j ) + { + if( x[0][j] <= current ) + count++; + } + + y[0][i] = (fp_t)count / (fp_t)k * 100.0; + } + return 0; +} + diff --git a/lib/ratio.c b/lib/ratio.c new file mode 100755 index 0000000..8568476 --- /dev/null +++ b/lib/ratio.c @@ -0,0 +1,49 @@ +// Ratio +// +// ratio - ratio +// +// Calculates the ratio between the current value and the value k samples ago +// +// y_i = x_i / x_i-k +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_ratio_params_t; + +ts_parameter_t const ts_ratio_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_ratio_params_t) }; + + +uint_t ts_ratio_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_ratio_params_t *)c)->k : 0 ); +} + +int ts_ratio( + 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_ratio_p ); + if ( !c ) return -1; + uint_t k = ((ts_ratio_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = k; + + for( ; xi < n; xi++ ) + { + if( x[0][xi - k] == 0 ) { y[0][xi] = 0; } else { y[0][xi] = x[0][xi] / x[0][xi - k]; } + } + return 0; +} + diff --git a/lib/ravi.c b/lib/ravi.c new file mode 100644 index 0000000..fcb3095 --- /dev/null +++ b/lib/ravi.c @@ -0,0 +1,88 @@ +// Ravi +// +// ravi +// +// Rogers Average True Range +// +// +// +// Inputs: 4 +// Outputs: 2 +// Constants: 2 + + +#include <math.h> +#include <stdlib.h> +#include "ts.h" + +typedef struct { + uint_t k; + fp_t k2; +} ts_ravi_params_t; + +ts_parameter_t const ts_ravi_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 2, .params_size = sizeof(ts_ravi_params_t) }; + +uint_t ts_ravi_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_ravi_params_t *)c)->k + (uint_t)((ts_ravi_params_t *)c)->k2 - 2 : 0 ); +} + +int ts_ravi( + 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_ravi_p ); + if ( !c ) return -1; + uint_t k = ((ts_ravi_params_t *)c)->k; + fp_t k2 = ((ts_ravi_params_t *)c)->k2; + + if( k == 0 || k2 == 0 ) return -1; + + fp_t *num_buf = calloc( n, sizeof( fp_t ) ); + fp_t *den_buf = calloc( n, sizeof( fp_t ) ); + if( !num_buf || !den_buf ) { free( num_buf ); free( den_buf ); return -1; } + + for( uint_t i = 0; i < n; ++i ) + { + num_buf[i] = (x[3][i] - x[0][i]) + (x[3][i] - (i > 0 ? x[3][i - 1] : x[3][i])); + den_buf[i] = fabs(x[1][i] - x[2][i]) + fabs(x[3][i] - x[0][i]); + } + + fp_t num_sum = 0; + fp_t den_sum = 0; + + for( uint_t i = 0; i < k; ++i ) + { + num_sum += num_buf[i]; + den_sum += den_buf[i]; + } + + fp_t rvi = ( den_sum != 0 ) ? num_sum / den_sum : 0; + fp_t sig = rvi; + fp_t sig_a = 1.0 / k2; + uint_t offset = k + (uint_t)k2 - 2; + + for (uint_t i = 0; i < offset; ++i) { y[0][i] = 0; y[1][i] = 0; } + + for( uint_t i = k; i < n; ++i ) + { + num_sum = num_sum - num_buf[i - k] + num_buf[i]; + den_sum = den_sum - den_buf[i - k] + den_buf[i]; + rvi = ( den_sum != 0 ) ? num_sum / den_sum : 0; + sig = sig + sig_a * (rvi - sig); + + if( i >= offset ) + { + y[0][i] = rvi; + y[1][i] = sig; + } + } + + free( num_buf ); + free( den_buf ); + return 0; +} + diff --git a/lib/reciprocal.c b/lib/reciprocal.c new file mode 100644 index 0000000..7a42482 --- /dev/null +++ b/lib/reciprocal.c @@ -0,0 +1,39 @@ +// Reciprocal +// +// reciprocal - rec +// +// f( x ) = 1 / x +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_reciprocal_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_reciprocal_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_reciprocal( + 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_reciprocal_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = _ts_reciprocal( x[0][i] ); + } + return 0; +} + diff --git a/lib/regression_linear_least_squares.c b/lib/regression_linear_least_squares.c new file mode 100755 index 0000000..49123bb --- /dev/null +++ b/lib/regression_linear_least_squares.c @@ -0,0 +1,92 @@ +// Simple Least Squares Moving Linear Regression +// +// regression_linear_simple_least_squares - slrls +// +// ((k * sum_{i=0}^{n}[x_i * y_i]) - (sum_{i=0}^{n}[x_i] * sum_{i=0}^{n}[y_i])) +// β = ──────────────────────────────────────────────────────────────────────── +// ((k * sum_{i=0}^{n}[x_i^2]) - (sum_{i=0}^{n}[x_i^2])^2) +// +// α = E(y) - β * E(x) +// = μ_y - β * μ_x +// +// ( E( xy ) - E( μ_x ) * E( μ_y ) ) +// r_xy = ──────────────────────────────────────────────────────────────────────── +// ((E(x^2) - E(x)^2) - (E(y^2) - E(y)^2))^(1 / 2) +// +// y = α + βx +// +// Inputs: 2 +// Outputs: 3 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_regression_linear_least_squares_params_t; + +ts_parameter_t const ts_regression_linear_least_squares_p = { .n_inputs = 2, .n_outputs = 3, .n_constants = 1, .params_size = sizeof(ts_regression_linear_least_squares_params_t) }; + + +uint_t ts_regression_linear_least_squares_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_regression_linear_least_squares_params_t *)c)->k : 0 ); +} + +int ts_regression_linear_least_squares( + 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_regression_linear_least_squares_p ); + if ( !c ) return -1; + uint_t k = ((ts_regression_linear_least_squares_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = k; + uint_t yi = k; + fp_t var_x, var_y, cov_xy; + + for( ; xi < n; ++xi, ++yi ) + { + // Two-pass variance/covariance for numerical stability + fp_t mean_x = 0, mean_y = 0; + for (uint_t j = xi - k + 1; j <= xi; j++) { + mean_x += x[0][j]; + mean_y += x[1][j]; + } + mean_x /= (fp_t)k; + mean_y /= (fp_t)k; + var_x = 0; var_y = 0; cov_xy = 0; + for (uint_t j = xi - k + 1; j <= xi; j++) { + fp_t dx = x[0][j] - mean_x; + fp_t dy = x[1][j] - mean_y; + var_x += dx * dx; + var_y += dy * dy; + cov_xy += dx * dy; + } + var_x /= (fp_t)k; + var_y /= (fp_t)k; + cov_xy /= (fp_t)k; + + if ( var_x != 0 ) + { + y[0][yi] = cov_xy / var_x; + y[1][yi] = mean_y - y[0][yi] * mean_x; + } + else + { + y[0][yi] = 0; + y[1][yi] = mean_y; + } + fp_t prod = var_x * var_y; + y[2][yi] = prod > 0 ? cov_xy / sqrt( prod ) : 0; + } + return 0; +} + diff --git a/lib/relative_strength.c b/lib/relative_strength.c new file mode 100644 index 0000000..634cd47 --- /dev/null +++ b/lib/relative_strength.c @@ -0,0 +1,41 @@ +// Relative Strength +// +// relative_strength +// +// Relative Strength +// +// +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_relative_strength_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_relative_strength_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_relative_strength( + 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_relative_strength_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[1][i] == 0.0 ? 0.0 : x[0][i] / x[1][i] * 100.0; + } + return 0; +} + diff --git a/lib/relative_volatility.c b/lib/relative_volatility.c new file mode 100644 index 0000000..9682a2d --- /dev/null +++ b/lib/relative_volatility.c @@ -0,0 +1,75 @@ +// Relative Volatility +// +// relative_volatility +// +// Relative Volatility Index +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_relative_volatility_params_t; + +ts_parameter_t const ts_relative_volatility_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_relative_volatility_params_t) }; + +uint_t ts_relative_volatility_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_relative_volatility_params_t *)c)->k - 1 : 0 ); +} + +int ts_relative_volatility( + 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_relative_volatility_p ); + if ( !c ) return -1; + uint_t k = ((ts_relative_volatility_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = 0; + uint_t yi = k - 1; + + fp_t sum = 0; + fp_t sum2 = 0; + + for( ; xi < k; ++xi ) + { + sum += x[0][xi]; + sum2 += _ts_square( x[0][xi] ); + } + + fp_t mean = sum / k; + fp_t mean2 = sum2 / k; + fp_t variance = mean2 - _ts_square( mean ); + fp_t sd = variance >= 0 ? sqrt( variance ) : 0; + + y[0][yi] = (fabs( mean ) > 0) ? sd / fabs( mean ) * 100 : 0; + + fp_t rk = _ts_reciprocal( k ); + + for( ; xi < n; ++xi, ++yi ) + { + sum = sum + ( x[0][xi] - x[0][xi - k] ); + sum2 = sum2 + ( _ts_square( x[0][xi] ) - _ts_square( x[0][xi - k] ) ); + + mean = sum * rk; + mean2 = sum2 * rk; + variance = mean2 - _ts_square( mean ); + sd = variance >= 0 ? sqrt( variance ) : 0; + + y[0][yi] = (fabs( mean ) > 0) ? sd / fabs( mean ) * 100 : 0; + } + return 0; +} + diff --git a/lib/relu.c b/lib/relu.c new file mode 100644 index 0000000..4e96edb --- /dev/null +++ b/lib/relu.c @@ -0,0 +1,40 @@ +// ReLU +// +// relu - Rectified Linear Unit +// +// y[t] = max( 0, x[t] ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_relu_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_relu_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_relu( + 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_relu_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + y[0][i] = xi > 0 ? xi : 0; + } + return 0; +} + diff --git a/lib/remainder.c b/lib/remainder.c new file mode 100644 index 0000000..c3a6df7 --- /dev/null +++ b/lib/remainder.c @@ -0,0 +1,41 @@ +// Remainder +// +// remainder +// +// IEEE remainder +// +// +// +// Inputs: 2 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_remainder_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_remainder_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_remainder( + 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_remainder_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + if( x[1][i] == 0.0 ) { y[0][i] = 0; continue; } + y[0][i] = remainder( x[0][i], x[1][i] ); + } + return 0; +} + diff --git a/lib/remquo_dummy.c b/lib/remquo_dummy.c new file mode 100644 index 0000000..3f9bd48 --- /dev/null +++ b/lib/remquo_dummy.c @@ -0,0 +1,40 @@ +// Remquo Dummy +// +// remquo_dummy +// +// Remainder with quotient +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_remquo_dummy_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_remquo_dummy_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_remquo_dummy( + 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_remquo_dummy_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = remainder( x[0][i], 1.0 ); + } + return 0; +} + diff --git a/lib/reversal.c b/lib/reversal.c new file mode 100644 index 0000000..ede74fe --- /dev/null +++ b/lib/reversal.c @@ -0,0 +1,52 @@ +// Reversal +// +// reversal +// +// Reversal indicator +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_reversal_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_reversal_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 2 ); +} + +int ts_reversal( + 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_reversal_p ); + (void)c; + if (n > 0) y[0][0] = 0; + if (n > 1) y[0][1] = 0; + for( uint_t i = 2; i < n; ++i ) + { + if( x[0][i] < x[0][i - 1] && x[0][i - 1] > x[0][i - 2] ) + { + y[0][i] = -1; + } + else if( x[0][i] > x[0][i - 1] && x[0][i - 1] < x[0][i - 2] ) + { + y[0][i] = 1; + } + else + { + y[0][i] = 0; + } + } + return 0; +} + diff --git a/lib/rint.c b/lib/rint.c new file mode 100644 index 0000000..fb744fb --- /dev/null +++ b/lib/rint.c @@ -0,0 +1,40 @@ +// Rint +// +// rint +// +// Round to integer +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_rint_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_rint_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_rint( + 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_rint_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = rint( x[0][i] ); + } + return 0; +} + diff --git a/lib/roc.c b/lib/roc.c new file mode 100644 index 0000000..3b45ecd --- /dev/null +++ b/lib/roc.c @@ -0,0 +1,47 @@ +// Roc +// +// roc +// +// Rate of Change +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_roc_params_t; + +ts_parameter_t const ts_roc_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_roc_params_t) }; + +uint_t ts_roc_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_roc_params_t *)c)->k : 0 ); +} + +int ts_roc( + 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_roc_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_roc_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k; i < n; ++i ) + { + if( x[0][i - k] == 0 ) { y[0][i] = 0; continue; } + y[0][i] = ( x[0][i] - x[0][i - k] ) / x[0][i - k] * 100; + } + return 0; +} + diff --git a/lib/rocp.c b/lib/rocp.c new file mode 100644 index 0000000..6575d85 --- /dev/null +++ b/lib/rocp.c @@ -0,0 +1,46 @@ +// Rocp +// +// rocp +// +// Rate of Change Percentage +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_rocp_params_t; + +ts_parameter_t const ts_rocp_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_rocp_params_t) }; + +uint_t ts_rocp_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_rocp_params_t *)c)->k : 0 ); +} + +int ts_rocp( + 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_rocp_p ); + if ( !c ) return -1; + uint_t k = ((ts_rocp_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k; i < n; ++i ) + { + if( x[0][i - k] == 0 ) { y[0][i] = 0; continue; } + y[0][i] = ( x[0][i] - x[0][i - k] ) / x[0][i - k]; + } + return 0; +} + diff --git a/lib/rocr.c b/lib/rocr.c new file mode 100644 index 0000000..d11cb91 --- /dev/null +++ b/lib/rocr.c @@ -0,0 +1,46 @@ +// Rocr +// +// rocr +// +// Rate of Change Ratio +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_rocr_params_t; + +ts_parameter_t const ts_rocr_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_rocr_params_t) }; + +uint_t ts_rocr_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_rocr_params_t *)c)->k : 0 ); +} + +int ts_rocr( + 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_rocr_p ); + if ( !c ) return -1; + uint_t k = ((ts_rocr_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k; i < n; ++i ) + { + if( x[0][i - k] == 0 ) { y[0][i] = 0; continue; } + y[0][i] = x[0][i] / x[0][i - k]; + } + return 0; +} + diff --git a/lib/rocr100.c b/lib/rocr100.c new file mode 100644 index 0000000..b90413f --- /dev/null +++ b/lib/rocr100.c @@ -0,0 +1,45 @@ +// Rocr100 +// +// rocr100 +// +// Rate of Change Ratio * 100 +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_rocr100_params_t; + +ts_parameter_t const ts_rocr100_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_rocr100_params_t) }; + +uint_t ts_rocr100_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_rocr100_params_t *)c)->k : 0 ); +} + +int ts_rocr100( + 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_rocr100_p ); + if ( !c ) return -1; + uint_t k = ((ts_rocr100_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k; i < n; ++i ) + { + if( x[0][i - k] == 0 ) { y[0][i] = 0; continue; } + y[0][i] = x[0][i] / x[0][i - k] * 100; + } + return 0; +} + diff --git a/lib/root.c b/lib/root.c new file mode 100755 index 0000000..a5e7dca --- /dev/null +++ b/lib/root.c @@ -0,0 +1,48 @@ +// Nth Root +// +// n_root - nrt +// +// f( x ) = x^( 1 / n ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 1 +// +// c[0] = n + + +#include <math.h> +#include "ts.h" + + +typedef struct { + fp_t r; +} ts_root_params_t; + +ts_parameter_t const ts_root_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_root_params_t) }; + + +uint_t ts_root_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_root( + 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_root_p ); + if ( !c ) return -1; + fp_t r = ((ts_root_params_t *)c)->r; + if (r == 0) return -1; + + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = pow( x[0][i], _ts_reciprocal( r ) ); + } + return 0; +} + diff --git a/lib/root_cube.c b/lib/root_cube.c new file mode 100644 index 0000000..1cd79d5 --- /dev/null +++ b/lib/root_cube.c @@ -0,0 +1,41 @@ +// Cube Root +// +// cube_root - cbrt +// +// f( x ) = ∛x +// = x^( 1 / 3 ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_root_cube_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_root_cube_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_root_cube( + 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_root_cube_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = cbrt( x[0][i] ); + } + return 0; +} + diff --git a/lib/root_square.c b/lib/root_square.c new file mode 100644 index 0000000..3e8ef8e --- /dev/null +++ b/lib/root_square.c @@ -0,0 +1,43 @@ +// Square Root +// +// square_root - sqrt +// +// f( x ) = √x +// = x^( 1 / 2 ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 +// +// + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_root_square_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_root_square_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_root_square( + 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_root_square_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] >= 0 ? sqrt( x[0][i] ) : 0; + } + return 0; +} + diff --git a/lib/round_.c b/lib/round_.c new file mode 100644 index 0000000..f061b87 --- /dev/null +++ b/lib/round_.c @@ -0,0 +1,40 @@ +// Round +// +// round - round +// +// f( x ) = ⌊ x + 0.5 ⌋ +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_round__p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_round__offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_round_( + 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_round__p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = round( x[0][i] ); + } + return 0; +} + diff --git a/lib/rsi.c b/lib/rsi.c new file mode 100644 index 0000000..bf21c5e --- /dev/null +++ b/lib/rsi.c @@ -0,0 +1,91 @@ +// Rsi +// +// rsi +// +// Relative Strength Index +// +// RSI = 100 - (100 / (1 + RS)), where RS = avg_gain / avg_loss +// Uses Wilder's smoothing for avg_gain and avg_loss. +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_rsi_params_t; + +ts_parameter_t const ts_rsi_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_rsi_params_t) }; + +uint_t ts_rsi_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_rsi_params_t *)c)->k : 0 ); +} + +int ts_rsi( + 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_rsi_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_rsi_params_t *)c)->k; + if (k == 0 || n <= k) return -1; + + for (uint_t i = 0; i < k; ++i) y[0][i] = NAN; + + fp_t avg_gain = 0; + fp_t avg_loss = 0; + + for( uint_t i = 1; i <= k; ++i ) + { + fp_t change = x[0][i] - x[0][i - 1]; + if( change > 0 ) + avg_gain += change; + else if( change < 0 ) + avg_loss += (-change); + } + + avg_gain /= k; + avg_loss /= k; + + { + if( avg_loss < TS_FILL_ZERO_THRESHOLD ) + y[0][k] = 100; + else + { + fp_t rs = avg_gain / avg_loss; + y[0][k] = 100 - ( 100 / ( 1 + rs ) ); + } + } + + for( uint_t i = k + 1; i < n; ++i ) + { + fp_t change = x[0][i] - x[0][i - 1]; + fp_t gain = change > 0 ? change : 0; + fp_t loss = change < 0 ? (-change) : 0; + + avg_gain = ( avg_gain * ( k - 1 ) + gain ) / k; + avg_loss = ( avg_loss * ( k - 1 ) + loss ) / k; + + if( avg_loss < TS_FILL_ZERO_THRESHOLD ) + y[0][i] = 100; + else + { + fp_t rs = avg_gain / avg_loss; + y[0][i] = 100 - ( 100 / ( 1 + rs ) ); + } + } + + return 0; +} + + diff --git a/lib/running_count.c b/lib/running_count.c new file mode 100644 index 0000000..fb8d3ad --- /dev/null +++ b/lib/running_count.c @@ -0,0 +1,43 @@ +// Running Count +// +// running_count +// +// Running count of non-zero values +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_running_count_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_running_count_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_running_count( + 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_running_count_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + if( i == 0 ) + y[0][i] = ( x[0][i] != 0 ) ? 1 : 0; + else + y[0][i] = y[0][i - 1] + ( ( x[0][i] != 0 ) ? 1 : 0 ); + } + + return 0; +} + diff --git a/lib/schaff_trend_cycle.c b/lib/schaff_trend_cycle.c new file mode 100644 index 0000000..f4584e6 --- /dev/null +++ b/lib/schaff_trend_cycle.c @@ -0,0 +1,151 @@ +// Schaff Trend Cycle +// +// schaff_trend_cycle +// +// Schaff Trend Cycle +// +// +// +// Inputs: 1 +// Outputs: 2 +// Constants: 1 + + +#include <stdlib.h> +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t period; +} ts_schaff_trend_cycle_params_t; + +ts_parameter_t const ts_schaff_trend_cycle_p = { .n_inputs = 1, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_schaff_trend_cycle_params_t) }; + +uint_t ts_schaff_trend_cycle_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 52 ); +} + +int ts_schaff_trend_cycle( + 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_schaff_trend_cycle_p ); + if ( !c ) return -1; + uint_t period = ((ts_schaff_trend_cycle_params_t *)c)->period; + if (period == 0) period = 3; + if (n == 0) return -1; + if (period > n) { for (uint_t j = 0; j < n; ++j) { y[0][j] = 0; y[1][j] = 0; } return 0; } + + uint_t fast = 10; + uint_t slow = 21; + uint_t rsi_period = 13; + + fp_t ema_fast = x[0][0]; + fp_t ema_slow = x[0][0]; + fp_t a_fast = 2.0 / (fast + 1); + fp_t a_slow = 2.0 / (slow + 1); + + fp_t *macd_line = calloc(n, sizeof(fp_t)); + if (!macd_line) return -1; + + for( uint_t i = 1; i < n; ++i ) + { + ema_fast = ema_fast + a_fast * (x[0][i] - ema_fast); + ema_slow = ema_slow + a_slow * (x[0][i] - ema_slow); + macd_line[i] = ema_fast - ema_slow; + } + + fp_t *rsi1 = calloc(n, sizeof(fp_t)); + fp_t *rsi2 = calloc(n, sizeof(fp_t)); + if (!rsi1 || !rsi2) { free(macd_line); free(rsi1); free(rsi2); return -1; } + + { + fp_t avg_up = 0, avg_down = 0; + for( uint_t i = 1; i <= rsi_period; ++i ) + { + fp_t change = macd_line[i] - macd_line[i - 1]; + if( change > 0 ) avg_up += change; + else avg_down += (-change); + } + avg_up /= rsi_period; + avg_down /= rsi_period; + rsi1[rsi_period] = (avg_down == 0) ? 100 : 100 - 100 / (1 + avg_up / avg_down); + + for( uint_t i = rsi_period + 1; i < n; ++i ) + { + fp_t change = macd_line[i] - macd_line[i - 1]; + fp_t gain = change > 0 ? change : 0; + fp_t loss = change < 0 ? (-change) : 0; + avg_up = (avg_up * (rsi_period - 1) + gain) / rsi_period; + avg_down = (avg_down * (rsi_period - 1) + loss) / rsi_period; + rsi1[i] = (avg_down == 0) ? 100 : 100 - 100 / (1 + avg_up / avg_down); + } + } + + { + fp_t avg_up = 0, avg_down = 0; + for( uint_t i = rsi_period + 1; i <= rsi_period * 2; ++i ) + { + fp_t change = rsi1[i] - rsi1[i - 1]; + if( change > 0 ) avg_up += change; + else avg_down += (-change); + } + avg_up /= rsi_period; + avg_down /= rsi_period; + rsi2[rsi_period * 2] = (avg_down == 0) ? 100 : 100 - 100 / (1 + avg_up / avg_down); + + for( uint_t i = rsi_period * 2 + 1; i < n; ++i ) + { + fp_t change = rsi1[i] - rsi1[i - 1]; + fp_t gain = change > 0 ? change : 0; + fp_t loss = change < 0 ? (-change) : 0; + avg_up = (avg_up * (rsi_period - 1) + gain) / rsi_period; + avg_down = (avg_down * (rsi_period - 1) + loss) / rsi_period; + rsi2[i] = (avg_down == 0) ? 100 : 100 - 100 / (1 + avg_up / avg_down); + } + } + + uint_t offset = slow + rsi_period * 2; + fp_t sig_a = 1.0 / (fp_t)period; + fp_t signal_ema = 0; + uint_t active = 0; + uint_t count = 0; + + for (uint_t j = 0; j < n && j < offset; ++j) { y[0][j] = 0; y[1][j] = 0; } + for( uint_t i = offset; i < n; ++i ) + { + fp_t hist = macd_line[i] - macd_line[i - 1]; + fp_t hist_prev = (i > 1) ? macd_line[i - 1] - macd_line[i - 2] : 0; + int prev_above = hist_prev > 0.5; + int curr_above = hist > 0.5; + fp_t stc = 0; + + if( !prev_above && curr_above ) + { + active = 1; + count = 0; + } + if( active ) + { + stc = 100; + count++; + if( count >= period ) + active = 0; + } + + y[0][i] = stc; + + signal_ema = signal_ema + sig_a * (stc - signal_ema); + y[1][i] = signal_ema; + } + + free(macd_line); + free(rsi1); + free(rsi2); + return 0; +} + diff --git a/lib/secant.c b/lib/secant.c new file mode 100644 index 0000000..128e5a7 --- /dev/null +++ b/lib/secant.c @@ -0,0 +1,41 @@ +// Secant +// +// secant - sec +// +// f( x ) = sec( x ) = 1 / cos( x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_secant_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_secant_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_secant( + 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_secant_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t cv = cos( x[0][i] ); + y[0][i] = ( fabs( cv ) > 1e-15 ) ? _ts_reciprocal( cv ) : ( cv > 0 ? (fp_t)INFINITY : (fp_t)-INFINITY ); + } + return 0; +} + diff --git a/lib/secant_hyperbolic.c b/lib/secant_hyperbolic.c new file mode 100644 index 0000000..6956840 --- /dev/null +++ b/lib/secant_hyperbolic.c @@ -0,0 +1,42 @@ +// Hyperbolic Secant +// +// secant_hyperbolic - sech +// +// f( x ) = sech( x ) +// = 1 / cosh( x ) +// = 2 / ( e^x + e^( -x ) ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_secant_hyperbolic_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_secant_hyperbolic_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_secant_hyperbolic( + 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_secant_hyperbolic_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = _ts_reciprocal( cosh( x[0][i] ) ); + } + return 0; +} + diff --git a/lib/secant_hyperbolic_inverse.c b/lib/secant_hyperbolic_inverse.c new file mode 100644 index 0000000..d530d71 --- /dev/null +++ b/lib/secant_hyperbolic_inverse.c @@ -0,0 +1,42 @@ +// Inverse Hyperbolic Secant +// +// secant_hyperbolic_inverse - asech +// +// f( x ) = asech( x ) +// = ln( ( 1 / x ) + √( ( 1 / x^2 ) - 1 ) ) 0 < x ≤ 1 +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_secant_hyperbolic_inverse_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_secant_hyperbolic_inverse_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_secant_hyperbolic_inverse( + 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_secant_hyperbolic_inverse_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + y[0][i] = ( xi > 0 && xi <= 1.0 ) ? acosh( _ts_reciprocal( xi ) ) : 0; + } + return 0; +} + diff --git a/lib/secant_inverse.c b/lib/secant_inverse.c new file mode 100644 index 0000000..fbbab80 --- /dev/null +++ b/lib/secant_inverse.c @@ -0,0 +1,42 @@ +// Inverse Secant +// +// secant_inverse - asec +// +// f( x ) = asec( x ) +// = acos( 1 / x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_secant_inverse_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_secant_inverse_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_secant_inverse( + 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_secant_inverse_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t r = _ts_reciprocal( x[0][i] ); + y[0][i] = ( r >= -1.0 && r <= 1.0 ) ? acos( r ) : 0; + } + return 0; +} + diff --git a/lib/session_volume.c b/lib/session_volume.c new file mode 100644 index 0000000..be9810f --- /dev/null +++ b/lib/session_volume.c @@ -0,0 +1,43 @@ +// Session Volume +// +// session_volume +// +// Session volume +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_session_volume_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_session_volume_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_session_volume( + 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_session_volume_p ); + (void)c; + fp_t cum = 0; + + for( uint_t i = 0; i < n; ++i ) + { + cum += x[0][i]; + y[0][i] = cum; + } + + return 0; +} + diff --git a/lib/shinohara_intensity_ratio.c b/lib/shinohara_intensity_ratio.c new file mode 100644 index 0000000..fcdd364 --- /dev/null +++ b/lib/shinohara_intensity_ratio.c @@ -0,0 +1,85 @@ +// Shinohara Intensity Ratio +// +// shinohara_intensity_ratio +// +// Shinohara Intensity Ratio +// +// +// +// Inputs: 4 +// Outputs: 1 +// Constants: 1 + + +#include <stdlib.h> +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_shinohara_intensity_ratio_params_t; + +ts_parameter_t const ts_shinohara_intensity_ratio_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_shinohara_intensity_ratio_params_t) }; + +uint_t ts_shinohara_intensity_ratio_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_shinohara_intensity_ratio_params_t *)c)->k > 0 ? ((ts_shinohara_intensity_ratio_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_shinohara_intensity_ratio( + 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_shinohara_intensity_ratio_p ); + if ( !c ) return -1; + uint_t k = ((ts_shinohara_intensity_ratio_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t *intensity = calloc( n, sizeof( fp_t ) ); + if ( !intensity ) return -1; + + for( uint_t i = 0; i < n; ++i ) + { + fp_t h = ts_h(x, i); + fp_t l = ts_l(x, i); + fp_t cl = ts_c(x, i); + fp_t o = ts_o(x, i); + fp_t range = h - l; + + if( range == 0 ) + { + intensity[i] = 0; + } + else if( cl > o ) + { + intensity[i] = (h - cl) / range; + } + else + { + intensity[i] = (cl - l) / range; + } + } + + for (uint_t j = 0; j < n && j < k - 1; ++j) y[0][j] = 0; + for( uint_t i = k - 1; i < n; ++i ) + { + if( i == k - 1 ) + { + fp_t sum = 0; + for( uint_t j = 0; j < k; ++j ) + sum += intensity[j]; + y[0][i] = sum / k; + } + else + { + y[0][i] = y[0][i-1] + (intensity[i] - intensity[i - k]) / k; + } + } + + free( intensity ); + return 0; +} + diff --git a/lib/sigmoid.c b/lib/sigmoid.c new file mode 100644 index 0000000..05ea126 --- /dev/null +++ b/lib/sigmoid.c @@ -0,0 +1,63 @@ +// Sigmoid +// +// sigmoid - sig +// +// f(x) = ( L / ( 1 + e^( -( 4m * ( x - x_0 ) / L ) ) ) ) + b - ( L / 2 ) +// +// m = f'(0) +// b = f(0) +// ( b - ( L / 2 ) ) < y < ( b + ( L / 2 ) ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 3 +// +// c[0] = m +// c[1] = L +// c[2] = b + + +#include <math.h> +#include "ts.h" + + +typedef struct { + fp_t m; + fp_t L; + fp_t b; +} ts_sigmoid_params_t; + +ts_parameter_t const ts_sigmoid_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 3, .params_size = sizeof(ts_sigmoid_params_t) }; + + +uint_t ts_sigmoid_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_sigmoid( + 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_sigmoid_p ); + if ( !c ) return -1; + fp_t m = ((ts_sigmoid_params_t *)c)->m; + fp_t L = ((ts_sigmoid_params_t *)c)->L; + fp_t b = ((ts_sigmoid_params_t *)c)->b; + + m = -( 4.0 * m ) / L; + b = b - ( 0.5 * L ); + + for( uint_t i = 0; i < n; ++i ) + { + fp_t xv = m * x[0][i]; + if( xv > 500.0 ) { y[0][i] = b; continue; } + if( xv < -500.0 ) { y[0][i] = L + b; continue; } + y[0][i] = ( L / ( 1.0 + exp( xv ) ) ) + b; + } + return 0; +} + diff --git a/lib/sign.c b/lib/sign.c new file mode 100644 index 0000000..d6b1aaf --- /dev/null +++ b/lib/sign.c @@ -0,0 +1,41 @@ +// Sign +// +// sign - sgn +// +// ⎧ -1 if x < 0 +// f( x ) = ⎨ 0 if x = 0 +// ⎩ 1 if x > 0 +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_sign_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_sign_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_sign( + 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_sign_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = ( x[0][i] > 0 ) - ( x[0][i] < 0 ); + } + return 0; +} + diff --git a/lib/sinc.c b/lib/sinc.c new file mode 100644 index 0000000..779c8da --- /dev/null +++ b/lib/sinc.c @@ -0,0 +1,47 @@ +// Sinc +// +// sinc - Normalized Sinc function +// +// y[t] = x[t] == 0 ? 1 : sin( pi * x[t] ) / ( pi * x[t] ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_sinc_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_sinc_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_sinc( + 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_sinc_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + if ( xi == 0 ) + y[0][i] = 1; + else + { + fp_t pix = PI * xi; + y[0][i] = sin( pix ) / pix; + } + } + return 0; +} + diff --git a/lib/sinc_unnormalized.c b/lib/sinc_unnormalized.c new file mode 100644 index 0000000..c68f9fa --- /dev/null +++ b/lib/sinc_unnormalized.c @@ -0,0 +1,44 @@ +// Sinc Unnormalized +// +// sinc_unnormalized - Unnormalized Sinc function +// +// y[t] = x[t] == 0 ? 1 : sin( x[t] ) / x[t] +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_sinc_unnormalized_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_sinc_unnormalized_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_sinc_unnormalized( + 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_sinc_unnormalized_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + if ( xi == 0 ) + y[0][i] = 1; + else + y[0][i] = sin( xi ) / xi; + } + return 0; +} + diff --git a/lib/sine.c b/lib/sine.c new file mode 100644 index 0000000..262d4f8 --- /dev/null +++ b/lib/sine.c @@ -0,0 +1,40 @@ +// Sine +// +// sine - sin +// +// f( x ) = sin( x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_sine_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_sine_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_sine( + 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_sine_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = sin( x[0][i] ); + } + return 0; +} + diff --git a/lib/sine_hyperbolic.c b/lib/sine_hyperbolic.c new file mode 100644 index 0000000..5662f19 --- /dev/null +++ b/lib/sine_hyperbolic.c @@ -0,0 +1,41 @@ +// Hyperbolic Sine +// +// sine_hyperbolic - sinh +// +// f( x ) = sinh( x ) +// = 0.5 * ( e^x - e^( -x ) ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_sine_hyperbolic_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_sine_hyperbolic_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_sine_hyperbolic( + 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_sine_hyperbolic_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = sinh( x[0][i] ); + } + return 0; +} + diff --git a/lib/sine_hyperbolic_inverse.c b/lib/sine_hyperbolic_inverse.c new file mode 100644 index 0000000..57c1be5 --- /dev/null +++ b/lib/sine_hyperbolic_inverse.c @@ -0,0 +1,41 @@ +// Inverse Hyperbolic Sine +// +// sine_hyperbolic_inverse - asinh +// +// f( x ) = asinh( x ) +// = ln( x + √( x^2 + 1 ) ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_sine_hyperbolic_inverse_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_sine_hyperbolic_inverse_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_sine_hyperbolic_inverse( + 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_sine_hyperbolic_inverse_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = asinh( x[0][i] ); + } + return 0; +} + diff --git a/lib/sine_inverse.c b/lib/sine_inverse.c new file mode 100644 index 0000000..5d96513 --- /dev/null +++ b/lib/sine_inverse.c @@ -0,0 +1,41 @@ +// Inverse Sine +// +// sine_inverse - asin +// +// f( x ) = asin( x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_sine_inverse_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_sine_inverse_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_sine_inverse( + 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_sine_inverse_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t v = x[0][i]; + y[0][i] = ( v >= -1.0 && v <= 1.0 ) ? asin( v ) : 0; + } + return 0; +} + diff --git a/lib/slope.c b/lib/slope.c new file mode 100755 index 0000000..ca4fd22 --- /dev/null +++ b/lib/slope.c @@ -0,0 +1,51 @@ +// Slope +// +// slope - slope +// +// Calculates the slope between the current value and the value k samples ago +// +// y_i = ( x_i - x_i-k ) / k +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_slope_params_t; + +ts_parameter_t const ts_slope_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_slope_params_t) }; + + +uint_t ts_slope_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_slope_params_t *)c)->k : 0 ); +} + +int ts_slope( + 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_slope_p ); + if ( !c ) return -1; + uint_t k = ((ts_slope_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = k; + + fp_t rk = _ts_reciprocal( k ); + + for( ; xi < n; xi++ ) + { + y[0][xi] = ( x[0][xi] - x[0][xi - k] ) * rk; + } + return 0; +} + diff --git a/lib/smootherstep.c b/lib/smootherstep.c new file mode 100644 index 0000000..3053bcf --- /dev/null +++ b/lib/smootherstep.c @@ -0,0 +1,49 @@ +// Smootherstep +// +// smootherstep - Smootherstep interpolation +// +// y[t] = x[t] <= 0 ? 0 : x[t] >= 1 ? 1 : 6*x[t]^5 - 15*x[t]^4 + 10*x[t]^3 +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_smootherstep_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_smootherstep_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_smootherstep( + 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_smootherstep_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + if ( xi <= 0 ) + y[0][i] = 0; + else if ( xi >= 1 ) + y[0][i] = 1; + else + { + fp_t x2 = xi * xi; + fp_t x3 = x2 * xi; + y[0][i] = 6 * x3 * x2 - 15 * x2 * x2 + 10 * x3; + } + } + return 0; +} + diff --git a/lib/smoothstep.c b/lib/smoothstep.c new file mode 100644 index 0000000..224e68b --- /dev/null +++ b/lib/smoothstep.c @@ -0,0 +1,48 @@ +// Smoothstep +// +// smoothstep - Smoothstep interpolation +// +// y[t] = x[t] <= 0 ? 0 : x[t] >= 1 ? 1 : 3*x[t]^2 - 2*x[t]^3 +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_smoothstep_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_smoothstep_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_smoothstep( + 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_smoothstep_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + if ( xi <= 0 ) + y[0][i] = 0; + else if ( xi >= 1 ) + y[0][i] = 1; + else + { + fp_t x2 = xi * xi; + y[0][i] = 3 * x2 - 2 * x2 * xi; + } + } + return 0; +} + diff --git a/lib/softplus.c b/lib/softplus.c new file mode 100644 index 0000000..b61f96b --- /dev/null +++ b/lib/softplus.c @@ -0,0 +1,41 @@ +// Softplus +// +// softplus - Softplus activation +// +// y[t] = log( 1 + exp( x[t] ) ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_softplus_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_softplus_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_softplus( + 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_softplus_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + y[0][i] = xi > 20 ? xi : log( 1 + exp( xi ) ); + } + return 0; +} + diff --git a/lib/softsign.c b/lib/softsign.c new file mode 100644 index 0000000..978f275 --- /dev/null +++ b/lib/softsign.c @@ -0,0 +1,41 @@ +// Softsign +// +// softsign - Softsign activation +// +// y[t] = x[t] / ( 1 + |x[t]| ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_softsign_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_softsign_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_softsign( + 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_softsign_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + y[0][i] = xi / ( 1 + fabs( xi ) ); + } + return 0; +} + diff --git a/lib/standard_error.c b/lib/standard_error.c new file mode 100644 index 0000000..9b0ac3b --- /dev/null +++ b/lib/standard_error.c @@ -0,0 +1,67 @@ +// Standard Error +// +// standard_error +// +// Standard Error of the Mean +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_standard_error_params_t; + +ts_parameter_t const ts_standard_error_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_standard_error_params_t) }; + +uint_t ts_standard_error_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_standard_error_params_t *)c)->k > 0 ? ((ts_standard_error_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_standard_error( + 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_standard_error_p ); + if ( !c ) return -1; + uint_t k = ((ts_standard_error_params_t *)c)->k; + if (k < 2) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t sum_x = 0, sum_y = 0, sum_xy = 0, sum_x2 = 0, sum_y2 = 0; + for( uint_t j = 0; j < k; ++j ) + { + fp_t xv = (fp_t)j; + fp_t yv = x[0][i - k + 1 + j]; + sum_x += xv; + sum_y += yv; + sum_xy += xv * yv; + sum_x2 += xv * xv; + sum_y2 += yv * yv; + } + fp_t nk = (fp_t)k; + fp_t denom = nk * sum_x2 - sum_x * sum_x; + if( denom == 0 ) + { + y[0][i] = 0; + } + else + { + fp_t ss_res = sum_y2 - (sum_y * sum_y) / nk - ((nk * sum_xy - sum_x * sum_y) * (nk * sum_xy - sum_x * sum_y)) / (nk * denom); + y[0][i] = ss_res > 0 ? sqrt( ss_res / (nk - 2) ) : 0; + } + } + return 0; +} + diff --git a/lib/starc_bands.c b/lib/starc_bands.c new file mode 100644 index 0000000..0c545f8 --- /dev/null +++ b/lib/starc_bands.c @@ -0,0 +1,70 @@ +// Starc Bands +// +// starc_bands +// +// STARC Bands +// +// +// +// Inputs: 4 +// Outputs: 3 +// Constants: 2 + + +#include <math.h> +#include "ts.h" + + +typedef struct { + uint_t k; + fp_t mult; +} ts_starc_bands_params_t; + +ts_parameter_t const ts_starc_bands_p = { .n_inputs = 4, .n_outputs = 3, .n_constants = 2, .params_size = sizeof(ts_starc_bands_params_t) }; + + +uint_t ts_starc_bands_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_starc_bands_params_t *)c)->k : 0 ); +} + +int ts_starc_bands( + 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_starc_bands_p ); + if ( !c ) return -1; + uint_t k = ((ts_starc_bands_params_t *)c)->k; + if (k == 0) return -1; + if (n < k + 1) return -1; + + fp_t mult = ((ts_starc_bands_params_t *)c)->mult; + + for( uint_t i = k; i < n; ++i ) + { + fp_t tr_sum = 0; + for( uint_t j = 0; j < k; ++j ) + { + uint_t idx = i - k + 1 + j; + fp_t tr = fmax( ts_h( x, idx ) - ts_l( x, idx ), fmax( fabs( ts_h( x, idx ) - ts_c( x, idx - 1 ) ), fabs( ts_l( x, idx ) - ts_c( x, idx - 1 ) ) ) ); + tr_sum += tr; + } + fp_t atr = tr_sum / (fp_t)k; + + fp_t sum = 0; + for( uint_t j = 0; j < k; ++j ) + { + sum += ts_c( x, i - k + 1 + j ); + } + fp_t mean = sum / k; + + y[0][i] = mean + mult * atr; + y[1][i] = mean; + y[2][i] = mean - mult * atr; + } + return 0; +} + diff --git a/lib/starc_lower.c b/lib/starc_lower.c new file mode 100644 index 0000000..97ac02f --- /dev/null +++ b/lib/starc_lower.c @@ -0,0 +1,74 @@ +// Starc Lower +// +// starc_lower +// +// STARC Lower Band +// +// +// +// Inputs: 4 +// Outputs: 1 +// Constants: 2 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; + fp_t mult; +} ts_starc_lower_params_t; + +ts_parameter_t const ts_starc_lower_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_starc_lower_params_t) }; + +uint_t ts_starc_lower_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_starc_lower_params_t *)c)->k > 0 ? ((ts_starc_lower_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_starc_lower( + 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_starc_lower_p ); + if ( !c ) return -1; + uint_t k = ((ts_starc_lower_params_t *)c)->k; + if( k == 0 ) return -1; + fp_t mult = ((ts_starc_lower_params_t *)c)->mult; + + uint_t half_k = k / 2; + if (n <= half_k) return -1; + + uint_t last = k - 1; + for( uint_t i = k - 1; i < n - half_k; ++i ) + { + fp_t middle_sum = 0; + fp_t atr_sum = 0; + + for( uint_t j = 0; j < k; ++j ) + { + uint_t idx = i - half_k + j; + middle_sum += ts_c( x, idx ); + + fp_t tr = ts_h( x, idx ) - ts_l( x, idx ); + if( idx > 0 ) + { + fp_t h_pc = fabs( ts_h( x, idx ) - ts_c( x, idx - 1 ) ); + fp_t l_pc = fabs( ts_l( x, idx ) - ts_c( x, idx - 1 ) ); + if( h_pc > tr ) tr = h_pc; + if( l_pc > tr ) tr = l_pc; + } + atr_sum += tr; + } + + y[0][i] = middle_sum / k - mult * atr_sum / k; + last = i; + } + for( uint_t i = last + 1; i < n; ++i ) + y[0][i] = y[0][last]; + return 0; +} + diff --git a/lib/starc_upper.c b/lib/starc_upper.c new file mode 100644 index 0000000..bcccb95 --- /dev/null +++ b/lib/starc_upper.c @@ -0,0 +1,64 @@ +// Starc Upper +// +// starc_upper +// +// STARC Upper Band +// +// +// +// Inputs: 4 +// Outputs: 1 +// Constants: 2 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; + fp_t mult; +} ts_starc_upper_params_t; + +ts_parameter_t const ts_starc_upper_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_starc_upper_params_t) }; + +uint_t ts_starc_upper_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_starc_upper_params_t *)c)->k : 0 ); +} + +int ts_starc_upper( + 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_starc_upper_p ); + if ( !c ) return -1; + uint_t k = ((ts_starc_upper_params_t *)c)->k; + fp_t mult = ((ts_starc_upper_params_t *)c)->mult; + if ( k == 0 || k >= n ) return -1; + + for ( uint_t i = k; i < n; ++i ) + { + fp_t tr_sum = 0; + for ( uint_t j = 0; j < k; ++j ) + { + uint_t idx = i - k + 1 + j; + fp_t tr = fmax( ts_h( x, idx ) - ts_l( x, idx ), fmax( fabs( ts_h( x, idx ) - ts_c( x, idx - 1 ) ), fabs( ts_l( x, idx ) - ts_c( x, idx - 1 ) ) ) ); + tr_sum += tr; + } + fp_t atr = tr_sum / (fp_t)k; + + fp_t sum = 0; + for ( uint_t j = 0; j < k; ++j ) + { + sum += ts_c( x, i - k + 1 + j ); + } + fp_t mean = sum / k; + + y[0][i] = mean + mult * atr; + } + return 0; +} + diff --git a/lib/std_error.c b/lib/std_error.c new file mode 100644 index 0000000..f55d34e --- /dev/null +++ b/lib/std_error.c @@ -0,0 +1,57 @@ +// Std Error +// +// std_error +// +// Standard Error +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_std_error_params_t; + +ts_parameter_t const ts_std_error_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_std_error_params_t) }; + +uint_t ts_std_error_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_std_error_params_t *)c)->k > 0 ? ((ts_std_error_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_std_error( + 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_std_error_p ); + if ( !c ) return -1; + uint_t k = ((ts_std_error_params_t *)c)->k; + if ( k == 0 ) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t sum = 0; + for( uint_t j = 0; j < k; ++j ) + sum += x[0][i - k + 1 + j]; + + fp_t mean = sum / k; + + fp_t sum_sq = 0; + for( uint_t j = 0; j < k; ++j ) + sum_sq += _ts_square( x[0][i - k + 1 + j] ); + + fp_t variance = sum_sq / k - _ts_square( mean ); + y[0][i] = variance >= 0 ? sqrt( variance ) / sqrt( (fp_t)k ) : 0; + } + return 0; +} + diff --git a/lib/stoch_rsi.c b/lib/stoch_rsi.c new file mode 100644 index 0000000..81992a6 --- /dev/null +++ b/lib/stoch_rsi.c @@ -0,0 +1,96 @@ +// Stoch Rsi +// +// stoch_rsi +// +// Stochastic RSI +// +// +// +// Inputs: 1 +// Outputs: 2 +// Constants: 2 + + +#include <math.h> +#include <stdlib.h> +#include "ts.h" + +typedef struct { + uint_t rsi_period; + uint_t stoch_period; +} ts_stoch_rsi_params_t; + +ts_parameter_t const ts_stoch_rsi_p = { .n_inputs = 1, .n_outputs = 2, .n_constants = 2, .params_size = sizeof(ts_stoch_rsi_params_t) }; + +uint_t ts_stoch_rsi_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_stoch_rsi_params_t *)c)->rsi_period + ((ts_stoch_rsi_params_t *)c)->stoch_period - 1 : 0 ); +} + +int ts_stoch_rsi( + 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_stoch_rsi_p ); + if ( !c ) return -1; + uint_t rsi_period = ((ts_stoch_rsi_params_t *)c)->rsi_period; + uint_t stoch_period = ((ts_stoch_rsi_params_t *)c)->stoch_period; + if (rsi_period == 0 || stoch_period == 0) return -1; + + fp_t *rsi_values = NULL; + if( n > 0 ) + { + rsi_values = calloc( n, sizeof( fp_t ) ); + if( !rsi_values ) return -1; + } + + for( uint_t i = rsi_period; i < n; ++i ) + { + fp_t sum_gain = 0; + fp_t sum_loss = 0; + + for( uint_t j = 0; j < rsi_period; ++j ) + { + fp_t change = x[0][i - rsi_period + 1 + j] - x[0][i - rsi_period + j]; + if( change > 0 ) + sum_gain += change; + else if( change < 0 ) + sum_loss += (-change); + } + + if( sum_loss == 0 ) + rsi_values[i] = 100.0; + else + { + fp_t rs = sum_gain / sum_loss; + rsi_values[i] = 100.0 - ( 100.0 / ( 1.0 + rs ) ); + } + } + + for (uint_t j = 0; j < n && j < rsi_period + stoch_period - 1; ++j) { y[0][j] = 0; y[1][j] = 0; } + for( uint_t i = rsi_period + stoch_period - 1; i < n; ++i ) + { + fp_t rsi_min = rsi_values[i - stoch_period + 1]; + fp_t rsi_max = rsi_values[i - stoch_period + 1]; + + for( uint_t j = 1; j < stoch_period; ++j ) + { + rsi_min = fmin( rsi_min, rsi_values[i - stoch_period + 1 + j] ); + rsi_max = fmax( rsi_max, rsi_values[i - stoch_period + 1 + j] ); + } + + fp_t denom = rsi_max - rsi_min; + fp_t stoch_k = denom != 0 ? ( rsi_values[i] - rsi_min ) / denom : 0; + fp_t stoch_d = stoch_k; + + y[0][i] = stoch_k; + y[1][i] = stoch_d; + } + + free( rsi_values ); + return 0; +} + diff --git a/lib/stochastic_fast.c b/lib/stochastic_fast.c new file mode 100644 index 0000000..eb203c8 --- /dev/null +++ b/lib/stochastic_fast.c @@ -0,0 +1,94 @@ +// Stochastic Fast +// +// stochastic_fast +// +// Stochastic Fast %K +// +// +// +// Inputs: 4 +// Outputs: 2 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_stochastic_fast_params_t; + +ts_parameter_t const ts_stochastic_fast_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_stochastic_fast_params_t) }; + +uint_t ts_stochastic_fast_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_stochastic_fast_params_t *)c)->k > 0 ? 2 * ((ts_stochastic_fast_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_stochastic_fast( + 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_fast_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_stochastic_fast_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + // Initial window max/min + fp_t hh = ts_h( x, 0 ); + fp_t ll = ts_l( x, 0 ); + for( uint_t j = 1; j < k; ++j ) + { + if( ts_h( x, j ) > hh ) + hh = ts_h( x, j ); + if( ts_l( x, j ) < ll ) + ll = ts_l( x, j ); + } + + { + fp_t k_val = ( hh - ll ) == 0 ? 0 : 100.0 * ( ts_c( x, k - 1 ) - ll ) / ( hh - ll ); + y[0][k - 1] = k_val; + } + + for( uint_t i = k; i < n; ++i ) + { + fp_t new_h = ts_h( x, i ); + fp_t new_l = ts_l( x, i ); + fp_t old_h = ts_h( x, i - k ); + fp_t old_l = ts_l( x, i - k ); + + if ( new_h > hh ) hh = new_h; + if ( new_l < ll ) ll = new_l; + if ( old_h == hh || old_l == ll ) + { + hh = ts_h( x, i - k + 1 ); + ll = ts_l( x, i - k + 1 ); + for( uint_t j = i - k + 2; j <= i; ++j ) + { + if( ts_h( x, j ) > hh ) hh = ts_h( x, j ); + if( ts_l( x, j ) < ll ) ll = ts_l( x, j ); + } + } + + fp_t k_val = ( hh - ll ) == 0 ? 0 : 100.0 * ( ts_c( x, i ) - ll ) / ( hh - ll ); + y[0][i] = k_val; + + if (i >= k + 1) + { + fp_t d_sum = 0; + for( uint_t j = 0; j < 3; ++j ) + d_sum += y[0][i - j]; + y[1][i] = d_sum / 3.0; + } + else + { + y[1][i] = 0; + } + } + + return 0; +} + 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; +} + diff --git a/lib/stochastic_slow.c b/lib/stochastic_slow.c new file mode 100644 index 0000000..0f84e1a --- /dev/null +++ b/lib/stochastic_slow.c @@ -0,0 +1,91 @@ +// Stochastic Slow +// +// stochastic_slow +// +// Stochastic Slow %K, %D +// +// +// +// Inputs: 4 +// Outputs: 2 +// Constants: 1 + + +#include <stdlib.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_stochastic_slow_params_t; + +ts_parameter_t const ts_stochastic_slow_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_stochastic_slow_params_t) }; + +uint_t ts_stochastic_slow_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_stochastic_slow_params_t *)c)->k > 0 ? 3 * ((ts_stochastic_slow_params_t *)c)->k - 3 : 0 : 0 ); +} + +int ts_stochastic_slow( + 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_slow_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_stochastic_slow_params_t *)c)->k; + if (k == 0) return -1; + + fp_t *fast_k = calloc( k, sizeof( fp_t ) ); + if( !fast_k ) return -1; + + for( uint_t i = 0; i < n; ++i ) + { + if( i < k - 1 ) + { + fast_k[i % k] = 0; + continue; + } + + fp_t hh = ts_h( x, i ); + fp_t ll = ts_l( x, i ); + + for( uint_t j = 1; j < k; ++j ) + { + if( ts_h( x, i - j ) > hh ) + hh = ts_h( x, i - j ); + if( ts_l( x, i - j ) < ll ) + ll = ts_l( x, i - j ); + } + + fast_k[i % k] = ( hh - ll ) == 0 ? 0 : 100.0 * ( ts_c( x, i ) - ll ) / ( hh - ll ); + } + + for (uint_t j = 0; j < n && j < 3 * k - 3; ++j) { y[0][j] = 0; y[1][j] = 0; } + for( uint_t i = 3 * k - 3; i < n; ++i ) + { + fp_t slow_k_sum = 0; + for( uint_t j = 0; j < k; ++j ) + slow_k_sum += fast_k[(i - j) % k]; + fp_t slow_k = slow_k_sum / k; + + fp_t slow_d_sum = 0; + for( uint_t j = 0; j < k; ++j ) + { + fp_t sk_sum = 0; + for( uint_t jj = 0; jj < k; ++jj ) + sk_sum += fast_k[(i - j - jj) % k]; + slow_d_sum += sk_sum / k; + } + fp_t slow_d = slow_d_sum / k; + + y[0][i] = slow_k; + y[1][i] = slow_d; + } + + free( fast_k ); + return 0; +} + diff --git a/lib/student_t_pdf.c b/lib/student_t_pdf.c new file mode 100644 index 0000000..67c9f1d --- /dev/null +++ b/lib/student_t_pdf.c @@ -0,0 +1,51 @@ +// Student T Pdf +// +// student_t_pdf +// +// Student's t probability density +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + fp_t nu; +} ts_student_t_pdf_params_t; + +ts_parameter_t const ts_student_t_pdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_student_t_pdf_params_t) }; + +uint_t ts_student_t_pdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_student_t_pdf( + 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_student_t_pdf_p ); + if ( !c ) return -1; + fp_t nu = ((ts_student_t_pdf_params_t *)c)->nu; + if ( nu <= 0 ) + { + for( uint_t i = 0; i < n; ++i ) y[0][i] = 0; + return -1; + } + fp_t coeff = tgamma( ( nu + 1.0 ) / 2.0 ) / ( sqrt( nu * PI ) * tgamma( nu / 2.0 ) ); + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + y[0][i] = coeff * pow( 1.0 + xi * xi / nu, -( nu + 1.0 ) / 2.0 ); + } + return 0; +} + diff --git a/lib/subtraction.c b/lib/subtraction.c new file mode 100644 index 0000000..01fd208 --- /dev/null +++ b/lib/subtraction.c @@ -0,0 +1,39 @@ +// Subtraction +// +// subtraction - sub +// +// f( x_0, x_1 ) = x_0 - x_1 +// +// X_n - 2 +// Y_n - 1 +// C_n - 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_subtraction_p = { .n_inputs = 2, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_subtraction_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_subtraction( + 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_subtraction_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = x[0][i] - x[1][i]; + } + return 0; +} + diff --git a/lib/summation.c b/lib/summation.c new file mode 100755 index 0000000..6d0020b --- /dev/null +++ b/lib/summation.c @@ -0,0 +1,57 @@ +// Summation +// +// summation - sum +// +// Calculates the sum of the past k values +// +// y_i = sum_{j=i-k+1}^{i}[x_j] +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_summation_params_t; + +ts_parameter_t const ts_summation_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_summation_params_t) }; + + +uint_t ts_summation_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_summation_params_t *)c)->k > 0 ? ((ts_summation_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_summation( + 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_summation_p ); + if ( !c ) return -1; + uint_t k = ((ts_summation_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = 0; + uint_t yi = k; + + y[0][k - 1] = 0; + + for( ; xi < k; xi++ ) + { + y[0][k - 1] += x[0][xi]; + } + + for( ; xi < n; xi++, yi++ ) + { + y[0][yi] = x[0][xi] + y[0][yi - 1] - x[0][xi - k]; + } + return 0; +} + diff --git a/lib/supertrend.c b/lib/supertrend.c new file mode 100644 index 0000000..4487e96 --- /dev/null +++ b/lib/supertrend.c @@ -0,0 +1,118 @@ +// Supertrend +// +// supertrend +// +// SuperTrend Indicator +// +// +// +// Inputs: 4 +// Outputs: 2 +// Constants: 2 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; + fp_t mult; +} ts_supertrend_params_t; + +ts_parameter_t const ts_supertrend_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 2, .params_size = sizeof(ts_supertrend_params_t) }; + +uint_t ts_supertrend_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_supertrend_params_t *)c)->k : 0 ); +} + +int ts_supertrend( + 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_supertrend_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_supertrend_params_t *)c)->k; + fp_t mult = ((ts_supertrend_params_t *)c)->mult; + if (k == 0 || n <= k) return -1; + + fp_t tr = ts_h( x, 1 ) - ts_l( x, 1 ); + fp_t tr2 = fabs( ts_h( x, 1 ) - ts_c( x, 0 ) ); + fp_t tr3 = fabs( ts_l( x, 1 ) - ts_c( x, 0 ) ); + if( tr2 > tr ) tr = tr2; + if( tr3 > tr ) tr = tr3; + fp_t atr = tr; + + for( uint_t i = 2; i <= k; ++i ) + { + tr = ts_h( x, i ) - ts_l( x, i ); + tr2 = fabs( ts_h( x, i ) - ts_c( x, i - 1 ) ); + tr3 = fabs( ts_l( x, i ) - ts_c( x, i - 1 ) ); + if( tr2 > tr ) tr = tr2; + if( tr3 > tr ) tr = tr3; + atr = atr + (tr - atr) / k; + } + + fp_t median = ( ts_h( x, k ) + ts_l( x, k ) ) / 2.0; + fp_t raw_upper = median + mult * atr; + fp_t raw_lower = median - mult * atr; + + fp_t final_upper = raw_upper; + fp_t final_lower = raw_lower; + int_t trend = 1; + + if( ts_c( x, k ) > raw_lower ) + { + trend = 1; + } + else + { + trend = -1; + } + + y[0][k] = trend == 1 ? final_lower : final_upper; + y[1][k] = trend; + + for( uint_t i = k + 1; i < n; ++i ) + { + tr = ts_h( x, i ) - ts_l( x, i ); + tr2 = fabs( ts_h( x, i ) - ts_c( x, i - 1 ) ); + tr3 = fabs( ts_l( x, i ) - ts_c( x, i - 1 ) ); + if( tr2 > tr ) tr = tr2; + if( tr3 > tr ) tr = tr3; + atr = atr + (tr - atr) / k; + + median = ( ts_h( x, i ) + ts_l( x, i ) ) / 2.0; + raw_upper = median + mult * atr; + raw_lower = median - mult * atr; + + if( raw_upper < final_upper || ts_c( x, i - 1 ) > final_upper ) + final_upper = raw_upper; + + if( raw_lower > final_lower || ts_c( x, i - 1 ) < final_lower ) + final_lower = raw_lower; + + int_t new_trend = trend; + + if( trend == 1 ) + { + if( ts_c( x, i ) < final_lower ) + new_trend = -1; + } + else + { + if( ts_c( x, i ) > final_upper ) + new_trend = 1; + } + + trend = new_trend; + y[0][i] = trend == 1 ? final_lower : final_upper; + y[1][i] = trend; + } + return 0; +} + diff --git a/lib/swing_index.c b/lib/swing_index.c new file mode 100644 index 0000000..2f7c563 --- /dev/null +++ b/lib/swing_index.c @@ -0,0 +1,52 @@ +// Swing Index +// +// swing_index +// +// Swing Index +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_swing_index_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_swing_index_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 1 ); +} + +int ts_swing_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_swing_index_p ); + (void)c; + if (n > 0) y[0][0] = 0; + for( uint_t i = 1; i < n; ++i ) + { + fp_t a1 = ts_h( x, i ) - ts_h( x, i - 1 ); + fp_t a2 = ts_l( x, i - 1 ) - ts_l( x, i ); + fp_t a = fmax( a1, a2 ); + fp_t b = ts_c( x, i ) - ts_c( x, i - 1 ); + fp_t ldpl = ts_l( x, i ) - ts_l( x, i - 1 ); + fp_t phmh = ts_h( x, i - 1 ) - ts_h( x, i ); + fp_t c_val = 0; + if( b < 0 && ldpl > phmh ) c_val = ldpl; + else if( b >= 0 && phmh > ldpl ) c_val = phmh; + fp_t hl = ts_h( x, i ) - ts_l( x, i ); + fp_t swing = ( hl != 0 ) ? ( a * 2.0 + b - c_val ) * ts_v( x, i ) / hl : 0; + y[0][i] = ( i > 1 ? y[0][i - 1] : 0 ) + swing; + } + return 0; +} + diff --git a/lib/swish.c b/lib/swish.c new file mode 100644 index 0000000..7d09787 --- /dev/null +++ b/lib/swish.c @@ -0,0 +1,41 @@ +// Swish +// +// swish - Swish (Silu) activation +// +// y[t] = x[t] / ( 1 + exp( -x[t] ) ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_swish_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_swish_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_swish( + 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_swish_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + y[0][i] = xi / ( 1 + exp( -xi ) ); + } + return 0; +} + diff --git a/lib/synthetic_yield.c b/lib/synthetic_yield.c new file mode 100644 index 0000000..c2c8d62 --- /dev/null +++ b/lib/synthetic_yield.c @@ -0,0 +1,47 @@ +// Synthetic Yield +// +// synthetic_yield +// +// Synthetic Yield +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_synthetic_yield_params_t; + +ts_parameter_t const ts_synthetic_yield_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_synthetic_yield_params_t) }; + +uint_t ts_synthetic_yield_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_synthetic_yield_params_t *)c)->k : 0 ); +} + +int ts_synthetic_yield( + 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_synthetic_yield_p ); + if ( !c ) return -1; + uint_t k = ((ts_synthetic_yield_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k; i < n; ++i ) + { + if( x[0][i - k] == 0 ) { y[0][i] = 0; continue; } + y[0][i] = ( x[0][i] - x[0][i - k] ) / x[0][i - k] * 252.0 / k * 100.0; + } + return 0; +} + diff --git a/lib/t3.c b/lib/t3.c new file mode 100644 index 0000000..4689d54 --- /dev/null +++ b/lib/t3.c @@ -0,0 +1,66 @@ +// T3 +// +// t3 +// +// T3 Moving Average +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + +ts_parameter_t const ts_t3_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_t3_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_t3( + 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_t3_p ); + (void)c; + if (n == 0) return -1; + + uint_t k = 5; + + fp_t b = 0.7; + + fp_t alpha = 2.0 / ( (fp_t)k + 1.0 ); + + fp_t c3 = b; + fp_t c3m1 = c3 - 1.0; + fp_t c3m2 = c3 - 2.0; + fp_t c3m3 = c3 - 3.0; + + fp_t w3 = c3; + fp_t w2 = -3.0 * c3m1; + fp_t w1 = 3.0 * c3m1 * c3m2; + fp_t w0 = -c3m1 * c3m2 * c3m3; + + fp_t ema1 = x[0][0]; + fp_t ema2 = x[0][0]; + fp_t ema3 = x[0][0]; + + y[0][0] = x[0][0]; + + for( uint_t i = 1; i < n; ++i ) + { + ema1 = ema1 + alpha * ( x[0][i] - ema1 ); + ema2 = ema2 + alpha * ( ema1 - ema2 ); + ema3 = ema3 + alpha * ( ema2 - ema3 ); + + y[0][i] = w3 * ema3 + w2 * ema2 + w1 * ema1 + w0 * x[0][i]; + } + return 0; +} + diff --git a/lib/tangent.c b/lib/tangent.c new file mode 100644 index 0000000..407ea6b --- /dev/null +++ b/lib/tangent.c @@ -0,0 +1,40 @@ +// Tangent +// +// tangent - tan +// +// f( x ) = tan( x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_tangent_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_tangent_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_tangent( + 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_tangent_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = tan( x[0][i] ); + } + return 0; +} + diff --git a/lib/tangent_hyperbolic.c b/lib/tangent_hyperbolic.c new file mode 100644 index 0000000..7a76c82 --- /dev/null +++ b/lib/tangent_hyperbolic.c @@ -0,0 +1,41 @@ +// Hyperbolic Tangent +// +// tangent_hyperbolic - tanh +// +// f( x ) = tanh( x ) +// = sinh( x ) / cosh( x ) +// = ( e^2x - 1 ) / ( e^2x + 1 ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_tangent_hyperbolic_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_tangent_hyperbolic_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_tangent_hyperbolic( + 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_tangent_hyperbolic_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = tanh( x[0][i] ); + } + return 0; +} + diff --git a/lib/tangent_hyperbolic_inverse.c b/lib/tangent_hyperbolic_inverse.c new file mode 100644 index 0000000..1c337ba --- /dev/null +++ b/lib/tangent_hyperbolic_inverse.c @@ -0,0 +1,43 @@ +// Inverse Hyperbolic Tangent +// +// tangent_hyperbolic_inverse - atanh +// +// f( x ) = atanh( x ) +// = 0.5 * ln( ( 1 + x ) / ( 1 - x ) ) |x| < 1 +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_tangent_hyperbolic_inverse_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_tangent_hyperbolic_inverse_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_tangent_hyperbolic_inverse( + 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_tangent_hyperbolic_inverse_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xv = x[0][i]; + if( fabs(xv) >= 1.0 ) { y[0][i] = 0; continue; } + y[0][i] = atanh( xv ); + } + return 0; +} + diff --git a/lib/tangent_inverse.c b/lib/tangent_inverse.c new file mode 100644 index 0000000..69b67b7 --- /dev/null +++ b/lib/tangent_inverse.c @@ -0,0 +1,40 @@ +// Inverse Tangent +// +// tangent_inverse - atan +// +// f( x ) = atan( x ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_tangent_inverse_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_tangent_inverse_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_tangent_inverse( + 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_tangent_inverse_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = atan( x[0][i] ); + } + return 0; +} + diff --git a/lib/tanhshrink.c b/lib/tanhshrink.c new file mode 100644 index 0000000..c48ab85 --- /dev/null +++ b/lib/tanhshrink.c @@ -0,0 +1,41 @@ +// Tanhshrink +// +// tanhshrink - Tanhshrink activation +// +// y[t] = x[t] - tanh( x[t] ) +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_tanhshrink_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_tanhshrink_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_tanhshrink( + 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_tanhshrink_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + y[0][i] = xi - tanh( xi ); + } + return 0; +} + diff --git a/lib/test.c b/lib/test.c new file mode 100755 index 0000000..56c47eb --- /dev/null +++ b/lib/test.c @@ -0,0 +1,77 @@ +#include <assert.h> +#include <math.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include "ts.h" + + +void _ts_assert_approximate( fp_t y0, fp_t y1, fp_t e ) +{ + assert( ( fabs( y0 - y1 ) <= e ) ); +} + + +bool _ts_is_approximate( fp_t y0, fp_t y1, fp_t e ) +{ + return ( fabs( y0 - y1 ) <= e ); +} + + +#define _ts_test_print( FUNCTION ) \ + \ + fputs( #FUNCTION, stdout ); \ + fputs( ": ", stdout ) + + +void ts_test_all( void ) +{ + ts_test_absolute_value(); + ts_test_addition(); + ts_test_ceiling(); + +} + +bool ts_test( + void ( *ts_function )( + fp_t * const *y, + fp_t const * const *x, + uint_t n, + ts_constant_t const *c + ), + uint_t ( *ts_offset )( + ts_constant_t const *c + ), + fp_t const * const *x, + fp_t const * const *e, + uint_t n, + ts_constant_t const *c, + ts_parameter_t const *m ) +{ + uint_t offset = ts_offset( c ); + uint_t y_n = n - offset; + bool result = true; + + fp_t *y[m->y]; + + for( uint_t i = 0; i < m->y; i++ ) + { + fp_t *tmp = malloc( y_n * sizeof( fp_t ) ); + y[i] = tmp; + } + + ts_function( y, x, n, c ); + + for( uint_t i = 0; i < m->y; ++i ) + { + for( uint_t j = 0; j < y_n; ++j ) + { + // _ts_assert_approximate( y[i][j], e[i][j], TS_TEST_EPSILON ); + result &= _ts_is_approximate( y[i][j], e[i][j], TS_TEST_EPSILON ); + } + + free( y[i] ); + } + + return result; +}
\ No newline at end of file diff --git a/lib/tgamma.c b/lib/tgamma.c new file mode 100644 index 0000000..967072e --- /dev/null +++ b/lib/tgamma.c @@ -0,0 +1,42 @@ +// Tgamma +// +// tgamma +// +// Gamma function +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_tgamma_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_tgamma_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_tgamma( + 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_tgamma_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xv = x[0][i]; + if( xv <= 0.0 ) { y[0][i] = 0; continue; } + y[0][i] = tgamma( xv ); + } + return 0; +} + diff --git a/lib/tick_volume.c b/lib/tick_volume.c new file mode 100644 index 0000000..9e28ec7 --- /dev/null +++ b/lib/tick_volume.c @@ -0,0 +1,41 @@ +// Tick Volume +// +// tick_volume +// +// Tick Volume +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_tick_volume_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_tick_volume_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_tick_volume( + 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_tick_volume_p ); + (void)c; + ( void ) x; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = 1; + } + + return 0; +} + diff --git a/lib/time_series_forecast.c b/lib/time_series_forecast.c new file mode 100644 index 0000000..bf8e7af --- /dev/null +++ b/lib/time_series_forecast.c @@ -0,0 +1,58 @@ +// Time Series Forecast +// +// time_series_forecast +// +// Time Series Forecast +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_time_series_forecast_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_time_series_forecast_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 4 ); +} + +int ts_time_series_forecast( + 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_time_series_forecast_p ); + (void)c; + for ( uint_t j = 0; j < n && j < 4; ++j ) y[0][j] = 0; + for ( uint_t i = 4; i < n; ++i ) + { + fp_t sum_x = 0, sum_y = 0, sum_xy = 0, sum_x2 = 0; + for ( uint_t j = 0; j < 5; ++j ) + { + fp_t xv = (fp_t)j; + fp_t yv = x[0][i - 4 + j]; + sum_x += xv; + sum_y += yv; + sum_xy += xv * yv; + sum_x2 += xv * xv; + } + fp_t denom = 5.0 * sum_x2 - sum_x * sum_x; + if (denom == 0) { + y[0][i] = sum_y / 5.0; + } else { + fp_t slope = (5.0 * sum_xy - sum_x * sum_y) / denom; + fp_t intercept = (sum_y - slope * sum_x) / 5.0; + y[0][i] = intercept + slope * 5.0; + } + } + return 0; +} + diff --git a/lib/trade_volume_index.c b/lib/trade_volume_index.c new file mode 100644 index 0000000..2e1b50d --- /dev/null +++ b/lib/trade_volume_index.c @@ -0,0 +1,43 @@ +// Trade Volume Index +// +// trade_volume_index +// +// Trade Volume Index +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_trade_volume_index_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_trade_volume_index_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_trade_volume_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_trade_volume_index_p ); + (void)c; + if (n < 2) return -1; + for( uint_t i = 0; i + 1 < n; ++i ) + { + fp_t roc = x[3][i] != 0 ? ( x[3][i + 1] - x[3][i] ) / x[3][i] : 0; + y[0][i] = ( i == 0 ? 0 : y[0][i - 1] ) + roc * x[4][i + 1]; + } + y[0][n - 1] = y[0][n - 2]; + return 0; + } + diff --git a/lib/trend_intensity_index.c b/lib/trend_intensity_index.c new file mode 100644 index 0000000..451e440 --- /dev/null +++ b/lib/trend_intensity_index.c @@ -0,0 +1,62 @@ +// Trend Intensity Index +// +// trend_intensity_index +// +// Trend Intensity Index +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_trend_intensity_index_params_t; + +ts_parameter_t const ts_trend_intensity_index_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_trend_intensity_index_params_t) }; + +uint_t ts_trend_intensity_index_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_trend_intensity_index_params_t *)c)->k > 0 ? ((ts_trend_intensity_index_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_trend_intensity_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_trend_intensity_index_p ); + if ( !c ) return -1; + uint_t k = ((ts_trend_intensity_index_params_t *)c)->k; + if ( k == 0 || n < k ) return -1; + + fp_t signed_sum = 0; + fp_t vol_sum = 0; + + for ( uint_t i = 1; i <= k; ++i ) + { + signed_sum += ( ts_c( x, i ) > ts_c( x, i - 1 ) ) ? ts_v( x, i ) : -ts_v( x, i ); + vol_sum += ts_v( x, i ); + } + + y[0][k - 1] = vol_sum != 0 ? signed_sum / vol_sum : 0; + + for ( uint_t i = k + 1; i < n; ++i ) + { + fp_t cur_signed = ( ts_c( x, i ) > ts_c( x, i - 1 ) ) ? ts_v( x, i ) : -ts_v( x, i ); + fp_t old_signed = ( ts_c( x, i - k ) > ts_c( x, i - k - 1 ) ) ? ts_v( x, i - k ) : -ts_v( x, i - k ); + + signed_sum = signed_sum - old_signed + cur_signed; + vol_sum = vol_sum - ts_v( x, i - k ) + ts_v( x, i ); + + y[0][i] = vol_sum != 0 ? signed_sum / vol_sum : 0; + } + return 0; +} + diff --git a/lib/trix.c b/lib/trix.c new file mode 100755 index 0000000..a9aac88 --- /dev/null +++ b/lib/trix.c @@ -0,0 +1,61 @@ +// Trix +// +// trix - trix +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + + +typedef struct { + fp_t a; +} ts_trix_params_t; + +ts_parameter_t const ts_trix_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_trix_params_t) }; + + +uint_t ts_trix_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_trix( + 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_trix_p ); + if ( !c ) return -1; + if (n == 0) return -1; + + fp_t a = ((ts_trix_params_t *)c)->a; + if (a == 0) return -1; + + fp_t ema1 = x[0][0]; + fp_t ema2 = x[0][0]; + fp_t ema30 = x[0][0]; + fp_t ema31; + + y[0][0] = x[0][0]; + + for( uint_t i = 1; i < n; ++i ) + { + ema1 = ema1 + a * ( x[0][i] - ema1 ); + ema2 = ema2 + a * ( ema1 - ema2 ); + ema31 = ema30 + a * ( ema2 - ema30 ); + + if (ema30 == 0) + y[0][i] = 0; + else + y[0][i] = ( ema31 - ema30 ) / ema30; + + ema30 = ema31; + } + return 0; +} + diff --git a/lib/true_range.c b/lib/true_range.c new file mode 100644 index 0000000..ff1740e --- /dev/null +++ b/lib/true_range.c @@ -0,0 +1,45 @@ +// True Range +// +// true_range +// +// True Range +// +// +// +// Inputs: 4 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_true_range_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(uint_t) }; + + +uint_t ts_true_range_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 1 ); +} + +int ts_true_range( + 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_true_range_p ); + (void)c; + if (n > 0) y[0][0] = 0; + for( uint_t i = 1; i < n; ++i ) + { + y[0][i] = fmax( ( ts_h( x, i ) - ts_l( x, i ) ), + fmax( fabs( ts_h( x, i ) - ts_c( x, i - 1 ) ), + fabs( ts_l( x, i ) - ts_c( x, i - 1 ) ) ) ); + } + return 0; +} + diff --git a/lib/truncate.c b/lib/truncate.c new file mode 100644 index 0000000..0b83feb --- /dev/null +++ b/lib/truncate.c @@ -0,0 +1,40 @@ +// Truncate +// +// truncate - trunc +// +// f( x ) = [ x ] +// +// X_n - 1 +// Y_n - 1 +// C_n - 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_truncate_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_truncate_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_truncate( + 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_truncate_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = trunc( x[0][i] ); + } + return 0; +} + diff --git a/lib/ts.c b/lib/ts.c new file mode 100755 index 0000000..68e2f41 --- /dev/null +++ b/lib/ts.c @@ -0,0 +1,119 @@ +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include "ts.h" + + +fp_t * ts_fill( fp_t *x, uint_t n, fp_t x0, fp_t x1 ) +{ + fp_t step = ( x1 - x0 ) / ( n - 1 ); + + if( x0 == 0.0 && x1 == 0.0 ) + { + memset(x, 0, sizeof( fp_t ) * n ); + } + + else + { + for( uint_t i = 0; i < n; i++ ) + { + x[i] = x0 + ( i * step ); + } + } + + return x; +} + + +void ts_print( fp_t *x, uint_t n ) +{ + fputc('[', stdout); + + uint_t i; + for( i = 0; i < n - 1; i++ ) + { + fprintf(stdout, "%f,", x[i]); + } + + fprintf(stdout, "%f]", x[i]); +} + + +void ts_pretty_print( fp_t const * const *x, uint_t m, uint_t n ) +{ + if( m > 1 ) + { + for( uint_t i = 0; i < n; i++ ) + { + uint_t j = 0; + for( ; j < m; j++ ) + { + fprintf( stdout, "%f ", x[i][j] ); + } + + fputs( "\n", stdout ); + } + } + else + { + for( uint_t i = 0; i < n; i++ ) + { + fprintf( stdout, "%f\n", x[0][i] ); + } + } +} + + +fp_t _ts_square( fp_t x ) +{ + return x * x; +} + + +fp_t _ts_reciprocal( fp_t x ) +{ + return x != 0 ? 1.0 / x : INFINITY; +} + + +fp_t _ts_square_pyramidal_number( fp_t x ) +{ + return ( x * ( x + 1 ) * ( 2 * x + 1 ) ) / 6; +} + + +fp_t _ts_triangle_number( fp_t x ) +{ + return ( ( x ) * ( ( x ) + 1 ) ) * 0.5; +} + + +fp_t _ts_sum_to_covariance( fp_t sum_xy, fp_t sum_x, fp_t sum_y, uint_t k ) +{ + return ( sum_xy - ( sum_x * sum_y / k ) ) / k; +} + + +fp_t _ts_sum_to_variance( fp_t sum_x2, fp_t sum_x, uint_t k ) +{ + return _ts_sum_to_covariance( sum_x2, sum_x, sum_x, k ); +} + + +uint_t _ts_circle_increment( uint_t i, uint_t k ) +{ + return ( i + 1 ) % k; +} + + +// ts_constant_t * ts_constant_init( uint_t n, ... ) +// { +// va_list args; +// va_start( args, n ); + +// for( uint_t i = 0; i < n; i++ ) +// { + +// } +// }
\ No newline at end of file diff --git a/lib/twiggs_money_flow.c b/lib/twiggs_money_flow.c new file mode 100644 index 0000000..334f968 --- /dev/null +++ b/lib/twiggs_money_flow.c @@ -0,0 +1,67 @@ +// Twiggs Money Flow +// +// twiggs_money_flow +// +// Twiggs Money Flow +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_twiggs_money_flow_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_twiggs_money_flow_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 35 ); +} + +int ts_twiggs_money_flow( + 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_twiggs_money_flow_p ); + (void)c; + if (n < 2) return -1; + + uint_t period = n - 2; + + fp_t pos_sum = 0; + fp_t neg_sum = 0; + + for( uint_t j = 0; j < period; ++j ) y[0][j] = 0; + for( uint_t i = 1; i <= period; ++i ) + { + fp_t change = x[0][i] - x[0][i - 1]; + if( change >= 0 ) pos_sum += change; + else neg_sum += fabs( change ); + } + + fp_t total = pos_sum + neg_sum; + y[0][period] = ( total != 0 ) ? ( pos_sum - neg_sum ) / total * 100.0 : 0; + + for( uint_t j = 1; j < n - period; ++j ) + { + fp_t new_change = x[0][period + j] - x[0][period + j - 1]; + fp_t old_change = x[0][j] - x[0][j - 1]; + + if( new_change >= 0 ) pos_sum += new_change; + else neg_sum += fabs( new_change ); + if( old_change >= 0 ) pos_sum -= old_change; + else neg_sum -= fabs( old_change ); + + total = pos_sum + neg_sum; + y[0][period + j] = ( total != 0 ) ? ( pos_sum - neg_sum ) / total * 100.0 : 0; + } + return 0; +} + diff --git a/lib/typical_price.c b/lib/typical_price.c new file mode 100644 index 0000000..2d7f1c6 --- /dev/null +++ b/lib/typical_price.c @@ -0,0 +1,41 @@ +// Typical Price +// +// typical_price +// +// Typical Price +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + + +ts_parameter_t const ts_typical_price_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_typical_price_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_typical_price( + 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_typical_price_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = ( x[1][i] + x[2][i] + x[3][i] ) / 3; + } + return 0; +} + diff --git a/lib/ulcer_index.c b/lib/ulcer_index.c new file mode 100644 index 0000000..ca70734 --- /dev/null +++ b/lib/ulcer_index.c @@ -0,0 +1,76 @@ +// Ulcer Index +// +// ulcer_index +// +// Ulcer Index +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include <stdlib.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_ulcer_index_params_t; + +ts_parameter_t const ts_ulcer_index_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_ulcer_index_params_t) }; + +uint_t ts_ulcer_index_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_ulcer_index_params_t *)c)->k > 0 ? ((ts_ulcer_index_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_ulcer_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_ulcer_index_p ); + if ( !c ) return -1; + uint_t k = ((ts_ulcer_index_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + /* Precompute cumulative highest-high for each index: O(n) */ + fp_t *cum_hhv = calloc( n, sizeof( fp_t ) ); + if ( !cum_hhv ) return -1; + { + fp_t hh = x[0][0]; + for ( uint_t i = 0; i < n; ++i ) + { + if ( x[0][i] > hh ) hh = x[0][i]; + cum_hhv[i] = hh; + } + } + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t hhv = x[0][i - k + 1]; + for( uint_t j = 1; j < k; ++j ) + { + fp_t v = x[0][i - k + 1 + j]; + if (v > hhv) hhv = v; + } + + fp_t d_sq_sum = 0; + for( uint_t j = 0; j < k; ++j ) + { + uint_t idx = i - k + 1 + j; + fp_t ch = cum_hhv[idx]; + fp_t d = ch > 0 ? ( ch - x[0][idx] ) / ch * 100.0 : 0; + d_sq_sum += d * d; + } + y[0][i] = sqrt( d_sq_sum / (fp_t)k ); + } + + free( cum_hhv ); + return 0; +} + diff --git a/lib/ultimate_oscillator.c b/lib/ultimate_oscillator.c new file mode 100644 index 0000000..aec2ef4 --- /dev/null +++ b/lib/ultimate_oscillator.c @@ -0,0 +1,88 @@ +// Ultimate Oscillator +// +// ultimate_oscillator +// +// Ultimate Oscillator +// +// +// +// Inputs: 4 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + +ts_parameter_t const ts_ultimate_oscillator_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_ultimate_oscillator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 54 ); +} + +int ts_ultimate_oscillator( + 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_ultimate_oscillator_p ); + (void)c; + for( uint_t i = 54; i < n; ++i ) + { + fp_t bp7 = 0, tr7 = 0; + fp_t bp14 = 0, tr14 = 0; + fp_t bp28 = 0, tr28 = 0; + + for( uint_t j = 0; j < 7; ++j ) + { + uint_t idx = i - 6 + j; + fp_t ll = ts_l( x, idx ); + fp_t hh = ts_h( x, idx ); + for( uint_t k = 1; k < 7; ++k ) + { + ll = fmin( ll, ts_l( x, idx - k ) ); + hh = fmax( hh, ts_h( x, idx - k ) ); + } + bp7 += ts_c( x, idx ) - ll; + tr7 += hh - ll; + } + + for( uint_t j = 0; j < 14; ++j ) + { + uint_t idx = i - 13 + j; + fp_t ll = ts_l( x, idx ); + fp_t hh = ts_h( x, idx ); + for( uint_t k = 1; k < 14; ++k ) + { + ll = fmin( ll, ts_l( x, idx - k ) ); + hh = fmax( hh, ts_h( x, idx - k ) ); + } + bp14 += ts_c( x, idx ) - ll; + tr14 += hh - ll; + } + + for( uint_t j = 0; j < 28; ++j ) + { + uint_t idx = i - 27 + j; + fp_t ll = ts_l( x, idx ); + fp_t hh = ts_h( x, idx ); + for( uint_t k = 1; k < 28; ++k ) + { + ll = fmin( ll, ts_l( x, idx - k ) ); + hh = fmax( hh, ts_h( x, idx - k ) ); + } + bp28 += ts_c( x, idx ) - ll; + tr28 += hh - ll; + } + + fp_t denom = 7.0 * tr7 + 3.0 * tr14 + tr28; + fp_t numer = 7.0 * bp7 + 3.0 * bp14 + bp28; + y[0][i] = denom != 0 ? 100.0 * numer / denom : 50.0; + } + return 0; +} + diff --git a/lib/valuation_lines.c b/lib/valuation_lines.c new file mode 100644 index 0000000..b56a871 --- /dev/null +++ b/lib/valuation_lines.c @@ -0,0 +1,62 @@ +// Valuation Lines +// +// valuation_lines +// +// Valuation Lines +// +// +// +// Inputs: 4 +// Outputs: 2 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_valuation_lines_params_t; + +ts_parameter_t const ts_valuation_lines_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_valuation_lines_params_t) }; + +uint_t ts_valuation_lines_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_valuation_lines_params_t *)c)->k > 0 ? ((ts_valuation_lines_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_valuation_lines( + 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_valuation_lines_p ); + if ( !c ) return -1; + uint_t k = ((ts_valuation_lines_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k - 1; i < n; ++i ) + { + fp_t min_val = ts_l( x, i ); + for( uint_t j = 1; j < k; ++j ) + { + fp_t val = ts_l( x, i - j ); + if( val < min_val ) + min_val = val; + } + y[0][i] = min_val; + + fp_t max_val = ts_h( x, i ); + for( uint_t j = 1; j < k; ++j ) + { + fp_t val = ts_h( x, i - j ); + if( val > max_val ) + max_val = val; + } + y[1][i] = max_val; + } + return 0; +} + diff --git a/lib/variable_index_dynamic_average.c b/lib/variable_index_dynamic_average.c new file mode 100644 index 0000000..5f4ae4f --- /dev/null +++ b/lib/variable_index_dynamic_average.c @@ -0,0 +1,65 @@ +// Variable Index Dynamic Average +// +// variable_index_dynamic_average +// +// Variable Index Dynamic Average +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t period; +} ts_variable_index_dynamic_average_params_t; + +ts_parameter_t const ts_variable_index_dynamic_average_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_variable_index_dynamic_average_params_t) }; + +uint_t ts_variable_index_dynamic_average_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_variable_index_dynamic_average_params_t *)c)->period : 0 ); +} + +int ts_variable_index_dynamic_average( + 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_variable_index_dynamic_average_p ); + if ( !c ) return -1; + uint_t period = ((ts_variable_index_dynamic_average_params_t *)c)->period; + if (period < 2 || n <= period) return -1; + + fp_t vidya = x[0][period]; + y[0][period] = vidya; + + fp_t alpha_init = (fp_t)(period - 2) / (2.0 * (fp_t)(period - 1)); + fp_t alpha = alpha_init; + + for( uint_t i = period + 1; i < n; ++i ) + { + vidya = vidya + alpha * (x[0][i] - vidya); + y[0][i] = vidya; + + fp_t numerator = fabs( x[0][i] - x[0][i - period] ); + fp_t denominator = 0; + for( uint_t j = i - period + 1; j <= i; ++j ) + denominator += fabs( x[0][j] - x[0][j - 1] ); + fp_t er = (denominator == 0) ? 0 : numerator / denominator; + + fp_t alpha_new = er * er * 2.0 / (fp_t)(period + 1); + if( alpha_new < 0 ) alpha_new = 0; + if( alpha_new > 1 ) alpha_new = 1; + + alpha = (alpha + alpha_new) / 2.0; + } + return 0; +} + diff --git a/lib/variance.c b/lib/variance.c new file mode 100755 index 0000000..f307198 --- /dev/null +++ b/lib/variance.c @@ -0,0 +1,72 @@ +// Variance +// +// variance - smv +// +// Calculates the moving variance +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +typedef struct { + uint_t k; +} ts_variance_params_t; + +ts_parameter_t const ts_variance_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_variance_params_t) }; + + +uint_t ts_variance_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_variance_params_t *)c)->k > 0 ? ((ts_variance_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_variance( + 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_variance_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_variance_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t xi = 0; + uint_t yi = k; + + fp_t sum = 0; // Sum of terms + fp_t sum2 = 0; // Sum of squared terms + fp_t mean; // Mean + fp_t mean2; // Mean of squares + + for( ; xi < k; ++xi ) + { + sum += x[0][xi]; + sum2 += _ts_square( x[0][xi] ); + + mean = sum / ( xi + 1 ); + mean2 = sum2 / ( xi + 1 ); + } + + fp_t var = mean2 - _ts_square( mean ); + y[0][k - 1] = var >= 0 ? var : 0.0; + + fp_t rk = _ts_reciprocal( k ); + + for( ; xi < n; ++xi, ++yi ) + { + mean = mean + ( x[0][xi] - x[0][xi - k] ) * rk; + mean2 = mean2 + ( _ts_square( x[0][xi] ) - _ts_square( x[0][xi - k] ) ) * rk; + + var = mean2 - _ts_square( mean ); + y[0][yi] = var >= 0 ? var : 0.0; + } + return 0; +} + diff --git a/lib/variance_exponential.c b/lib/variance_exponential.c new file mode 100755 index 0000000..338a140 --- /dev/null +++ b/lib/variance_exponential.c @@ -0,0 +1,51 @@ +// Exponential Variance +// +// variance_exponential +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + +#include "ts.h" + + +typedef struct { + fp_t a; +} ts_variance_exponential_params_t; + +ts_parameter_t const ts_variance_exponential_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_variance_exponential_params_t) }; + + +uint_t ts_variance_exponential_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_variance_exponential( + 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_variance_exponential_p ); + if ( !c ) return -1; + if (n == 0) return -1; + + fp_t a = ((ts_variance_exponential_params_t *)c)->a; + if (a == 0) return -1; + + y[0][0] = 0; + + fp_t delta; + fp_t ema = x[0][0]; + + for( uint_t i = 1; i < n; ++i ) + { + delta = x[0][i] - ema; + ema = ema + a * delta; + y[0][i] = ( 1 - a ) * ( y[0][i - 1] + a * _ts_square( delta ) ); + } + return 0; +} + diff --git a/lib/vertical_horizontal_filter.c b/lib/vertical_horizontal_filter.c new file mode 100644 index 0000000..f5c91cf --- /dev/null +++ b/lib/vertical_horizontal_filter.c @@ -0,0 +1,75 @@ +// Vertical Horizontal Filter +// +// vertical_horizontal_filter +// +// Vertical Horizontal Filter +// +// +// +// Inputs: 4 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_vertical_horizontal_filter_params_t; + +ts_parameter_t const ts_vertical_horizontal_filter_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_vertical_horizontal_filter_params_t) }; + +uint_t ts_vertical_horizontal_filter_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_vertical_horizontal_filter_params_t *)c)->k : 0 ); +} + +int ts_vertical_horizontal_filter( + 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_vertical_horizontal_filter_p ); + if ( !c ) return -1; + uint_t k = ((ts_vertical_horizontal_filter_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t cum_den = 0; + + for ( uint_t j = 1; j <= k; ++j ) + { + cum_den += fabs( ts_h( x, j ) - ts_h( x, j - 1 ) ) + + fabs( ts_l( x, j ) - ts_l( x, j - 1 ) ); + } + + for ( uint_t i = k; i < n; ++i ) + { + if ( i > k ) + { + cum_den += fabs( ts_h( x, i ) - ts_h( x, i - 1 ) ) + + fabs( ts_l( x, i ) - ts_l( x, i - 1 ) ); + cum_den -= fabs( ts_h( x, i - k ) - ts_h( x, i - k - 1 ) ) + + fabs( ts_l( x, i - k ) - ts_l( x, i - k - 1 ) ); + } + + fp_t hh = ts_h( x, i - k + 1 ); + fp_t ll = ts_l( x, i - k + 1 ); + for ( uint_t j = i - k + 2; j <= i; ++j ) + { + if ( ts_h( x, j ) > hh ) hh = ts_h( x, j ); + if ( ts_l( x, j ) < ll ) ll = ts_l( x, j ); + } + + fp_t range = hh - ll; + + if ( cum_den == 0 ) + y[0][i] = ( range == 0 ) ? 1 : 0; + else + y[0][i] = range / cum_den; + } + return 0; +} + diff --git a/lib/volatility_stop.c b/lib/volatility_stop.c new file mode 100644 index 0000000..bfb207b --- /dev/null +++ b/lib/volatility_stop.c @@ -0,0 +1,74 @@ +// Volatility Stop +// +// volatility_stop +// +// Volatility Stop +// +// +// +// Inputs: 4 +// Outputs: 2 +// Constants: 2 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; + fp_t mult; +} ts_volatility_stop_params_t; + +ts_parameter_t const ts_volatility_stop_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 2, .params_size = sizeof(ts_volatility_stop_params_t) }; + +uint_t ts_volatility_stop_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_volatility_stop_params_t *)c)->k : 0 ); +} + +int ts_volatility_stop( + 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_volatility_stop_p ); + if ( !c ) return -1; + uint_t k = ((ts_volatility_stop_params_t *)c)->k; + fp_t mult = ((ts_volatility_stop_params_t *)c)->mult; + if (k == 0 || n < k) return -1; + + for( uint_t i = k; i < n; ++i ) + { + fp_t hh = ts_h(x, i - k); + fp_t ll = ts_l(x, i - k); + + for( uint_t j = i - k + 1; j <= i; ++j ) + { + if( ts_h(x, j) > hh ) hh = ts_h(x, j); + if( ts_l(x, j) < ll ) ll = ts_l(x, j); + } + + fp_t atr = 0; + for( uint_t j = i - k; j <= i; ++j ) + { + fp_t tr = ts_h(x, j) - ts_l(x, j); + if( j > 0 ) + { + fp_t prev_close = ts_c(x, j - 1); + fp_t tr2 = fabs(ts_h(x, j) - prev_close); + fp_t tr3 = fabs(ts_l(x, j) - prev_close); + if( tr2 > tr ) tr = tr2; + if( tr3 > tr ) tr = tr3; + } + atr += tr; + } + atr /= (k + 1); + + y[0][i] = hh - mult * atr; + y[1][i] = ll + mult * atr; + } + return 0; +} + diff --git a/lib/volatility_system.c b/lib/volatility_system.c new file mode 100644 index 0000000..dbb74d1 --- /dev/null +++ b/lib/volatility_system.c @@ -0,0 +1,55 @@ +// Volatility System +// +// volatility_system +// +// Volatility System +// +// +// +// Inputs: 4 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_volatility_system_params_t; + +ts_parameter_t const ts_volatility_system_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_volatility_system_params_t) }; + +uint_t ts_volatility_system_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? 2 * ((ts_volatility_system_params_t *)c)->k : 0 ); +} + +int ts_volatility_system( + 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_volatility_system_p ); + if ( !c ) return -1; + uint_t k = ((ts_volatility_system_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + uint_t range_period = 2 * k; + if (n < range_period) return -1; + + fp_t ema = (ts_c(x, range_period - 2) + ts_c(x, range_period - 1)) / 2.0; + + for( uint_t i = range_period; i < n; ++i ) + { + if( i == range_period ) + ema = (ts_c(x, i-1) + ts_c(x, i)) / 2.0; + else + ema = ema * 0.5 + ts_c(x, i) * 0.5; + y[0][i] = ema; + } + return 0; +} + diff --git a/lib/volume_delta.c b/lib/volume_delta.c new file mode 100644 index 0000000..cabd94a --- /dev/null +++ b/lib/volume_delta.c @@ -0,0 +1,60 @@ +// Volume Delta +// +// volume_delta +// +// Volume Delta +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_volume_delta_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_volume_delta_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_volume_delta( + 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_volume_delta_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t hl = x[1][i] - x[2][i]; + if( hl == 0 ) + { + y[0][i] = 0; + } + else if( x[3][i] > x[0][i] ) + { + fp_t buy_vol = x[4][i] * ( x[3][i] - x[2][i] ) / hl; + fp_t sell_vol = x[4][i] - buy_vol; + y[0][i] = buy_vol - sell_vol; + } + else if( x[3][i] < x[0][i] ) + { + fp_t sell_vol = x[4][i] * ( x[1][i] - x[3][i] ) / hl; + fp_t buy_vol = x[4][i] - sell_vol; + y[0][i] = buy_vol - sell_vol; + } + else + { + y[0][i] = 0; + } + } + + return 0; +} + diff --git a/lib/volume_moving_average.c b/lib/volume_moving_average.c new file mode 100644 index 0000000..93eb592 --- /dev/null +++ b/lib/volume_moving_average.c @@ -0,0 +1,48 @@ +// Volume Moving Average +// +// volume_moving_average +// +// Volume Moving Average +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_volume_moving_average_params_t; + +ts_parameter_t const ts_volume_moving_average_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_volume_moving_average_params_t) }; + +uint_t ts_volume_moving_average_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_volume_moving_average_params_t *)c)->k > 0 ? ((ts_volume_moving_average_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_volume_moving_average( + 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_volume_moving_average_p ); + if ( !c ) return -1; + uint_t k = ((ts_volume_moving_average_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for (uint_t i = k - 1; i < n; ++i) + { + fp_t sum = 0; + for (uint_t j = i - k + 1; j <= i; ++j) + sum += x[4][j]; + y[0][i] = sum / k; + } + return 0; +} + diff --git a/lib/volume_oscillator.c b/lib/volume_oscillator.c new file mode 100644 index 0000000..6aa59f0 --- /dev/null +++ b/lib/volume_oscillator.c @@ -0,0 +1,57 @@ +// Volume Oscillator +// +// volume_oscillator +// +// Volume Oscillator +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 2 + + +#include "ts.h" + +typedef struct { + fp_t fast_k; + fp_t slow_k; +} ts_volume_oscillator_params_t; + +ts_parameter_t const ts_volume_oscillator_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 2, .params_size = sizeof(ts_volume_oscillator_params_t) }; + +uint_t ts_volume_oscillator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_volume_oscillator_params_t *)c)->slow_k > 0 ? (uint_t)(((ts_volume_oscillator_params_t *)c)->slow_k - 1) : 0 : 0 ); +} + +int ts_volume_oscillator( + 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_volume_oscillator_p ); + if ( !c ) return -1; + fp_t fast_k = ((ts_volume_oscillator_params_t *)c)->fast_k; + fp_t slow_k = ((ts_volume_oscillator_params_t *)c)->slow_k; + if (fast_k == 0 || slow_k == 0) return -1; + if (n == 0) return -1; + + fp_t fast_a = 2.0 / (fast_k + 1); + fp_t slow_a = 2.0 / (slow_k + 1); + + fp_t fast_ema = x[0][0]; + fp_t slow_ema = x[0][0]; + y[0][0] = 0; + + for (uint_t i = 1; i < n; ++i) + { + fast_ema = fast_ema + fast_a * (x[0][i] - fast_ema); + slow_ema = slow_ema + slow_a * (x[0][i] - slow_ema); + y[0][i] = slow_ema != 0 ? (fast_ema - slow_ema) / slow_ema * 100 : 0; + } + return 0; +} + diff --git a/lib/volume_rate_of_change.c b/lib/volume_rate_of_change.c new file mode 100644 index 0000000..ae9c776 --- /dev/null +++ b/lib/volume_rate_of_change.c @@ -0,0 +1,46 @@ +// Volume Rate Of Change +// +// volume_rate_of_change +// +// Volume Rate of Change +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_volume_rate_of_change_params_t; + +ts_parameter_t const ts_volume_rate_of_change_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_volume_rate_of_change_params_t) }; + +uint_t ts_volume_rate_of_change_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_volume_rate_of_change_params_t *)c)->k : 0 ); +} + +int ts_volume_rate_of_change( + 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_volume_rate_of_change_p ); + if ( !c ) return -1; + uint_t k = ((ts_volume_rate_of_change_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for (uint_t i = k; i < n; ++i) + { + y[0][i] = x[4][i - k] != 0 ? (x[4][i] - x[4][i - k]) / x[4][i - k] * 100 : 0; + } + return 0; +} + diff --git a/lib/volume_underlay.c b/lib/volume_underlay.c new file mode 100644 index 0000000..030ba66 --- /dev/null +++ b/lib/volume_underlay.c @@ -0,0 +1,45 @@ +// Volume Underlay +// +// volume_underlay +// +// Volume Underlay +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + + +ts_parameter_t const ts_volume_underlay_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(uint_t) }; + +uint_t ts_volume_underlay_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_volume_underlay( + 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_volume_underlay_p ); + (void)c; + /* Volume Underlay: normalize volume to [0,1] */ + /* Find max volume */ + fp_t max_vol = 0; + for (uint_t i = 0; i < n; ++i) { + if (x[0][i] > max_vol) max_vol = x[0][i]; + } + + for (uint_t i = 0; i < n; ++i) { + y[0][i] = max_vol != 0 ? x[0][i] / max_vol : 0; + } + return 0; +} + diff --git a/lib/volume_weighted_moving_average.c b/lib/volume_weighted_moving_average.c new file mode 100644 index 0000000..d6cd6bd --- /dev/null +++ b/lib/volume_weighted_moving_average.c @@ -0,0 +1,58 @@ +// Volume Weighted Moving Average +// +// volume_weighted_moving_average +// +// Volume Weighted Moving Average +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_volume_weighted_moving_average_params_t; + +ts_parameter_t const ts_volume_weighted_moving_average_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_volume_weighted_moving_average_params_t) }; + +uint_t ts_volume_weighted_moving_average_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_volume_weighted_moving_average_params_t *)c)->k > 0 ? ((ts_volume_weighted_moving_average_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_volume_weighted_moving_average( + 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_volume_weighted_moving_average_p ); + if ( !c ) return -1; + uint_t k = ((ts_volume_weighted_moving_average_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + fp_t cv_sum = 0; + fp_t v_sum = 0; + + for( uint_t j = 0; j < k; ++j ) + { + cv_sum += ts_c(x, j) * ts_v(x, j); + v_sum += ts_v(x, j); + } + + y[0][k - 1] = (v_sum != 0) ? cv_sum / v_sum : 0; + + for( uint_t i = k; i < n; ++i ) + { + cv_sum += ts_c(x, i) * ts_v(x, i) - ts_c(x, i - k) * ts_v(x, i - k); + v_sum += ts_v(x, i) - ts_v(x, i - k); + y[0][i] = (v_sum != 0) ? cv_sum / v_sum : 0; + } + return 0; +} + diff --git a/lib/vortex_indicator.c b/lib/vortex_indicator.c new file mode 100644 index 0000000..39ecfbc --- /dev/null +++ b/lib/vortex_indicator.c @@ -0,0 +1,64 @@ +// Vortex Indicator +// +// vortex_indicator +// +// Vortex Indicator +// +// +// +// Inputs: 4 +// Outputs: 2 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + uint_t k; +} ts_vortex_indicator_params_t; + +ts_parameter_t const ts_vortex_indicator_p = { .n_inputs = 4, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_vortex_indicator_params_t) }; + +uint_t ts_vortex_indicator_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_vortex_indicator_params_t *)c)->k : 0 ); +} + +int ts_vortex_indicator( + 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_vortex_indicator_p ); + if ( !c ) return -1; + uint_t k = ((ts_vortex_indicator_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + for( uint_t i = k; i < n; ++i ) + { + fp_t sum_vm_plus = 0; + fp_t sum_vm_minus = 0; + fp_t sum_tr = 0; + + for( uint_t j = 0; j < k; ++j ) + { + uint_t idx = i - k + 1 + j; + fp_t vm_plus = fabs( ts_h( x, idx ) - ts_l( x, idx - 1 ) ); + fp_t vm_minus = fabs( ts_l( x, idx ) - ts_h( x, idx - 1 ) ); + fp_t tr = fmax( ts_h( x, idx ) - ts_l( x, idx ), + fmax( fabs( ts_h( x, idx ) - ts_c( x, idx - 1 ) ), + fabs( ts_l( x, idx ) - ts_c( x, idx - 1 ) ) ) ); + sum_vm_plus += vm_plus; + sum_vm_minus += vm_minus; + sum_tr += tr; + } + + y[0][i] = sum_tr != 0 ? sum_vm_plus / sum_tr : 0; + y[1][i] = sum_tr != 0 ? sum_vm_minus / sum_tr : 0; + } + return 0; +} + diff --git a/lib/vwap.c b/lib/vwap.c new file mode 100644 index 0000000..50308c7 --- /dev/null +++ b/lib/vwap.c @@ -0,0 +1,44 @@ +// Vwap +// +// vwap +// +// Volume Weighted Average Price +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_vwap_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_vwap_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_vwap( + 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_vwap_p ); + (void)c; + fp_t cum_pv = 0; + fp_t cum_v = 0; + + for( uint_t i = 0; i < n; ++i ) + { + cum_pv += ts_c( x, i ) * ts_v( x, i ); + cum_v += ts_v( x, i ); + y[0][i] = cum_v != 0 ? cum_pv / cum_v : 0; + } + return 0; +} + diff --git a/lib/vwap_period.c b/lib/vwap_period.c new file mode 100644 index 0000000..b8af2bd --- /dev/null +++ b/lib/vwap_period.c @@ -0,0 +1,58 @@ +// Vwap Period +// +// vwap_period +// +// Period VWAP +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_vwap_period_params_t; + +ts_parameter_t const ts_vwap_period_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_vwap_period_params_t) }; + +uint_t ts_vwap_period_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_vwap_period_params_t *)c)->k > 0 ? ((ts_vwap_period_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_vwap_period( + 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_vwap_period_p ); + if ( !c ) return -1; + uint_t k = ((ts_vwap_period_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + /* Periodic VWAP: reset cumulative sums every k bars */ + fp_t sum_pv = 0; + fp_t sum_vol = 0; + + for (uint_t i = 0; i < n; ++i) + { + sum_pv += ts_c( x, i ) * ts_v( x, i ); + sum_vol += ts_v( x, i ); + + y[0][i] = sum_vol != 0 ? sum_pv / sum_vol : 0; + + if ((i + 1) % k == 0 || i == n - 1) + { + sum_pv = 0; + sum_vol = 0; + } + } + return 0; +} + diff --git a/lib/weibull_pdf.c b/lib/weibull_pdf.c new file mode 100644 index 0000000..894c94a --- /dev/null +++ b/lib/weibull_pdf.c @@ -0,0 +1,46 @@ +// Weibull Pdf +// +// weibull_pdf +// +// Weibull probability density +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include <math.h> +#include "ts.h" + +typedef struct { + fp_t k; +} ts_weibull_pdf_params_t; + +ts_parameter_t const ts_weibull_pdf_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_weibull_pdf_params_t) }; + +uint_t ts_weibull_pdf_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_weibull_pdf( + 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_weibull_pdf_p ); + if ( !c ) return -1; + fp_t k = ((ts_weibull_pdf_params_t *)c)->k; + if (k <= 0.0 || isnan(k) || isinf(k)) return -1; + for( uint_t i = 0; i < n; ++i ) + { + fp_t xi = x[0][i]; + y[0][i] = xi >= 0 ? k * pow( xi, k - 1.0 ) * exp( -pow( xi, k ) ) : 0.0; + } + return 0; +} + diff --git a/lib/weighted_close.c b/lib/weighted_close.c new file mode 100644 index 0000000..30b8585 --- /dev/null +++ b/lib/weighted_close.c @@ -0,0 +1,39 @@ +// Weighted Close +// +// weighted_close +// +// Weighted Close +// +// +// +// Inputs: 5 +// Outputs: 1 +// Constants: 0 + + +#include "ts.h" + + +ts_parameter_t const ts_weighted_close_p = { .n_inputs = 5, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + +uint_t ts_weighted_close_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_weighted_close( + 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_weighted_close_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + y[0][i] = ( x[1][i] + x[2][i] + 2 * x[3][i] ) / 4; + } + return 0; +} + diff --git a/lib/wilders_smoothing.c b/lib/wilders_smoothing.c new file mode 100644 index 0000000..7aca8ad --- /dev/null +++ b/lib/wilders_smoothing.c @@ -0,0 +1,52 @@ +// Wilders Smoothing +// +// wilders_smoothing +// +// Wilder's Smoothing +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + fp_t k; +} ts_wilders_smoothing_params_t; + +ts_parameter_t const ts_wilders_smoothing_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_wilders_smoothing_params_t) }; + +uint_t ts_wilders_smoothing_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_wilders_smoothing( + 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_wilders_smoothing_p ); + if ( !c ) return -1; + if (n == 0) return -1; + + fp_t k = ((ts_wilders_smoothing_params_t *)c)->k; + if (k == 0) return -1; + fp_t a = 1.0 / k; + + y[0][0] = x[0][0]; + + for( uint_t i = 1; i < n; ++i ) + { + y[0][i] = y[0][i - 1] + a * ( x[0][i] - y[0][i - 1] ); + } + + return 0; +} + + diff --git a/lib/williams_r.c b/lib/williams_r.c new file mode 100644 index 0000000..f0fae3f --- /dev/null +++ b/lib/williams_r.c @@ -0,0 +1,86 @@ +// Williams R +// +// williams_r +// +// Williams %R +// +// +// +// Inputs: 4 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_williams_r_params_t; + +ts_parameter_t const ts_williams_r_p = { .n_inputs = 4, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_williams_r_params_t) }; + +uint_t ts_williams_r_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_williams_r_params_t *)c)->k > 0 ? ((ts_williams_r_params_t *)c)->k - 1 : 0 : 0 ); +} + +int ts_williams_r( + 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_williams_r_p ); + if ( !c ) return -1; + TS_CHECK_INPUT(x, x_n, n); + uint_t k = ((ts_williams_r_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + // Initial window max/min + fp_t hh = ts_h( x, 0 ); + fp_t ll = ts_l( x, 0 ); + for( uint_t j = 1; j < k; ++j ) + { + if( ts_h( x, j ) > hh ) + hh = ts_h( x, j ); + if( ts_l( x, j ) < ll ) + ll = ts_l( x, j ); + } + + { + if( hh == ll ) + y[0][k - 1] = 0; + else + y[0][k - 1] = (hh - ts_c( x, k - 1 )) / (hh - ll) * (-100.0); + } + + for( uint_t i = k; i < n; ++i ) + { + fp_t new_h = ts_h( x, i ); + fp_t new_l = ts_l( x, i ); + fp_t old_h = ts_h( x, i - k ); + fp_t old_l = ts_l( x, i - k ); + + if ( new_h > hh ) hh = new_h; + if ( new_l < ll ) ll = new_l; + if ( old_h == hh || old_l == ll ) + { + hh = ts_h( x, i - k + 1 ); + ll = ts_l( x, i - k + 1 ); + for( uint_t j = i - k + 2; j <= i; ++j ) + { + if( ts_h( x, j ) > hh ) hh = ts_h( x, j ); + if( ts_l( x, j ) < ll ) ll = ts_l( x, j ); + } + } + + if( hh == ll ) + y[0][i] = 0; + else + y[0][i] = (hh - ts_c( x, i )) / (hh - ll) * (-100.0); + } + + return 0; +} + diff --git a/lib/zero_lag_ema.c b/lib/zero_lag_ema.c new file mode 100644 index 0000000..c78adbd --- /dev/null +++ b/lib/zero_lag_ema.c @@ -0,0 +1,53 @@ +// Zero Lag Ema +// +// zero_lag_ema +// +// Zero Lag EMA +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 1 + + +#include "ts.h" + +typedef struct { + uint_t k; +} ts_zero_lag_ema_params_t; + +ts_parameter_t const ts_zero_lag_ema_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 1, .params_size = sizeof(ts_zero_lag_ema_params_t) }; + +uint_t ts_zero_lag_ema_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( c ? ((ts_zero_lag_ema_params_t *)c)->k : 0 ); +} + +int ts_zero_lag_ema( + 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_zero_lag_ema_p ); + if ( !c ) return -1; + uint_t k = ((ts_zero_lag_ema_params_t *)c)->k; + if (k == 0 || n < k) return -1; + + /* Zero-lag EMA: compute lag, then apply EMA to (2*x - x_lag) */ + fp_t alpha = 2.0 / (k + 1.0); + uint_t lag = (k - 1) / 2; + + for (uint_t i = lag; i < n; ++i) + { + fp_t adjusted = 2.0 * x[0][i] - x[0][i - lag]; + if (i == lag) + y[0][i] = adjusted; + else + y[0][i] = y[0][i - 1] + alpha * (adjusted - y[0][i - 1]); + } + return 0; +} + diff --git a/lib/zeta.c b/lib/zeta.c new file mode 100644 index 0000000..7b32e77 --- /dev/null +++ b/lib/zeta.c @@ -0,0 +1,52 @@ +// Zeta +// +// zeta +// +// Riemann Zeta Function +// +// +// +// Inputs: 1 +// Outputs: 1 +// Constants: 0 + + +#include <math.h> +#include "ts.h" + + + +ts_parameter_t const ts_zeta_p = { .n_inputs = 1, .n_outputs = 1, .n_constants = 0, .params_size = 0 }; + + +uint_t ts_zeta_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_zeta( + 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_zeta_p ); + (void)c; + for( uint_t i = 0; i < n; ++i ) + { + fp_t s = x[0][i]; + if( s <= 1.0 ) { y[0][i] = 0; continue; } + fp_t sum = 0.0; + fp_t term = 0.0; + for( uint_t k = 1; k <= 100000; ++k ) + { + term = 1.0 / pow( (fp_t)k, s ); + sum += term; + if( term < 1e-12 && k > 1000 ) break; + } + y[0][i] = sum; + } + return 0; +} + diff --git a/lib/zigzag.c b/lib/zigzag.c new file mode 100644 index 0000000..50549e2 --- /dev/null +++ b/lib/zigzag.c @@ -0,0 +1,99 @@ +// Zigzag +// +// zigzag +// +// ZigZag Filter +// +// +// +// Inputs: 1 +// Outputs: 2 +// Constants: 1 + + +#include "ts.h" + + +typedef struct { + fp_t threshold; +} ts_zigzag_params_t; + +ts_parameter_t const ts_zigzag_p = { .n_inputs = 1, .n_outputs = 2, .n_constants = 1, .params_size = sizeof(ts_zigzag_params_t) }; + + +uint_t ts_zigzag_offset( ts_constant_t const *c ) +{ + ( void )c; + return ( 0 ); +} + +int ts_zigzag( + 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_zigzag_p ); + if ( !c ) return -1; + if (n == 0) return -1; + + fp_t threshold = ((ts_zigzag_params_t *)c)->threshold; + if (threshold <= 0 || isnan(threshold) || isinf(threshold)) return -1; + + y[0][0] = x[0][0]; + y[1][0] = 0; + + for( uint_t i = 1; i < n; ++i ) + { + fp_t last_zz = y[0][i - 1]; + fp_t dir = y[1][i - 1]; + fp_t change = last_zz != 0 ? ( x[0][i] - last_zz ) / last_zz * 100.0 : 0; + + if( dir == 0 ) + { + if( change >= threshold ) + { + y[0][i] = x[0][i]; + y[1][i] = 1; + } + else if( change <= -threshold ) + { + y[0][i] = x[0][i]; + y[1][i] = -1; + } + else + { + y[0][i] = last_zz; + y[1][i] = 0; + } + } + else if( dir == 1 ) + { + if( change <= -threshold ) + { + y[0][i] = x[0][i]; + y[1][i] = -1; + } + else + { + y[0][i] = last_zz; + y[1][i] = 1; + } + } + else + { + if( change >= threshold ) + { + y[0][i] = x[0][i]; + y[1][i] = 1; + } + else + { + y[0][i] = last_zz; + y[1][i] = -1; + } + } + } + return 0; +} + |