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 /test | |
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 'test')
355 files changed, 8248 insertions, 0 deletions
diff --git a/test/absolute_value.c b/test/absolute_value.c new file mode 100644 index 0000000..2180501 --- /dev/null +++ b/test/absolute_value.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_absolute_value( void ) +{ + fp_t const x0[] = { -4, -3, -2, -1, 0, 1, 2, 3, 4 }; + fp_t const e0[] = { 4, 3, 2, 1, 0, 1, 2, 3, 4 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_absolute_value, ts_absolute_value_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_absolute_value_p); +} diff --git a/test/acceleration_bands.c b/test/acceleration_bands.c new file mode 100644 index 0000000..5911e8b --- /dev/null +++ b/test/acceleration_bands.c @@ -0,0 +1,28 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_acceleration_bands( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const cp[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, cp }; + + /* k=3, offset=2, y_n=8 */ + /* Rolling HH3: 12,13,14,15,16,17,18,19,20,21 */ + /* Rolling LL3: 9,9,9,10,11,12,13,14,15,16 */ + /* TP = (H+L+C)/3: 10.667,11.667,12.667,13.667,14.667,15.667,16.667,17.667,18.667,19.667 */ + /* SMA3(HH3): 13,14,15,16,17,18,19,20 */ + /* SMA3(TP): 11.667,12.667,13.667,14.667,15.667,16.667,17.667,18.667 */ + /* SMA3(LL3): 9,9.333,10,11,12,13,14,15 */ + fp_t const eu[] = { 13, 14, 15, 16, 17, 18, 19, 20 }; + fp_t const em[] = { 11.66667, 12.66667, 13.66667, 14.66667, 15.66667, 16.66667, 17.66667, 18.66667 }; + fp_t const el[] = { 9, 9.33333, 10, 11, 12, 13, 14, 15 }; + fp_t const * const exp[3] = { eu, em, el }; + + uint_t k = 3; + return ts_test(ts_acceleration_bands, ts_acceleration_bands_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_acceleration_bands_p); +} diff --git a/test/acosh.c b/test/acosh.c new file mode 100644 index 0000000..c9ecfd1 --- /dev/null +++ b/test/acosh.c @@ -0,0 +1,27 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_acosh( void ) +{ + fp_t const x0[] = { 1.000000, 1.500000, 2.000000, 3.000000, 5.000000 }; + fp_t const e0[] = { 0.000000, 0.962424, 1.316958, 1.762747, 2.292432 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + bool result = ts_test(ts_acosh, ts_acosh_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_acosh_p); + + fp_t const xb[] = { 0.000000, -1.000000, 0.500000 }; + + for( uint_t i = 0; i < sizeof( xb ) / sizeof( *xb ); ++i ) + { + fp_t tmp = 0; + fp_t const * const xi[1] = { &xb[i] }; + fp_t * const yi[1] = { &tmp }; + ts_acosh(yi, 1, xi, 1, 1, NULL); + result &= isnan( tmp ); + } + + return result; +} diff --git a/test/ad.c b/test/ad.c new file mode 100644 index 0000000..677068f --- /dev/null +++ b/test/ad.c @@ -0,0 +1,18 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_ad( void ) +{ + fp_t const o[] = { 10, 11, 12, 11, 12 }; + fp_t const h[] = { 12, 13, 14, 12, 14 }; + fp_t const l[] = { 8, 9, 10, 9, 10 }; + fp_t const c[] = { 11, 12, 10, 11, 11 }; + fp_t const v[] = { 100, 200, 300, 400, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t const e[] = { 50, 150, -150, -16.666666666666668, -266.66666666666669 }; + fp_t const * const e_arr[1] = { e }; + + return ts_test(ts_ad, ts_ad_offset, x, e_arr, 5, (ts_constant_t *)NULL, &ts_ad_p); +} diff --git a/test/ad_oscillator.c b/test/ad_oscillator.c new file mode 100644 index 0000000..623fc44 --- /dev/null +++ b/test/ad_oscillator.c @@ -0,0 +1,46 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_ad_oscillator( void ) +{ + fp_t const o[] = { 10, 11, 12, 11, 12 }; + fp_t const h[] = { 12, 13, 14, 12, 14 }; + fp_t const l[] = { 8, 9, 10, 9, 10 }; + fp_t const c[] = { 11, 12, 10, 11, 11 }; + fp_t const v[] = { 100, 200, 300, 400, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t fast = 3; + fp_t slow = 5; + fp_t a_fast = 1.0 / (fp_t)fast; + fp_t a_slow = 1.0 / (fp_t)slow; + + fp_t ad = 0; + fp_t ema_f = 0; + fp_t ema_s = 0; + + fp_t hl0 = h[0] - l[0]; + fp_t mf0 = hl0 != 0 ? ( (c[0] - l[0]) - (h[0] - c[0]) ) / hl0 * v[0] : 0; + ad = mf0; + ema_f = ad; + ema_s = ad; + + fp_t e[5] = { 0 }; + + for( uint_t i = 1; i < 5; ++i ) + { + fp_t hl = h[i] - l[i]; + fp_t mf = hl != 0 ? ( (c[i] - l[i]) - (h[i] - c[i]) ) / hl * v[i] : 0; + ad += mf; + ema_f = ema_f + a_fast * ( ad - ema_f ); + ema_s = ema_s + a_slow * ( ad - ema_s ); + e[i] = ema_f - ema_s; + } + + fp_t const * const e_arr[1] = { e }; + + fp_t constants[2] = { fast, slow }; + + return ts_test(ts_ad_oscillator, ts_ad_oscillator_offset, x, e_arr, 5, (ts_constant_t *)constants, &ts_ad_oscillator_p); +} diff --git a/test/addition.c b/test/addition.c new file mode 100644 index 0000000..a913da7 --- /dev/null +++ b/test/addition.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_addition( void ) +{ + fp_t x0[] = { -4, -3, -2, -1, 0, 1, 2, 3, 4 }; + fp_t x1[] = { -4, -3, -2, -1, 0, 1, 2, 3, 4 }; + fp_t e0[] = { -8, -6, -4, -2, 0, 2, 4, 6, 8 }; + + fp_t const * const x[] = { x0, x1 }; + fp_t const * const e[] = { e0 }; + + return ts_test(ts_addition, ts_addition_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_addition_p); +} diff --git a/test/adx.c b/test/adx.c new file mode 100644 index 0000000..e8df67e --- /dev/null +++ b/test/adx.c @@ -0,0 +1,61 @@ +#include <math.h> +#include <stdlib.h> +#include "ts.h" + +bool ts_test_adx( void ) +{ + uint_t n = 14; + uint_t k = 3; + + /* Monotonically rising data: +DM=1 each bar, -DM=0, TR=3 */ + fp_t *x[4]; + x[0] = malloc( n * sizeof( fp_t ) ); + x[1] = malloc( n * sizeof( fp_t ) ); + x[2] = malloc( n * sizeof( fp_t ) ); + x[3] = malloc( n * sizeof( fp_t ) ); + + for ( uint_t i = 0; i < n; ++i ) + { + x[0][i] = 10 + i; + x[1][i] = 12 + i; + x[2][i] = 9 + i; + x[3][i] = 11 + i; + } + + /* Expected: +DI=100/3, -DI=0, DX=100, ADX=100 (converged EMAs) */ + fp_t edp[] = { 100.0 / 3, 100.0 / 3, 100.0 / 3, 100.0 / 3, 100.0 / 3, 100.0 / 3, 100.0 / 3, 100.0 / 3, 100.0 / 3, 100.0 / 3 }; + fp_t edm[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + fp_t edx[] = { 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 }; + fp_t ead[] = { 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 }; + fp_t *e[4] = { edp, edm, edx, ead }; + + uint_t offset = k + 1; + uint_t y_n = n - offset; + + /* Allocate full-size output since the function writes to absolute + * indices [offset..n-1], not compacted [0..y_n-1] */ + fp_t *y[4]; + for ( uint_t i = 0; i < 4; ++i ) + y[i] = calloc( n, sizeof( fp_t ) ); + + uint8_t c[TS_CONSTANT_SIZE] = { 0 }; + *( uint_t * )c = k; + + ts_adx(y, ts_adx_p.n_outputs, (fp_t const * const *)x, ts_adx_p.n_inputs, n, (ts_constant_t const *)c); + + bool result = true; + for ( uint_t i = 0; i < 4; ++i ) + { + for ( uint_t j = 0; j < y_n; ++j ) + { + if ( fabs( y[i][offset + j] - e[i][j] ) > TS_TEST_EPSILON ) + result = false; + } + } + + for ( uint_t i = 0; i < 4; ++i ) + free( y[i] ); + free( x[0] ); free( x[1] ); free( x[2] ); free( x[3] ); + + return result; +} diff --git a/test/alligator.c b/test/alligator.c new file mode 100644 index 0000000..0288d1a --- /dev/null +++ b/test/alligator.c @@ -0,0 +1,21 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_alligator( void ) +{ + fp_t const x[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; + + fp_t const * const xp[1] = { x }; + + /* offset=12, y_n=12, comparison indices 12..23 */ + /* Jaw (shift 8) writes at indices 8..19 → overlap 12..19 (8 values) */ + /* Teeth (shift 5) writes at indices 5..21 → overlap 12..21 (10 values) */ + /* Lips (shift 3) writes at indices 3..22 → overlap 12..22 (11 values) */ + fp_t const ej[] = { 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 0, 0, 0, 0 }; + fp_t const et[] = { 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5, 19.5, 20.5, 0, 0 }; + fp_t const el[] = { 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 0 }; + fp_t const * const exp[3] = { ej, et, el }; + + return ts_test(ts_alligator, ts_alligator_offset, xp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)NULL, &ts_alligator_p); +} diff --git a/test/angle_deg_to_rad.c b/test/angle_deg_to_rad.c new file mode 100644 index 0000000..2e73988 --- /dev/null +++ b/test/angle_deg_to_rad.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_angle_deg_to_rad( void ) +{ + fp_t const x0[] = { 0.000000, 45.000000, 90.000000, 180.000000, 270.000000, 360.000000 }; + fp_t const e0[] = { 0.000000, 0.785398, 1.570796, 3.141593, 4.712389, 6.283185 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_angle_deg_to_rad, ts_angle_deg_to_rad_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_angle_deg_to_rad_p); +} diff --git a/test/angle_normalize.c b/test/angle_normalize.c new file mode 100644 index 0000000..bdfed2e --- /dev/null +++ b/test/angle_normalize.c @@ -0,0 +1,11 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_angle_normalize( void ) +{ + fp_t const x0[] = { 0.0, PI, -PI, 2*PI, -2*PI, 3*PI, -3*PI }; + fp_t const e0[] = { 0.0, PI, -PI, 0.0, 0.0, PI, -PI }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_angle_normalize, ts_angle_normalize_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_angle_normalize_p); +} diff --git a/test/angle_rad_to_deg.c b/test/angle_rad_to_deg.c new file mode 100644 index 0000000..899895e --- /dev/null +++ b/test/angle_rad_to_deg.c @@ -0,0 +1,11 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_angle_rad_to_deg( void ) +{ + fp_t const x0[] = { 0.0, PI/4, PI/3, PI/2, PI, 2*PI }; + fp_t const e0[] = { 0.0, 45.0, 60.0, 90.0, 180.0, 360.0 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_angle_rad_to_deg, ts_angle_rad_to_deg_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_angle_rad_to_deg_p); +} diff --git a/test/annualized_historical_volatility.c b/test/annualized_historical_volatility.c new file mode 100644 index 0000000..69a881e --- /dev/null +++ b/test/annualized_historical_volatility.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_annualized_historical_volatility( void ) +{ + fp_t const x0[] = { 100, 101, 100, 102, 101, 100, 103, 101, 102, 100 }; + fp_t const * const x[] = { x0 }; + + fp_t const e0[] = { 0.196453, 0.222285, 0.222285, 0.295293, 0.337649, 0.320724, 0.221194, 0 }; + + fp_t const * const e[1] = { e0 }; + + uint_t k = 3; + return ts_test(ts_annualized_historical_volatility, ts_annualized_historical_volatility_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_annualized_historical_volatility_p); +} diff --git a/test/apo.c b/test/apo.c new file mode 100644 index 0000000..7af9f5e --- /dev/null +++ b/test/apo.c @@ -0,0 +1,41 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_apo( void ) +{ + fp_t const x[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + + fp_t const * const inp[1] = { x }; + + /* fast=3, slow=5: fast_a=1/3, slow_a=1/5 */ + /* fast EMA: 10, 10.333, 10.889, 11.593, 12.395, 13.263, 14.176, 15.117, 16.078, 17.052 */ + /* slow EMA: 10, 10.2, 10.44, 10.752, 11.131, 11.575, 12.085, 12.666, 13.326, 14.062 */ + /* APO: 0.1333, 0.4481, 0.8405, 1.2634, 1.6876, 2.0930, 2.4545, 2.7521, 2.9901 */ + + fp_t fast_e = 10, slow_e = 10; + fp_t fast_a = 1.0 / 3, slow_a = 1.0 / 5; + fp_t e[6] = { 0 }; + + uint_t offset = 4; + for( uint_t i = 1; i <= offset; ++i ) + { + fast_e = fast_e + fast_a * ( x[i] - fast_e ); + slow_e = slow_e + slow_a * ( x[i] - slow_e ); + } + e[0] = fast_e - slow_e; + + for( uint_t i = offset + 1; i < 10; ++i ) + { + fast_e = fast_e + fast_a * ( x[i] - fast_e ); + slow_e = slow_e + slow_a * ( x[i] - slow_e ); + e[i - offset] = fast_e - slow_e; + } + + fp_t const * const exp[1] = { e }; + + typedef struct { fp_t fast; fp_t slow; } c_t; + c_t c = { .fast = 3, .slow = 5 }; + + return ts_test(ts_apo, ts_apo_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&c, &ts_apo_p); +} diff --git a/test/aroon.c b/test/aroon.c new file mode 100644 index 0000000..df68637 --- /dev/null +++ b/test/aroon.c @@ -0,0 +1,21 @@ +#include "ts.h" + +bool ts_test_aroon( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* k=3, offset=2, y_n=8 */ + /* Monotonically rising H, falling L => most recent bar is always the extreme => age=0 => Aroon=100 */ + /* Function writes to y[2..9], ts_test compares y[j+offset] vs e[j] for j=0..7 */ + fp_t const eup[] = { 100, 100, 100, 100, 100, 100, 100, 100 }; + fp_t const edn[] = { 100, 100, 100, 100, 100, 100, 100, 100 }; + fp_t const * const exp[2] = { eup, edn }; + + uint_t k = 3; + return ts_test(ts_aroon, ts_aroon_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_aroon_p); +} diff --git a/test/aroon_oscillator.c b/test/aroon_oscillator.c new file mode 100644 index 0000000..6a56922 --- /dev/null +++ b/test/aroon_oscillator.c @@ -0,0 +1,22 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_aroon_oscillator( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* k=3, offset=2 */ + /* Rising highs, falling lows => AroonUp=100, AroonDown=100 */ + /* Oscillator = 100 - 100 = 0 */ + fp_t const e[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_aroon_oscillator, ts_aroon_oscillator_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_aroon_oscillator_p); +} diff --git a/test/asi.c b/test/asi.c new file mode 100644 index 0000000..0307a3b --- /dev/null +++ b/test/asi.c @@ -0,0 +1,35 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_asi( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const c[] = { 11, 12, 11, 14, 13, 16, 15, 18, 17, 20 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* ASI = prev_ASI + component2 + component3 + * component2 = (term1 - term2 + term3) / denom * (H - L) + * component3 = (term1 - term2 + term3) / (2 * denom) + * term1 = C - Cprev, term2 = 0.5*(O - Op), term3 = 0.25*(C - O + Op - Cp) + * denom = max(H - Lp, Hp - L, Hp - Lp) + * + * i=0: ASI = 0 + * i=1: term1=1, term2=0.5, term3=0, denom=4, comp2=0.375, comp3=0.125 => 0.5 + * i=2: term1=-1, term2=0.5, term3=-0.5, denom=4, comp2=-1.5, comp3=-0.5 => -1.5 + * i=3: term1=3, term2=0.5, term3=0.5, denom=4, comp2=2.25, comp3=0.75 => 1.5 + * i=4: term1=-1, term2=0.5, term3=-0.5, denom=4, comp2=-1.5, comp3=-0.5 => -0.5 + * i=5: term1=3, term2=0.5, term3=0.5, denom=4, comp2=2.25, comp3=0.75 => 2.5 + * i=6: term1=-1, term2=0.5, term3=-0.5, denom=4, comp2=-1.5, comp3=-0.5 => 0.5 + * i=7: term1=3, term2=0.5, term3=0.5, denom=4, comp2=2.25, comp3=0.75 => 3.5 + * i=8: term1=-1, term2=0.5, term3=-0.5, denom=4, comp2=-1.5, comp3=-0.5 => 1.5 + * i=9: term1=3, term2=0.5, term3=0.5, denom=4, comp2=2.25, comp3=0.75 => 4.5 + */ + fp_t const e[] = { 0, 0.5, -1.5, 1.5, -0.5, 2.5, 0.5, 3.5, 1.5, 4.5 }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_asi, ts_asi_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)NULL, &ts_asi_p); +} diff --git a/test/asinh.c b/test/asinh.c new file mode 100644 index 0000000..4ad6494 --- /dev/null +++ b/test/asinh.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_asinh( void ) +{ + fp_t const x0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000 }; + fp_t const e0[] = { -1.443635, -0.881374, 0.000000, 0.881374, 1.443635 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_asinh, ts_asinh_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_asinh_p); +} diff --git a/test/atan2.c b/test/atan2.c new file mode 100644 index 0000000..8509e22 --- /dev/null +++ b/test/atan2.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_atan2( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, 1.000000, -1.000000 }; + fp_t const x1[] = { -1.000000, 0.000000, -1.000000, 0.000000 }; + fp_t const e0[] = { 3.141593, 1.570796, 2.356194, -1.570796 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_atan2, ts_atan2_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_atan2_p); +} diff --git a/test/atanh.c b/test/atanh.c new file mode 100644 index 0000000..91a9169 --- /dev/null +++ b/test/atanh.c @@ -0,0 +1,35 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_atanh( void ) +{ + fp_t const x0[] = { -0.900000, -0.500000, 0.000000, 0.500000, 0.900000 }; + fp_t const e0[] = { -1.472219, -0.549306, 0.000000, 0.549306, 1.472219 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + bool result = ts_test(ts_atanh, ts_atanh_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_atanh_p); + + fp_t const xb[] = { -1.000000, 1.000000, -1.500000, 1.500000 }; + fp_t const eb[] = { -INFINITY, INFINITY, NAN, NAN }; + + for( uint_t i = 0; i < sizeof( xb ) / sizeof( *xb ); ++i ) + { + fp_t tmp = 0; + fp_t const * const xi[1] = { &xb[i] }; + fp_t * const yi[1] = { &tmp }; + ts_atanh(yi, 1, xi, 1, 1, NULL); + if( isinf( eb[i] ) ) + { + result &= isinf( tmp ) && signbit( tmp ) == signbit( eb[i] ); + } + else if( isnan( eb[i] ) ) + { + result &= isnan( tmp ); + } + } + + return result; +} diff --git a/test/atr.c b/test/atr.c new file mode 100644 index 0000000..fb1ad4d --- /dev/null +++ b/test/atr.c @@ -0,0 +1,19 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_atr( void ) +{ + fp_t const o[] = { 9, 11, 10, 12, 12, 13, 11, 14, 13, 15 }; + fp_t const h[] = { 10, 12, 11, 13, 12, 14, 12, 15, 14, 16 }; + fp_t const l[] = { 8, 9, 10, 11, 10, 12, 11, 13, 12, 14 }; + fp_t const c[] = { 9, 10, 12, 11, 13, 11, 14, 12, 15, 13 }; + + fp_t const * const x[] = { o, h, l, c }; + + fp_t const e[] = { 2.0, 2.0, 2.0, 1.66667, 1.77778, 1.85185, 1.90123 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_atr, ts_atr_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_atr_p); +} diff --git a/test/atr_bands.c b/test/atr_bands.c new file mode 100644 index 0000000..2d58743 --- /dev/null +++ b/test/atr_bands.c @@ -0,0 +1,29 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_atr_bands( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const cp[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, cp }; + + /* k=3, mult=2.0 */ + /* TR[1]=3, TR[2]=3, TR[3]=3 => ATR=3.0 */ + /* TR[4]=3, ... => ATR stays 3.0 */ + /* Middle(SMA3 of close from idx 1): (12+13+14)/3=13, then rolling */ + /* Middle: 13, 14, 15, 16, 17, 18, 19 */ + /* Upper: 19, 20, 21, 22, 23, 24, 25 */ + /* Lower: 7, 8, 9, 10, 11, 12, 13 */ + fp_t const em[] = { 13, 14, 15, 16, 17, 18, 19 }; + fp_t const eu[] = { 19, 20, 21, 22, 23, 24, 25 }; + fp_t const el[] = { 7, 8, 9, 10, 11, 12, 13 }; + fp_t const * const exp[3] = { eu, em, el }; + + typedef struct { uint_t k; fp_t mult; } c_t; + c_t c = { .k = 3, .mult = 2.0 }; + return ts_test(ts_atr_bands, ts_atr_bands_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&c, &ts_atr_bands_p); +} diff --git a/test/atr_trailing_stops.c b/test/atr_trailing_stops.c new file mode 100644 index 0000000..5f04b14 --- /dev/null +++ b/test/atr_trailing_stops.c @@ -0,0 +1,26 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_atr_trailing_stops( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const cp[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, cp }; + + /* k=3, mult=2.0, offset=3, y_n=7 */ + /* TR: all 3 => ATR=3.0 */ + /* At i=3: Mid=(15+12)/2=13.5, Upper=13.5+6=19.5, Lower=13.5-6=7.5 */ + /* At i=4: Mid=14.5, computed U=20.5, L=8.5 => trail: U=fmax(19.5,20.5)=20.5, L=fmin(7.5,8.5)=7.5 */ + /* Upper trails up, lower stays at 7.5 (only moves down) */ + fp_t const eu[] = { 19.5, 20.5, 21.5, 22.5, 23.5, 24.5, 25.5 }; + fp_t const el[] = { 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5 }; + fp_t const * const exp[2] = { eu, el }; + + typedef struct { uint_t k; fp_t mult; } c_t; + c_t my_c = { .k = 3, .mult = 2.0 }; + return ts_test(ts_atr_trailing_stops, ts_atr_trailing_stops_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&my_c, &ts_atr_trailing_stops_p); +} diff --git a/test/average.c b/test/average.c new file mode 100644 index 0000000..8652a99 --- /dev/null +++ b/test/average.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_average( void ) +{ + uint_t const c = 3; + + fp_t const x0[] = { 2, 4, 6, 8, 10 }; + fp_t const e0[] = { 4, 6, 8 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_average, ts_average_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_average_p); +} diff --git a/test/average_cumulative.c b/test/average_cumulative.c new file mode 100644 index 0000000..01986f7 --- /dev/null +++ b/test/average_cumulative.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_average_cumulative( void ) +{ + fp_t const x0[] = { -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + fp_t const e0[] = { -10, -9.5, -9, -8.5, -8, -7.5, -7, -6.5, -6, -5.5, -5, -4.5, -4, -3.5, -3, -2.5, -2, -1.5, -1, -0.5, 0 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_average_cumulative, ts_average_cumulative_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_average_cumulative_p); +} diff --git a/test/average_exponential.c b/test/average_exponential.c new file mode 100644 index 0000000..2e0b50b --- /dev/null +++ b/test/average_exponential.c @@ -0,0 +1,16 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_average_exponential( void ) +{ + fp_t const x0[] = { -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10 }; + fp_t const e0[] = { -10, -8.75, -6.875, -4.6875, -2.34375, 0.078125, 2.5390625, 5.01953125, 7.509765625 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + fp_t c = 2; + + return ts_test(ts_average_exponential, ts_average_exponential_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_average_exponential_p); +} diff --git a/test/average_exponential_double.c b/test/average_exponential_double.c new file mode 100644 index 0000000..f78d341 --- /dev/null +++ b/test/average_exponential_double.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_average_exponential_double( void ) +{ + fp_t const c[] = { 0.5 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 1, 1.75, 2.75, 3.8125, 4.875 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_average_exponential_double, ts_average_exponential_double_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_average_exponential_double_p); +} diff --git a/test/average_exponential_triple.c b/test/average_exponential_triple.c new file mode 100644 index 0000000..baeeb31 --- /dev/null +++ b/test/average_exponential_triple.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_average_exponential_triple( void ) +{ + fp_t const c[] = { 0.5 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 1, 1.875, 2.9375, 4.0, 5.03125 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_average_exponential_triple, ts_average_exponential_triple_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_average_exponential_triple_p); +} diff --git a/test/average_price.c b/test/average_price.c new file mode 100644 index 0000000..2587783 --- /dev/null +++ b/test/average_price.c @@ -0,0 +1,17 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_average_price( void ) +{ + fp_t const x0[] = { 1, 1, 1, 1, 1 }; + fp_t const x1[] = { 2, 3, 4, 5, 6 }; + fp_t const x2[] = { 0, 1, 2, 3, 4 }; + fp_t const x3[] = { 3, 4, 5, 6, 7 }; + fp_t const x4[] = { 1, 1, 1, 1, 1 }; + fp_t const e0[] = { 1.66666666666667, 2.66666666666667, 3.66666666666667, 4.66666666666667, 5.66666666666667 }; + + fp_t const * const x[] = { x0, x1, x2, x3, x4 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_average_price, ts_average_price_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_average_price_p); +} diff --git a/test/average_triangle.c b/test/average_triangle.c new file mode 100644 index 0000000..7116099 --- /dev/null +++ b/test/average_triangle.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_average_triangle( void ) +{ + uint_t const c[] = { 3 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5, 6 }; + fp_t const e0[] = { 3, 4 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_average_triangle, ts_average_triangle_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_average_triangle_p); +} diff --git a/test/average_weighted.c b/test/average_weighted.c new file mode 100644 index 0000000..544af84 --- /dev/null +++ b/test/average_weighted.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_average_weighted( void ) +{ + uint_t const c[] = { 3 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 2.333333, 3.333333, 4.333333 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_average_weighted, ts_average_weighted_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_average_weighted_p); +} diff --git a/test/average_weighted_series.c b/test/average_weighted_series.c new file mode 100644 index 0000000..f6c4318 --- /dev/null +++ b/test/average_weighted_series.c @@ -0,0 +1,16 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_average_weighted_series( void ) +{ + uint_t const c[] = { 3 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const x1[] = { 2, 3, 4, 5, 6 }; + fp_t const e0[] = { 6.666667, 12.666667, 20.666667 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_average_weighted_series, ts_average_weighted_series_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_average_weighted_series_p); +} diff --git a/test/awesome_oscillator.c b/test/awesome_oscillator.c new file mode 100644 index 0000000..205bf78 --- /dev/null +++ b/test/awesome_oscillator.c @@ -0,0 +1,58 @@ +#include <stddef.h> +#include <stdlib.h> +#include <math.h> +#include "ts.h" + +bool ts_test_awesome_oscillator( void ) +{ + uint_t n = 40; + fp_t *o = calloc( n, sizeof( fp_t ) ); + fp_t *h = calloc( n, sizeof( fp_t ) ); + fp_t *l = calloc( n, sizeof( fp_t ) ); + fp_t *c = calloc( n, sizeof( fp_t ) ); + + if ( !o || !h || !l || !c ) + { + free( o ); free( h ); free( l ); free( c ); + return false; + } + + for ( uint_t i = 0; i < n; ++i ) + { + o[i] = (fp_t)(10 + i); + h[i] = (fp_t)(12 + i); + l[i] = (fp_t)(8 + i); + c[i] = (fp_t)(11 + i); + } + + fp_t *result = calloc( n, sizeof( fp_t ) ); + + ts_awesome_oscillator(&result, 1, (fp_t const * const []){ o, h, l, c }, 4, n, NULL); + + /* Compute expected EMA(5) and EMA(34) of median price */ + fp_t fast_a = 2.0 / 6.0; + fp_t slow_a = 2.0 / 35.0; + fp_t sum_fast = 0, sum_slow = 0; + for ( uint_t i = 0; i < 34; ++i ) + { + fp_t mp = (h[i] + l[i]) / 2; + sum_slow += mp; + if ( i < 5 ) sum_fast += mp; + } + fp_t ema_fast = sum_fast / 5.0; + fp_t ema_slow = sum_slow / 34.0; + for ( uint_t i = 34; i < n; ++i ) + { + fp_t mp = (h[i] + l[i]) / 2; + ema_fast = ema_fast + fast_a * ( mp - ema_fast ); + ema_slow = ema_slow + slow_a * ( mp - ema_slow ); + } + + fp_t expected = ema_fast - ema_slow; + + bool pass = fabs( result[n - 1] - expected ) < 1e-10; + + free( o ); free( h ); free( l ); free( c ); free( result ); + + return pass; +} diff --git a/test/balance_of_power.c b/test/balance_of_power.c new file mode 100644 index 0000000..cff39bb --- /dev/null +++ b/test/balance_of_power.c @@ -0,0 +1,17 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_balance_of_power( void ) +{ + fp_t const x0[] = { 10, 10, 15, 20, 25 }; + fp_t const x1[] = { 14, 13, 18, 24, 29 }; + fp_t const x2[] = { 8, 9, 14, 21, 24 }; + fp_t const x3[] = { 12, 11, 16, 22, 27 }; + fp_t const e0[] = { 0.333333333333333, 0.25, 0.25, 0.666666666666667, 0.4 }; + + fp_t const * const x[] = { x0, x1, x2, x3 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_balance_of_power, ts_balance_of_power_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_balance_of_power_p); +} diff --git a/test/band_width.c b/test/band_width.c new file mode 100644 index 0000000..99dd4bf --- /dev/null +++ b/test/band_width.c @@ -0,0 +1,19 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_band_width( void ) +{ + fp_t const x[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const * const inp[1] = { x }; + + /* k=3, mult=2.0 */ + /* SD = sqrt(2/3) = 0.81650 for all windows */ + /* Width = (Upper - Lower) / Middle * 100 = (4*SD) / Middle * 100 */ + fp_t const e[] = { 29.690785, 27.216553, 25.122972, 23.328474, 21.773242, 20.412415, 19.211684, 18.144368 }; + fp_t const * const exp[1] = { e }; + + typedef struct { uint_t k; fp_t std_mult; } c_t; + c_t my_c = { .k = 3, .std_mult = 2.0 }; + return ts_test(ts_band_width, ts_band_width_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&my_c, &ts_band_width_p); +} diff --git a/test/bench.c b/test/bench.c new file mode 100644 index 0000000..83330aa --- /dev/null +++ b/test/bench.c @@ -0,0 +1,204 @@ +#define TS_IMPLEMENTATION +#include "ts.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#define BENCH_N 10000 +#define BENCH_ITER 100 + +typedef struct { uint_t k; fp_t std_mult; } bb_params_t; +typedef struct { fp_t fast_k; fp_t slow_k; fp_t signal_k; } macd_params_t; +typedef struct { fp_t Q; fp_t R; } kalman_params_t; + +static fp_t bench_input[BENCH_N]; +static fp_t bench_output[BENCH_N]; +static fp_t bench_ohlc[4][BENCH_N]; +static fp_t bench_output_multi[4][BENCH_N]; + +static double elapsed_ms(struct timespec *start, struct timespec *end) +{ + return (end->tv_sec - start->tv_sec) * 1000.0 + (end->tv_nsec - start->tv_nsec) / 1000000.0; +} + +int main(void) +{ + ts_fill(bench_input, BENCH_N, 0, BENCH_N); + + for (uint_t c = 0; c < 4; c++) { + ts_fill(bench_ohlc[c], BENCH_N, 100 + c, 200 + c); + } + + printf("Benchmark: n=%d, iterations=%d\n", BENCH_N, BENCH_ITER); + printf("--------------------------------------------------\n"); + + struct timespec start, end; + + /* ts_average */ + { + uint_t k = 14; + fp_t * const y[1] = { bench_output }; + fp_t const * const x[1] = { bench_input }; + clock_gettime(CLOCK_MONOTONIC, &start); + for (uint_t i = 0; i < BENCH_ITER; i++) { + (void)ts_average(y, 1, x, 1, BENCH_N, (ts_constant_t *)&k); + } + clock_gettime(CLOCK_MONOTONIC, &end); + double ms = elapsed_ms(&start, &end); + printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_average", ms, ms * 1000000.0 / BENCH_ITER); + } + + /* ts_rsi */ + { + uint_t k = 14; + fp_t * const y[1] = { bench_output }; + fp_t const * const x[1] = { bench_input }; + clock_gettime(CLOCK_MONOTONIC, &start); + for (uint_t i = 0; i < BENCH_ITER; i++) { + (void)ts_rsi(y, 1, x, 1, BENCH_N, (ts_constant_t *)&k); + } + clock_gettime(CLOCK_MONOTONIC, &end); + double ms = elapsed_ms(&start, &end); + printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_rsi", ms, ms * 1000000.0 / BENCH_ITER); + } + + /* ts_deviation_standard */ + { + uint_t k = 14; + fp_t * const y[1] = { bench_output }; + fp_t const * const x[1] = { bench_input }; + clock_gettime(CLOCK_MONOTONIC, &start); + for (uint_t i = 0; i < BENCH_ITER; i++) { + (void)ts_deviation_standard(y, 1, x, 1, BENCH_N, (ts_constant_t *)&k); + } + clock_gettime(CLOCK_MONOTONIC, &end); + double ms = elapsed_ms(&start, &end); + printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_deviation_standard", ms, ms * 1000000.0 / BENCH_ITER); + } + + /* ts_average_exponential */ + { + uint_t k = 14; + fp_t * const y[1] = { bench_output }; + fp_t const * const x[1] = { bench_input }; + clock_gettime(CLOCK_MONOTONIC, &start); + for (uint_t i = 0; i < BENCH_ITER; i++) { + (void)ts_average_exponential(y, 1, x, 1, BENCH_N, (ts_constant_t *)&k); + } + clock_gettime(CLOCK_MONOTONIC, &end); + double ms = elapsed_ms(&start, &end); + printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_average_exponential", ms, ms * 1000000.0 / BENCH_ITER); + } + + /* ts_bollinger_bands */ + { + bb_params_t c = { .k = 20, .std_mult = 2.0 }; + fp_t * const y[3] = { bench_output_multi[0], bench_output_multi[1], bench_output_multi[2] }; + fp_t const * const x[1] = { bench_input }; + clock_gettime(CLOCK_MONOTONIC, &start); + for (uint_t i = 0; i < BENCH_ITER; i++) { + (void)ts_bollinger_bands(y, 3, x, 1, BENCH_N, (ts_constant_t *)&c); + } + clock_gettime(CLOCK_MONOTONIC, &end); + double ms = elapsed_ms(&start, &end); + printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_bollinger_bands", ms, ms * 1000000.0 / BENCH_ITER); + } + + /* ts_macd */ + { + macd_params_t c = { .fast_k = 12, .slow_k = 26, .signal_k = 9 }; + fp_t * const y[3] = { bench_output_multi[0], bench_output_multi[1], bench_output_multi[2] }; + fp_t const * const x[1] = { bench_input }; + clock_gettime(CLOCK_MONOTONIC, &start); + for (uint_t i = 0; i < BENCH_ITER; i++) { + (void)ts_macd(y, 3, x, 1, BENCH_N, (ts_constant_t *)&c); + } + clock_gettime(CLOCK_MONOTONIC, &end); + double ms = elapsed_ms(&start, &end); + printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_macd", ms, ms * 1000000.0 / BENCH_ITER); + } + + /* ts_atr */ + { + uint_t k = 14; + fp_t * const y[1] = { bench_output }; + fp_t const * const x[4] = { bench_ohlc[0], bench_ohlc[1], bench_ohlc[2], bench_ohlc[3] }; + clock_gettime(CLOCK_MONOTONIC, &start); + for (uint_t i = 0; i < BENCH_ITER; i++) { + (void)ts_atr(y, 1, x, 4, BENCH_N, (ts_constant_t *)&k); + } + clock_gettime(CLOCK_MONOTONIC, &end); + double ms = elapsed_ms(&start, &end); + printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_atr", ms, ms * 1000000.0 / BENCH_ITER); + } + + /* ts_adx */ + { + uint_t k = 14; + fp_t * const y[4] = { bench_output_multi[0], bench_output_multi[1], bench_output_multi[2], bench_output_multi[3] }; + fp_t const * const x[4] = { bench_ohlc[0], bench_ohlc[1], bench_ohlc[2], bench_ohlc[3] }; + clock_gettime(CLOCK_MONOTONIC, &start); + for (uint_t i = 0; i < BENCH_ITER; i++) { + (void)ts_adx(y, 4, x, 4, BENCH_N, (ts_constant_t *)&k); + } + clock_gettime(CLOCK_MONOTONIC, &end); + double ms = elapsed_ms(&start, &end); + printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_adx", ms, ms * 1000000.0 / BENCH_ITER); + } + + /* ts_kalman_filter */ + { + kalman_params_t c = { .Q = 0.01, .R = 0.05 }; + fp_t * const y[1] = { bench_output }; + fp_t const * const x[1] = { bench_input }; + clock_gettime(CLOCK_MONOTONIC, &start); + for (uint_t i = 0; i < BENCH_ITER; i++) { + (void)ts_kalman_filter(y, 1, x, 1, BENCH_N, (ts_constant_t *)&c); + } + clock_gettime(CLOCK_MONOTONIC, &end); + double ms = elapsed_ms(&start, &end); + printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_kalman_filter", ms, ms * 1000000.0 / BENCH_ITER); + } + + /* ts_absolute_value */ + { + fp_t * const y[1] = { bench_output }; + fp_t const * const x[1] = { bench_input }; + clock_gettime(CLOCK_MONOTONIC, &start); + for (uint_t i = 0; i < BENCH_ITER; i++) { + (void)ts_absolute_value(y, 1, x, 1, BENCH_N, NULL); + } + clock_gettime(CLOCK_MONOTONIC, &end); + double ms = elapsed_ms(&start, &end); + printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_absolute_value", ms, ms * 1000000.0 / BENCH_ITER); + } + + /* ts_sine */ + { + fp_t * const y[1] = { bench_output }; + fp_t const * const x[1] = { bench_input }; + clock_gettime(CLOCK_MONOTONIC, &start); + for (uint_t i = 0; i < BENCH_ITER; i++) { + (void)ts_sine(y, 1, x, 1, BENCH_N, NULL); + } + clock_gettime(CLOCK_MONOTONIC, &end); + double ms = elapsed_ms(&start, &end); + printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_sine", ms, ms * 1000000.0 / BENCH_ITER); + } + + /* ts_addition */ + { + fp_t * const y[1] = { bench_output }; + fp_t const * const x[2] = { bench_input, bench_ohlc[0] }; + clock_gettime(CLOCK_MONOTONIC, &start); + for (uint_t i = 0; i < BENCH_ITER; i++) { + (void)ts_addition(y, 1, x, 2, BENCH_N, NULL); + } + clock_gettime(CLOCK_MONOTONIC, &end); + double ms = elapsed_ms(&start, &end); + printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_addition", ms, ms * 1000000.0 / BENCH_ITER); + } + + return 0; +} diff --git a/test/beta_pdf.c b/test/beta_pdf.c new file mode 100644 index 0000000..d8606b9 --- /dev/null +++ b/test/beta_pdf.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_beta_pdf( void ) +{ + fp_t const c[] = { 2.000000, 5.000000 }; + + fp_t const x0[] = { 0.100000, 0.200000, 0.300000, 0.400000, 0.500000 }; + fp_t const e0[] = { 1.968300, 2.457600, 2.160900, 1.555200, 0.937500 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_beta_pdf, ts_beta_pdf_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_beta_pdf_p); +} diff --git a/test/binomial.c b/test/binomial.c new file mode 100644 index 0000000..365ed6d --- /dev/null +++ b/test/binomial.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_binomial( void ) +{ + fp_t const x0[] = { 5.000000, 10.000000, 6.000000, 4.000000 }; + fp_t const x1[] = { 2.000000, 3.000000, 2.000000, 2.000000 }; + fp_t const e0[] = { 10.000000, 120.000000, 15.000000, 6.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_binomial, ts_binomial_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_binomial_p); +} diff --git a/test/binomial_pdf.c b/test/binomial_pdf.c new file mode 100644 index 0000000..2d234cc --- /dev/null +++ b/test/binomial_pdf.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_binomial_pdf( void ) +{ + /* n_trials=10 (uint_t at byte 0), p=0.5 (fp_t at byte 8) */ + typedef struct { uint_t n_trials; fp_t p; } c_t; + c_t c = { .n_trials = 10, .p = 0.5 }; + fp_t const x0[] = { 0,1,2,3,4,5,6,7,8,9,10 }; + fp_t const e0[] = { 0.000977, 0.009766, 0.043945, 0.117188, 0.205078, 0.246094, 0.205078, 0.117188, 0.043945, 0.009766, 0.000977 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_binomial_pdf, ts_binomial_pdf_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_binomial_pdf_p); +} diff --git a/test/bollinger_bands.c b/test/bollinger_bands.c new file mode 100644 index 0000000..37bc138 --- /dev/null +++ b/test/bollinger_bands.c @@ -0,0 +1,22 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_bollinger_bands( void ) +{ + fp_t const x[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const * const inp[1] = { x }; + + /* k=3, std_mult=2 */ + /* SMA: 11, 12, 13, 14, 15, 16, 17, 18 */ + /* SD: sqrt(2/3)=0.81650 for all windows */ + /* Upper = SMA + 2*SD, Lower = SMA - 2*SD */ + fp_t const em[] = { 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const eu[] = { 12.632993, 13.632993, 14.632993, 15.632993, 16.632993, 17.632993, 18.632993, 19.632993 }; + fp_t const el[] = { 9.367007, 10.367007, 11.367007, 12.367007, 13.367007, 14.367007, 15.367007, 16.367007 }; + fp_t const * const exp[3] = { em, eu, el }; + + typedef struct { uint_t k; fp_t std_mult; } c_t; + c_t c = { .k = 3, .std_mult = 2.0 }; + return ts_test(ts_bollinger_bands, ts_bollinger_bands_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&c, &ts_bollinger_bands_p); +} diff --git a/test/bollinger_lower.c b/test/bollinger_lower.c new file mode 100644 index 0000000..5e91f97 --- /dev/null +++ b/test/bollinger_lower.c @@ -0,0 +1,16 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_bollinger_lower( void ) +{ + fp_t const x[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { 9.367007, 10.367007, 11.367007, 12.367007, 13.367007, 14.367007, 15.367007, 16.367007 }; + fp_t const * const exp[1] = { e }; + + typedef struct { uint_t k; fp_t std_mult; } c_t; + c_t c = { .k = 3, .std_mult = 2.0 }; + return ts_test(ts_bollinger_lower, ts_bollinger_lower_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&c, &ts_bollinger_lower_p); +} diff --git a/test/bollinger_pctb.c b/test/bollinger_pctb.c new file mode 100644 index 0000000..760156f --- /dev/null +++ b/test/bollinger_pctb.c @@ -0,0 +1,19 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_bollinger_pctb( void ) +{ + fp_t const x[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const * const inp[1] = { x }; + + /* pctB = (C - Lower) / (Upper - Lower) = (C - (M - 2*SD)) / (4*SD) */ + /* At idx 2: C=12, M=11, SD=0.81650, (12 - 9.367) / 3.266 = 0.80622 */ + /* At idx 3: C=13, M=12, SD=0.81650, (13 - 10.367) / 3.266 = 0.80622 */ + fp_t const e[] = { 0.8061862178, 0.8061862178, 0.8061862178, 0.8061862178, 0.8061862178, 0.8061862178, 0.8061862178, 0.8061862178 }; + fp_t const * const exp[1] = { e }; + + typedef struct { uint_t k; fp_t std_mult; } c_t; + c_t c = { .k = 3, .std_mult = 2.0 }; + return ts_test(ts_bollinger_pctb, ts_bollinger_pctb_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&c, &ts_bollinger_pctb_p); +} diff --git a/test/bollinger_upper.c b/test/bollinger_upper.c new file mode 100644 index 0000000..701980e --- /dev/null +++ b/test/bollinger_upper.c @@ -0,0 +1,16 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_bollinger_upper( void ) +{ + fp_t const x[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { 12.632993, 13.632993, 14.632993, 15.632993, 16.632993, 17.632993, 18.632993, 19.632993 }; + fp_t const * const exp[1] = { e }; + + typedef struct { uint_t k; fp_t std_mult; } c_t; + c_t c = { .k = 3, .std_mult = 2.0 }; + return ts_test(ts_bollinger_upper, ts_bollinger_upper_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&c, &ts_bollinger_upper_p); +} diff --git a/test/bollinger_width.c b/test/bollinger_width.c new file mode 100644 index 0000000..6a5b21f --- /dev/null +++ b/test/bollinger_width.c @@ -0,0 +1,17 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_bollinger_width( void ) +{ + fp_t const x[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const * const inp[1] = { x }; + + /* width = 2*2*SD/Middle*100 = 4*0.81650/Middle*100 */ + fp_t const e[] = { 29.690785, 27.216553, 25.122972, 23.328474, 21.773242, 20.412415, 19.211684, 18.144368 }; + fp_t const * const exp[1] = { e }; + + typedef struct { uint_t k; fp_t std_mult; } c_t; + c_t c = { .k = 3, .std_mult = 2.0 }; + return ts_test(ts_bollinger_width, ts_bollinger_width_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&c, &ts_bollinger_width_p); +} diff --git a/test/candlestick_formations.c b/test/candlestick_formations.c new file mode 100644 index 0000000..300b05e --- /dev/null +++ b/test/candlestick_formations.c @@ -0,0 +1,32 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_candlestick_formations( void ) +{ + fp_t const o[] = { 10, 10, 14, 11, 10, 15, 12, 13, 14, 16 }; + fp_t const h[] = { 11, 11, 15, 12, 14, 15, 13, 16, 14, 16 }; + fp_t const l[] = { 9, 9, 13, 10, 10, 13, 11, 12, 12, 14 }; + fp_t const c[] = { 10, 10, 14, 11, 13, 14, 12, 15, 13, 15 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* i=1: O=10,C=10,H=11,L=9, body=0, range=2, doji (body/range=0 < 0.1) => 1 */ + /* i=2: O=14,C=14,H=15,L=13, body=0, range=2, doji => 1 */ + /* i=3: O=11,C=11,H=12,L=10, body=0, range=2, doji => 1 */ + /* i=4: O=10,C=13,H=14,L=10, body=3, range=4, upper_wick=1, lower_wick=0, body_abs/range=0.75 */ + /* prev_body=0, not engulfing. upper_wick=1, lower_wick=0 => not hammer/star => 0 */ + /* i=5: O=15,C=14,H=15,L=13, body=-1, range=2, upper_wick=0, lower_wick=1 */ + /* prev_body=3>0, -body=1 < 3, not engulfing. upper_wick=0 < 2*1 => not star. lower_wick=1 < 2*1 => not hammer. 0 */ + /* i=6: O=12,C=12,H=13,L=11, body=0, range=2, doji => 1 */ + /* i=7: O=13,C=15,H=16,L=12, body=2, range=4, upper_wick=1, lower_wick=1 */ + /* prev_body=0, not engulfing. upper_wick=1 < 2*2, lower_wick=1 < 2*2 => 0 */ + /* i=8: O=14,C=13,H=14,L=12, body=-1, range=2, upper_wick=0, lower_wick=1 */ + /* prev_body=2>0, -body=1 < 2, not engulfing. not star/hammer => 0 */ + /* i=9: O=16,C=15,H=16,L=14, body=-1, range=2, upper_wick=0, lower_wick=1 */ + /* prev_body=-1, same direction, not engulfing. lower_wick=1 < 2*1 => 0 */ + fp_t const e[] = { 1, 1, 1, 0, 0, 1, 0, 0, 0 }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_candlestick_formations, ts_candlestick_formations_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)NULL, &ts_candlestick_formations_p); +} diff --git a/test/catalan.c b/test/catalan.c new file mode 100644 index 0000000..0dda06e --- /dev/null +++ b/test/catalan.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_catalan( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, 2.000000, 3.000000, 4.000000, 5.000000 }; + fp_t const e0[] = { 1.000000, 1.000000, 2.000000, 5.000000, 14.000000, 42.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_catalan, ts_catalan_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_catalan_p); +} diff --git a/test/cauchy_cdf.c b/test/cauchy_cdf.c new file mode 100644 index 0000000..0197133 --- /dev/null +++ b/test/cauchy_cdf.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_cauchy_cdf( void ) +{ + fp_t const x0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000 }; + fp_t const e0[] = { 0.147584, 0.250000, 0.500000, 0.750000, 0.852416 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_cauchy_cdf, ts_cauchy_cdf_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cauchy_cdf_p); +} diff --git a/test/cauchy_pdf.c b/test/cauchy_pdf.c new file mode 100644 index 0000000..e8c5f55 --- /dev/null +++ b/test/cauchy_pdf.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_cauchy_pdf( void ) +{ + fp_t const x0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000 }; + fp_t const e0[] = { 0.063662, 0.159155, 0.318310, 0.159155, 0.063662 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_cauchy_pdf, ts_cauchy_pdf_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cauchy_pdf_p); +} diff --git a/test/cbrt.c b/test/cbrt.c new file mode 100644 index 0000000..f0c0ae4 --- /dev/null +++ b/test/cbrt.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_cbrt( void ) +{ + fp_t const x0[] = { -8.000000, -1.000000, 0.000000, 1.000000, 8.000000, 27.000000 }; + fp_t const e0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000, 3.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_cbrt, ts_cbrt_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cbrt_p); +} diff --git a/test/cci.c b/test/cci.c new file mode 100644 index 0000000..21fb97c --- /dev/null +++ b/test/cci.c @@ -0,0 +1,26 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_cci( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* k=3 + * TP: 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 + * SMA(3) of TP: 12, 13, 14, 15, 16, 17, 18, 19 + * MAD(3) of TP around SMA: |11-12|+|12-12|+|13-12| / 3 = 2/3 for first window + * CCI = (13 - 12) / (0.015 * 2/3) = 1 / 0.01 = 100 + * Next: SMA=13, MAD = (|12-13|+|13-13|+|14-13|)/3 = 2/3, CCI = (14-13)/(0.015*2/3) = 100 + */ + fp_t const e[] = { 100, 100, 100, 100, 100, 100, 100, 100 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_cci, ts_cci_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_cci_p); +} diff --git a/test/ceiling.c b/test/ceiling.c new file mode 100644 index 0000000..dece6c0 --- /dev/null +++ b/test/ceiling.c @@ -0,0 +1,14 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_ceiling( void ) +{ + fp_t const x0[] = { -4.4, -3.2, -2.2, -1.1, 0, 1.1, 2.2, 3.3, 4.4 }; + fp_t const e0[] = { -4, -3, -2, -1, 0, 2, 3, 4, 5 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_ceiling, ts_ceiling_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_ceiling_p); +} diff --git a/test/center_of_gravity.c b/test/center_of_gravity.c new file mode 100644 index 0000000..ee67df3 --- /dev/null +++ b/test/center_of_gravity.c @@ -0,0 +1,17 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_center_of_gravity( void ) +{ + fp_t const x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + fp_t const * const inp[1] = { x }; + + /* k=5: windows [1,2,3,4,5], [2,3,4,5,6], [3,4,5,6,7], [4,5,6,7,8] + * COG = 1 - 2*SUM(ix)/((k+1)*SUM(x)) */ + fp_t const e[] = { -0.22222, -0.16667, -0.13333, -0.11111 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 5; + return ts_test(ts_center_of_gravity, ts_center_of_gravity_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_center_of_gravity_p); +} diff --git a/test/chande_forecast_oscillator.c b/test/chande_forecast_oscillator.c new file mode 100644 index 0000000..3dad081 --- /dev/null +++ b/test/chande_forecast_oscillator.c @@ -0,0 +1,15 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_chande_forecast_oscillator( void ) +{ + fp_t const x[] = { 1, 3, 2, 5, 4, 7, 6, 8 }; + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { -25.9259259259259, -2.7777777777778, -23.0769230769231, -4.7619047619048 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 5; + return ts_test(ts_chande_forecast_oscillator, ts_chande_forecast_oscillator_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_chande_forecast_oscillator_p); +} diff --git a/test/change.c b/test/change.c new file mode 100644 index 0000000..39725e2 --- /dev/null +++ b/test/change.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_change( void ) +{ + fp_t const x0[] = { 10, 12, 14, 16, 18, 20, 22, 24 }; + fp_t const e0[] = { 60, 50, 42.8571428571429, 37.5, 33.3333333333333 }; + + fp_t const * const x[] = { x0 }; + fp_t const * const e[1] = { e0 }; + + uint_t const k = 3; + + return ts_test(ts_change, ts_change_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_change_p); +} diff --git a/test/channel.c b/test/channel.c new file mode 100644 index 0000000..edbed8f --- /dev/null +++ b/test/channel.c @@ -0,0 +1,23 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_channel( void ) +{ + fp_t const o[] = { 10, 12, 11, 14, 13, 15, 16, 14, 17, 18 }; + fp_t const h[] = { 12, 14, 13, 16, 15, 17, 18, 16, 19, 20 }; + fp_t const l[] = { 9, 11, 10, 13, 12, 14, 15, 13, 16, 17 }; + fp_t const cp[] = { 11, 13, 12, 15, 14, 16, 17, 15, 18, 19 }; + + fp_t const * const x[] = { o, h, l, cp }; + + /* k=3, offset=2, y_n=8 */ + /* HH3 starting at index 2: max(h[0..2])=14, max(h[1..3])=14, max(h[2..4])=16, max(h[3..5])=16, max(h[4..6])=17, max(h[5..7])=18, max(h[6..8])=18, max(h[7..9])=19 */ + /* LL3 starting at index 2: min(l[0..2])=10, min(l[1..3])=10, min(l[2..4])=12, min(l[3..5])=12, min(l[4..6])=14, min(l[5..7])=14, min(l[6..8])=13, min(l[7..9])=16 */ + fp_t const eu[] = { 14, 16, 16, 17, 18, 18, 19, 20 }; + fp_t const el[] = { 9, 10, 10, 12, 12, 13, 13, 13 }; + fp_t const * const exp[2] = { eu, el }; + + uint_t k = 3; + return ts_test(ts_channel, ts_channel_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_channel_p); +} diff --git a/test/chebyshev_distance.c b/test/chebyshev_distance.c new file mode 100644 index 0000000..7bce0ee --- /dev/null +++ b/test/chebyshev_distance.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_chebyshev_distance( void ) +{ + fp_t const x0[] = { 3.000000, -5.000000, 0.000000, 1.000000 }; + fp_t const x1[] = { 4.000000, 12.000000, 5.000000, -2.000000 }; + fp_t const e0[] = { 4.000000, 12.000000, 5.000000, 2.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_chebyshev_distance, ts_chebyshev_distance_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_chebyshev_distance_p); +} diff --git a/test/chebyshev_t.c b/test/chebyshev_t.c new file mode 100644 index 0000000..93ed0fb --- /dev/null +++ b/test/chebyshev_t.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_chebyshev_t( void ) +{ + fp_t const x0[] = { 0.000000, 0.500000, 1.000000, 0.700000, 0.000000, 2.000000, 2.000000, 2.000000, 1.500000, -2.000000 }; + fp_t const x1[] = { 0.000000, 1.000000, 2.000000, 3.000000, 4.000000, 0.000000, 1.000000, 2.000000, 3.000000, 2.000000 }; + fp_t const e0[] = { 1.000000, 0.500000, 1.000000, -0.728000, 1.000000, 1.000000, 2.000000, 7.000000, 9.000000, 7.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_chebyshev_t, ts_chebyshev_t_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_chebyshev_t_p); +} diff --git a/test/chi_squared_pdf.c b/test/chi_squared_pdf.c new file mode 100644 index 0000000..c2f5cdb --- /dev/null +++ b/test/chi_squared_pdf.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_chi_squared_pdf( void ) +{ + fp_t const c[] = { 3.000000 }; + + fp_t const x0[] = { 0.100000, 1.000000, 2.000000, 3.000000, 5.000000 }; + fp_t const e0[] = { 0.120004, 0.241971, 0.207554, 0.154180, 0.073225 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_chi_squared_pdf, ts_chi_squared_pdf_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_chi_squared_pdf_p); +} diff --git a/test/choppiness_index.c b/test/choppiness_index.c new file mode 100644 index 0000000..fda6520 --- /dev/null +++ b/test/choppiness_index.c @@ -0,0 +1,23 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_choppiness_index( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }; + fp_t const v[] = { 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + /* k=3, 2k=6, offset=6, H-L=3 for all bars */ + /* At xi=6: sum_range of bars 0-2 = 9, HH6 of bars 1-6 = 18, LL6 of bars 1-6 = 10, range=8 */ + /* CI = 100 * ln(9/8) / ln(3/e) = 100 * 0.11778 / 0.04931 = 238.9 */ + fp_t const e[] = { 10.72107, 10.72107, 10.72107, 10.72107, 10.72107, 10.72107, 10.72107, 10.72107, 10.72107, 10.72107, 10.72107, 10.72107, 10.72107, 10.72107 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_choppiness_index, ts_choppiness_index_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_choppiness_index_p); +} diff --git a/test/close_minus_open.c b/test/close_minus_open.c new file mode 100644 index 0000000..c6030e3 --- /dev/null +++ b/test/close_minus_open.c @@ -0,0 +1,17 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_close_minus_open( void ) +{ + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const x1[] = { 2, 3, 4, 5, 6 }; + fp_t const x2[] = { 0, 1, 2, 3, 4 }; + fp_t const x3[] = { 3, 5, 7, 9, 11 }; + fp_t const x4[] = { 1, 1, 1, 1, 1 }; + fp_t const e0[] = { 2, 3, 4, 5, 6 }; + + fp_t const * const x[] = { x0, x1, x2, x3, x4 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_close_minus_open, ts_close_minus_open_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_close_minus_open_p); +} diff --git a/test/close_to_high.c b/test/close_to_high.c new file mode 100644 index 0000000..295eb92 --- /dev/null +++ b/test/close_to_high.c @@ -0,0 +1,17 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_close_to_high( void ) +{ + fp_t const x0[] = { 1, 1, 1, 1, 1 }; + fp_t const x1[] = { 4, 6, 8, 10, 12 }; + fp_t const x2[] = { 0, 2, 4, 6, 8 }; + fp_t const x3[] = { 2, 4, 6, 8, 10 }; + fp_t const x4[] = { 1, 1, 1, 1, 1 }; + fp_t const e0[] = { 0.5, 0.5, 0.5, 0.5, 0.5 }; + + fp_t const * const x[] = { x0, x1, x2, x3, x4 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_close_to_high, ts_close_to_high_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_close_to_high_p); +} diff --git a/test/close_to_open_ratio.c b/test/close_to_open_ratio.c new file mode 100644 index 0000000..a636186 --- /dev/null +++ b/test/close_to_open_ratio.c @@ -0,0 +1,17 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_close_to_open_ratio( void ) +{ + fp_t const x0[] = { 2, 4, 6, 8, 10 }; + fp_t const x1[] = { 3, 5, 7, 9, 11 }; + fp_t const x2[] = { 1, 3, 5, 7, 9 }; + fp_t const x3[] = { 4, 8, 12, 16, 20 }; + fp_t const x4[] = { 1, 1, 1, 1, 1 }; + fp_t const e0[] = { 2, 2, 2, 2, 2 }; + + fp_t const * const x[] = { x0, x1, x2, x3, x4 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_close_to_open_ratio, ts_close_to_open_ratio_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_close_to_open_ratio_p); +} diff --git a/test/cmf.c b/test/cmf.c new file mode 100644 index 0000000..66b4c3f --- /dev/null +++ b/test/cmf.c @@ -0,0 +1,41 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_cmf( void ) +{ + uint_t k = TS_TEST_K; + + fp_t const o[] = { 10, 11, 12, 11, 12, 10, 11, 13, 12, 14 }; + fp_t const h[] = { 12, 13, 14, 12, 14, 11, 12, 15, 14, 16 }; + fp_t const l[] = { 8, 9, 10, 9, 10, 9, 10, 11, 10, 12 }; + fp_t const c[] = { 11, 12, 10, 11, 11, 10, 12, 14, 13, 15 }; + fp_t const v[] = { 100, 200, 300, 400, 500, 300, 200, 400, 300, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t mf_vals[10] = { 0 }; + for( uint_t i = 0; i < 10; ++i ) + { + fp_t hl = h[i] - l[i]; + mf_vals[i] = hl != 0 ? ( ( c[i] - l[i] ) - ( h[i] - c[i] ) ) / hl * v[i] : 0; + } + + fp_t e[6] = { 0 }; + for( uint_t i = k - 1; i < 10; ++i ) + { + fp_t sum_mf = 0; + fp_t sum_v = 0; + for( uint_t j = 0; j < k; ++j ) + { + uint_t idx = i - k + 1 + j; + sum_mf += mf_vals[idx]; + sum_v += v[idx]; + } + e[i - k + 1] = sum_v != 0 ? sum_mf / sum_v : 0; + } + fp_t const * const e_arr[1] = { e }; + + uint_t c_val = k; + + return ts_test(ts_cmf, ts_cmf_offset, x, e_arr, 10, (ts_constant_t *)&c_val, &ts_cmf_p); +} diff --git a/test/cmo.c b/test/cmo.c new file mode 100644 index 0000000..00fdb66 --- /dev/null +++ b/test/cmo.c @@ -0,0 +1,25 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_cmo( void ) +{ + /* k=3, prices: 10, 12, 14, 13, 15, 16, 18, 17, 19, 20 */ + fp_t const x[] = { 10, 12, 14, 13, 15, 16, 18, 17, 19, 20 }; + + fp_t const * const inp[1] = { x }; + + /* i=1: diff=+2, i=2: diff=+2, i=3: diff=-1 */ + /* First window (i=1..3): up=2+2+0=4, down=0+0+1=1, CMO=100*(4-1)/(4+1)=60 */ + /* Slide: add i=4 diff=+2, remove i=1 diff=+2: up=4-2+2=4, down=1-0+0=1, CMO=60 */ + /* Slide: add i=5 diff=+1, remove i=2 diff=+2: up=4-2+1=3, down=1-0+0=1, CMO=100*(3-1)/(3+1)=50 */ + /* Slide: add i=6 diff=+2, remove i=3 diff=-1: up=3-0+2=5, down=1-1+0=0, CMO=100*(5-0)/(5+0)=100 */ + /* Slide: add i=7 diff=-1, remove i=4 diff=+2: up=5-2+0=3, down=0-0+1=1, CMO=100*(3-1)/(3+1)=50 */ + /* Slide: add i=8 diff=+2, remove i=5 diff=+1: up=3-1+2=4, down=1-0+0=1, CMO=100*(4-1)/(4+1)=60 */ + /* Slide: add i=9 diff=+1, remove i=6 diff=+2: up=4-2+1=3, down=1-0+0=1, CMO=50 */ + fp_t const e[] = { 60, 60, 50, 100, 50, 60, 50 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_cmo, ts_cmo_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_cmo_p); +} diff --git a/test/coppock_curve.c b/test/coppock_curve.c new file mode 100644 index 0000000..48239e4 --- /dev/null +++ b/test/coppock_curve.c @@ -0,0 +1,26 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_coppock_curve( void ) +{ + fp_t const x[] = { 100, 105, 98, 110, 102, 115, 108, 120, 106, 112, 118, 99, 113, 107, 121, 114, 109, 116, 103, 111, 119, 104, 117, 108, 122, 110, 115, 107, 121, 105 }; + + fp_t const * const inp[1] = { x }; + + /* + * Coppock = expanding WMA(ROC(14) + ROC(11)), full WMA(10) from idx 9, + * then rolling WMA(10). ROC(k) = (x[i] - x[i-k]) / x[i-k] * 100. + * WMA weights: most recent value gets highest weight. + * Offset = 14, first output at index 14. + */ + fp_t const e[] = { + 31.00000000, 27.44537815, 23.27989457, 20.98845532, 17.79356430, + 15.48386172, 14.28049689, 12.48191637, 11.72007206, 10.86293252, + 6.25323376, 3.24940269, 2.78976008, 0.81656550, 3.89753260, + 4.22501503 + }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_coppock_curve, ts_coppock_curve_offset, inp, exp, 30, (ts_constant_t *)NULL, &ts_coppock_curve_p); +} diff --git a/test/copysign.c b/test/copysign.c new file mode 100644 index 0000000..cab7a99 --- /dev/null +++ b/test/copysign.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_copysign( void ) +{ + fp_t const x0[] = { 1.000000, 2.000000, 3.000000, 4.000000 }; + fp_t const x1[] = { 1.000000, -1.000000, 1.000000, -1.000000 }; + fp_t const e0[] = { 1.000000, -2.000000, 3.000000, -4.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_copysign, ts_copysign_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_copysign_p); +} diff --git a/test/correlation_coefficient.c b/test/correlation_coefficient.c new file mode 100644 index 0000000..f1054d0 --- /dev/null +++ b/test/correlation_coefficient.c @@ -0,0 +1,16 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_correlation_coefficient( void ) +{ + fp_t const x0[] = { 1, 2, 3, 4, 5, 6, 7 }; + fp_t const x1[] = { 2, 4, 6, 8, 10, 12, 14 }; + fp_t const e0[] = { 1, 1, 1, 1, 1 }; + + fp_t const * const x[] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + uint_t k = 3; + + return ts_test(ts_correlation_coefficient, ts_correlation_coefficient_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_correlation_coefficient_p); +} diff --git a/test/cosecant.c b/test/cosecant.c new file mode 100644 index 0000000..1ebe741 --- /dev/null +++ b/test/cosecant.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_cosecant( void ) +{ + fp_t const x0[] = { 0.5, 1.0, 1.5, 2.0, 2.5 }; + fp_t const e0[] = { 2.085830, 1.188395, 1.002511, 1.099750, 1.670922 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_cosecant, ts_cosecant_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cosecant_p); +} diff --git a/test/cosecant_hyperbolic.c b/test/cosecant_hyperbolic.c new file mode 100644 index 0000000..e6426a3 --- /dev/null +++ b/test/cosecant_hyperbolic.c @@ -0,0 +1,9 @@ +#include <stddef.h> +#include "ts.h" +bool ts_test_cosecant_hyperbolic( void ) { + fp_t const x0[] = { 0.5, 1.0, 1.5, 2.0, 2.5 }; + fp_t const e0[] = { 1.919035, 0.850918, 0.469642, 0.275721, 0.165284 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_cosecant_hyperbolic, ts_cosecant_hyperbolic_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cosecant_hyperbolic_p); +} diff --git a/test/cosecant_hyperbolic_inverse.c b/test/cosecant_hyperbolic_inverse.c new file mode 100644 index 0000000..3b4fea9 --- /dev/null +++ b/test/cosecant_hyperbolic_inverse.c @@ -0,0 +1,9 @@ +#include <stddef.h> +#include "ts.h" +bool ts_test_cosecant_hyperbolic_inverse( void ) { + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 0.881374, 0.481212, 0.327450, 0.247466, 0.198690 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_cosecant_hyperbolic_inverse, ts_cosecant_hyperbolic_inverse_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cosecant_hyperbolic_inverse_p); +} diff --git a/test/cosecant_inverse.c b/test/cosecant_inverse.c new file mode 100644 index 0000000..02c0a2a --- /dev/null +++ b/test/cosecant_inverse.c @@ -0,0 +1,9 @@ +#include <stddef.h> +#include "ts.h" +bool ts_test_cosecant_inverse( void ) { + fp_t const x0[] = { 2, 3, 4, 5, 10 }; + fp_t const e0[] = { 0.523599, 0.339837, 0.252680, 0.201358, 0.100167 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_cosecant_inverse, ts_cosecant_inverse_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cosecant_inverse_p); +} diff --git a/test/cosine.c b/test/cosine.c new file mode 100644 index 0000000..6dac0cf --- /dev/null +++ b/test/cosine.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_cosine( void ) +{ + fp_t const x0[] = { 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0 }; + fp_t const e0[] = { 1.000000, 0.877583, 0.540302, 0.070737, -0.416147, -0.801144, -0.989992, -0.936457, -0.653644 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_cosine, ts_cosine_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cosine_p); +} diff --git a/test/cosine_hyperbolic.c b/test/cosine_hyperbolic.c new file mode 100644 index 0000000..02cb98a --- /dev/null +++ b/test/cosine_hyperbolic.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_cosine_hyperbolic( void ) +{ + fp_t const x0[] = { 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0 }; + fp_t const e0[] = { 1.000000, 1.127626, 1.543081, 2.352410, 3.762196, 6.132289, 10.067662, 16.572825, 27.308233 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_cosine_hyperbolic, ts_cosine_hyperbolic_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cosine_hyperbolic_p); +} diff --git a/test/cosine_inverse.c b/test/cosine_inverse.c new file mode 100644 index 0000000..8a16df6 --- /dev/null +++ b/test/cosine_inverse.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_cosine_inverse( void ) +{ + fp_t const x0[] = { 0, 0.25, 0.5, 0.75, 1.0 }; + fp_t const e0[] = { 1.570796, 1.318116, 1.047198, 0.722734, 0 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_cosine_inverse, ts_cosine_inverse_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cosine_inverse_p); +} diff --git a/test/cosine_similarity.c b/test/cosine_similarity.c new file mode 100644 index 0000000..1fb36b9 --- /dev/null +++ b/test/cosine_similarity.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_cosine_similarity( void ) +{ + fp_t const x0[] = { 3.000000, 0.000000, 1.000000, -1.000000 }; + fp_t const x1[] = { 4.000000, 0.000000, 1.000000, 1.000000 }; + fp_t const e0[] = { 1.000000, 0.000000, 1.000000, -1.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_cosine_similarity, ts_cosine_similarity_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cosine_similarity_p); +} diff --git a/test/cotangent.c b/test/cotangent.c new file mode 100644 index 0000000..33634c5 --- /dev/null +++ b/test/cotangent.c @@ -0,0 +1,9 @@ +#include <stddef.h> +#include "ts.h" +bool ts_test_cotangent( void ) { + fp_t const x0[] = { 0.5, 1.0, 1.5, 2.0, 2.5 }; + fp_t const e0[] = { 1.830488, 0.642093, 0.070915, -0.457658, -1.338648 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_cotangent, ts_cotangent_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cotangent_p); +} diff --git a/test/cotangent_hyperbolic.c b/test/cotangent_hyperbolic.c new file mode 100644 index 0000000..b7963a4 --- /dev/null +++ b/test/cotangent_hyperbolic.c @@ -0,0 +1,9 @@ +#include <stddef.h> +#include "ts.h" +bool ts_test_cotangent_hyperbolic( void ) { + fp_t const x0[] = { 0.5, 1.0, 1.5, 2.0, 2.5 }; + fp_t const e0[] = { 2.163953, 1.313035, 1.104791, 1.037315, 1.013567 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_cotangent_hyperbolic, ts_cotangent_hyperbolic_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cotangent_hyperbolic_p); +} diff --git a/test/cotangent_hyperbolic_inverse.c b/test/cotangent_hyperbolic_inverse.c new file mode 100644 index 0000000..6fbddff --- /dev/null +++ b/test/cotangent_hyperbolic_inverse.c @@ -0,0 +1,9 @@ +#include <stddef.h> +#include "ts.h" +bool ts_test_cotangent_hyperbolic_inverse( void ) { + fp_t const x0[] = { 2, 3, 4, 5, 10 }; + fp_t const e0[] = { 0.549306, 0.346574, 0.255413, 0.202733, 0.100335 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_cotangent_hyperbolic_inverse, ts_cotangent_hyperbolic_inverse_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cotangent_hyperbolic_inverse_p); +} diff --git a/test/cotangent_inverse.c b/test/cotangent_inverse.c new file mode 100644 index 0000000..86a1287 --- /dev/null +++ b/test/cotangent_inverse.c @@ -0,0 +1,9 @@ +#include <stddef.h> +#include "ts.h" +bool ts_test_cotangent_inverse( void ) { + fp_t const x0[] = { -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 2.944197, 2.896614, 2.819842, 2.677945, 2.356194, 1.570796, 0.785398, 0.463648, 0.321751, 0.244979, 0.197396 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_cotangent_inverse, ts_cotangent_inverse_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cotangent_inverse_p); +} diff --git a/test/crossover.c b/test/crossover.c new file mode 100644 index 0000000..3aa8f0f --- /dev/null +++ b/test/crossover.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_crossover( void ) +{ + fp_t const x0[] = { 1, 2, 4, 5, 4, 2, 1 }; + fp_t const x1[] = { 3, 3, 3, 3, 3, 3, 3 }; + fp_t const e0[] = { 0, 1, 0, 0, -1, 0 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_crossover, ts_crossover_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_crossover_p); +} diff --git a/test/cumulative_product.c b/test/cumulative_product.c new file mode 100644 index 0000000..3ae6708 --- /dev/null +++ b/test/cumulative_product.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_cumulative_product( void ) +{ + fp_t const x0[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + fp_t const e0[] = { 1, 2, 6, 24, 120, 720, 5040, 40320 }; + + fp_t const * const x[] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_cumulative_product, ts_cumulative_product_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cumulative_product_p); +} diff --git a/test/cumulative_sum.c b/test/cumulative_sum.c new file mode 100644 index 0000000..828ef20 --- /dev/null +++ b/test/cumulative_sum.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_cumulative_sum( void ) +{ + fp_t const x0[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + fp_t const e0[] = { 1, 3, 6, 10, 15, 21, 28, 36 }; + + fp_t const * const x[] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_cumulative_sum, ts_cumulative_sum_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_cumulative_sum_p); +} diff --git a/test/cumulative_volume_delta.c b/test/cumulative_volume_delta.c new file mode 100644 index 0000000..024b8b5 --- /dev/null +++ b/test/cumulative_volume_delta.c @@ -0,0 +1,27 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_cumulative_volume_delta( void ) +{ + fp_t const o[] = { 10, 11, 12, 11, 12, 10, 11, 13, 12, 14 }; + fp_t const h[] = { 12, 13, 14, 12, 14, 11, 12, 15, 14, 16 }; + fp_t const l[] = { 8, 9, 10, 9, 10, 9, 10, 11, 10, 12 }; + fp_t const c[] = { 11, 12, 10, 11, 11, 10, 12, 14, 13, 15 }; + fp_t const v[] = { 100, 200, 300, 400, 500, 300, 200, 400, 300, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t e[10] = { 0 }; + fp_t cum = 0; + for( uint_t i = 0; i < 10; ++i ) + { + fp_t diff = c[i] - o[i]; + fp_t sign = ( diff > 0 ) ? 1.0 : ( diff < 0 ) ? -1.0 : 0.0; + cum += v[i] * sign; + e[i] = cum; + } + + fp_t const * const e_arr[1] = { e }; + + return ts_test(ts_cumulative_volume_delta, ts_cumulative_volume_delta_offset, x, e_arr, 10, (ts_constant_t *)NULL, &ts_cumulative_volume_delta_p); +} diff --git a/test/cv.c b/test/cv.c new file mode 100644 index 0000000..2c41604 --- /dev/null +++ b/test/cv.c @@ -0,0 +1,25 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_cv( void ) +{ + fp_t const o[] = { 10, 11, 12, 11, 12, 13, 14, 13, 14, 15, 14 }; + fp_t const h[] = { 12, 13, 14, 12, 14, 15, 16, 14, 16, 17, 16 }; + fp_t const l[] = { 8, 9, 10, 9, 10, 11, 12, 11, 12, 13, 12 }; + fp_t const c[] = { 11, 12, 10, 11, 11, 14, 15, 13, 15, 16, 15 }; + fp_t const v[] = { 100, 200, 300, 400, 500, 150, 250, 350, 450, 550, 650 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t fast = 3; + fp_t slow = 5; + + + fp_t e[] = { -0.020148, 0.003635, -0.117257, -0.040582, 0.003017, 0.026068 }; + + fp_t const * const e_arr[1] = { e }; + + fp_t constants[2] = { fast, slow }; + + return ts_test(ts_cv, ts_cv_offset, x, e_arr, 11, (ts_constant_t *)constants, &ts_cv_p); +} diff --git a/test/darvas_box.c b/test/darvas_box.c new file mode 100644 index 0000000..af5e857 --- /dev/null +++ b/test/darvas_box.c @@ -0,0 +1,23 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_darvas_box( void ) +{ + fp_t const o[] = { 10, 12, 11, 14, 13, 15, 16, 14, 17, 18 }; + fp_t const h[] = { 12, 14, 13, 16, 15, 17, 18, 16, 19, 20 }; + fp_t const l[] = { 9, 11, 10, 13, 12, 14, 15, 13, 16, 17 }; + fp_t const cp[] = { 11, 13, 12, 15, 14, 16, 17, 15, 18, 19 }; + + fp_t const * const x[] = { o, h, l, cp }; + + /* k=3, offset=2, y_n=8 */ + /* HH3 starting at index 2: 14, 14, 16, 16, 17, 18, 18, 19 */ + /* LL3 starting at index 2: 10, 10, 12, 12, 14, 14, 13, 16 */ + fp_t const et[] = { 14, 16, 16, 17, 18, 18, 19, 20 }; + fp_t const eb[] = { 9, 10, 10, 12, 12, 13, 13, 13 }; + fp_t const * const exp[2] = { et, eb }; + + uint_t k = 3; + return ts_test(ts_darvas_box, ts_darvas_box_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_darvas_box_p); +} diff --git a/test/dawsn.c b/test/dawsn.c new file mode 100644 index 0000000..2e4e482 --- /dev/null +++ b/test/dawsn.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_dawsn( void ) +{ + fp_t const x0[] = { 0.000000, 0.250000, 0.500000, 1.000000, -1.000000, 2.000000 }; + fp_t const e0[] = { 0.000000, 0.239839, 0.424436, 0.538080, -0.538080, 0.301340 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_dawsn, ts_dawsn_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_dawsn_p); +} diff --git a/test/decay_exponential.c b/test/decay_exponential.c new file mode 100644 index 0000000..363dbed --- /dev/null +++ b/test/decay_exponential.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_decay_exponential( void ) +{ + uint_t const c[] = { 3 }; + + fp_t const x0[] = { 5, 3, 4, 2, 6, 1 }; + fp_t const e0[] = { 2.666666666666667, 6, 4 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_decay_exponential, ts_decay_exponential_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_decay_exponential_p); +} diff --git a/test/decay_linear.c b/test/decay_linear.c new file mode 100644 index 0000000..24d0adf --- /dev/null +++ b/test/decay_linear.c @@ -0,0 +1,14 @@ +#include "ts.h" + +bool ts_test_decay_linear( void ) +{ + uint_t const c[] = { 3 }; + + fp_t const x0[] = { 6, 3, 4, 2, 6, 1 }; + fp_t const e0[] = { 2.66667, 6.0, 4.0 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_decay_linear, ts_decay_linear_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_decay_linear_p); +} diff --git a/test/degree_radian.c b/test/degree_radian.c new file mode 100644 index 0000000..7570121 --- /dev/null +++ b/test/degree_radian.c @@ -0,0 +1,14 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_degree_radian( void ) +{ + fp_t const x[] = { 0, 30, 45, 60, 90, 180, 270, 360 }; + fp_t const e[] = { 0, PI / 6, PI / 4, PI / 3, HALF_PI, PI, 3 * HALF_PI, 2 * PI }; + + fp_t const * const inp[1] = { x }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_degree_radian, ts_degree_radian_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)NULL, &ts_degree_radian_p); +} diff --git a/test/delta.c b/test/delta.c new file mode 100644 index 0000000..d4856a6 --- /dev/null +++ b/test/delta.c @@ -0,0 +1,16 @@ +#include <stddef.h> +#include <stdio.h> +#include <tgmath.h> +#include "ts.h" + +bool ts_test_delta( void ) +{ + fp_t x0[] = { -4, -3, -2, -1, 0, 1, 2, 3, 4 }; + fp_t e0[] = { 3, 3, 3, 3, 3, 3 }; + + fp_t const * const x[] = { x0 }; + fp_t const * const e[] = { e0 }; + uint_t const c[] = { 3 }; + + return ts_test(ts_delta, ts_delta_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)c, &ts_delta_p); +} diff --git a/test/deviation_average.c b/test/deviation_average.c new file mode 100644 index 0000000..29bdab3 --- /dev/null +++ b/test/deviation_average.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_deviation_average( void ) +{ + uint_t const c[] = { 3 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 0.666667, 0.666667, 0.666667 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_deviation_average, ts_deviation_average_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_deviation_average_p); +} diff --git a/test/deviation_standard.c b/test/deviation_standard.c new file mode 100644 index 0000000..e4cedb2 --- /dev/null +++ b/test/deviation_standard.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_deviation_standard( void ) +{ + uint_t const c[] = { 3 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 0.816497, 0.816497, 0.816497 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_deviation_standard, ts_deviation_standard_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_deviation_standard_p); +} diff --git a/test/deviation_standard_average_exponential.c b/test/deviation_standard_average_exponential.c new file mode 100644 index 0000000..b5aa625 --- /dev/null +++ b/test/deviation_standard_average_exponential.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_deviation_standard_average_exponential( void ) +{ + fp_t const c[] = { 0.5 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 1.000000, 0.707107, 1.172604, 1.489547, 1.693277 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_deviation_standard_average_exponential, ts_deviation_standard_average_exponential_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_deviation_standard_average_exponential_p); +} diff --git a/test/deviation_vector.c b/test/deviation_vector.c new file mode 100644 index 0000000..8e4e2c6 --- /dev/null +++ b/test/deviation_vector.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_deviation_vector( void ) +{ + uint_t const c[] = { 3 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 0.816497, 0.816497, 0.816497 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_deviation_vector, ts_deviation_vector_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_deviation_vector_p); +} diff --git a/test/di_minus.c b/test/di_minus.c new file mode 100644 index 0000000..35d2545 --- /dev/null +++ b/test/di_minus.c @@ -0,0 +1,20 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_di_minus( void ) +{ + fp_t const o[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; + fp_t const h[] = { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3 }; + fp_t const l[] = { 8, 6, 4, 2, 0, -2, -4, -6, -8,-10 }; + fp_t const c[] = { 11, 10, 9, 8, 7, 6, 5, 4, 3, 2 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* k=3, -DM=2 each period, +DM=0 => -DI = 100*EMA(-DM)/(EMA(-DM)+EMA(+DM)) */ + fp_t const e[] = { 100., 100., 100., 100., 100., 100., 100. }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_di_minus, ts_di_minus_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_di_minus_p); +} diff --git a/test/di_plus.c b/test/di_plus.c new file mode 100644 index 0000000..f8667fb --- /dev/null +++ b/test/di_plus.c @@ -0,0 +1,20 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_di_plus( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* k=3, +DM=1 (H increases by 1 each bar), -DM=0, +DI = 100*EMA(+DM)/(EMA(+DM)+EMA(-DM)) = 100 */ + fp_t const e[] = { 100, 100, 100, 100, 100, 100, 100 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_di_plus, ts_di_plus_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_di_plus_p); +} diff --git a/test/digamma.c b/test/digamma.c new file mode 100644 index 0000000..c9e221c --- /dev/null +++ b/test/digamma.c @@ -0,0 +1,11 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_digamma( void ) +{ + fp_t const x0[] = { 10.000000, 15.000000, 20.000000, 50.000000, 100.000000 }; + fp_t const e0[] = { 2.2517525891, 2.6743466617, 2.9705239922, 3.9019896734, 4.6001618527 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_digamma, ts_digamma_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_digamma_p); +} diff --git a/test/disparity_index.c b/test/disparity_index.c new file mode 100644 index 0000000..1860f8f --- /dev/null +++ b/test/disparity_index.c @@ -0,0 +1,27 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_disparity_index( void ) +{ + fp_t const x0[] = { 10, 10, 10, 10, 15, 15, 15 }; + fp_t const * const x[] = { x0 }; + + uint_t k = 3; + + fp_t sma = (10 + 10 + 10) / 3.0; + fp_t e[5] = { 0 }; + e[0] = (10 - sma) / sma * 100; + sma = sma + (10 - 10) / 3.0; + e[1] = (10 - sma) / sma * 100; + sma = sma + (15 - 10) / 3.0; + e[2] = (15 - sma) / sma * 100; + sma = sma + (15 - 10) / 3.0; + e[3] = (15 - sma) / sma * 100; + sma = sma + (15 - 10) / 3.0; + e[4] = (15 - sma) / sma * 100; + + fp_t const * const exp[1] = { e }; + + return ts_test(ts_disparity_index, ts_disparity_index_offset, x, exp, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_disparity_index_p); +} diff --git a/test/distance.c b/test/distance.c new file mode 100644 index 0000000..c8466b7 --- /dev/null +++ b/test/distance.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_distance( void ) +{ + fp_t const x0[] = { 3.000000, 5.000000, 0.000000, 1.000000 }; + fp_t const x1[] = { 4.000000, 12.000000, 5.000000, 0.000000 }; + fp_t const e0[] = { 5.000000, 13.000000, 5.000000, 1.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_distance, ts_distance_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_distance_p); +} diff --git a/test/division.c b/test/division.c new file mode 100644 index 0000000..7442b53 --- /dev/null +++ b/test/division.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include <math.h> +#include "ts.h" + +bool ts_test_division( void ) +{ + fp_t const x0[] = { 10, 8, 6, 4 }; + fp_t const x1[] = { 2, 4, 3, 1 }; + fp_t const e0[] = { 5, 2, 2, 4 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_division, ts_division_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_division_p); +} diff --git a/test/donchian_channel.c b/test/donchian_channel.c new file mode 100644 index 0000000..4ada2d0 --- /dev/null +++ b/test/donchian_channel.c @@ -0,0 +1,26 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_donchian_channel( void ) +{ + fp_t const o[] = { 10, 12, 11, 14, 13, 15, 16, 14, 17, 18 }; + fp_t const h[] = { 12, 14, 13, 16, 15, 17, 18, 16, 19, 20 }; + fp_t const l[] = { 9, 11, 10, 13, 12, 14, 15, 13, 16, 17 }; + fp_t const c[] = { 11, 13, 12, 15, 14, 16, 17, 15, 18, 19 }; + fp_t const v[] = { 100, 200, 150, 180, 160, 190, 210, 170, 200, 220 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + /* k=3, offset=2, y_n=8 */ + /* HH3 at index 2..9: 14, 14, 16, 16, 17, 18, 18, 19 */ + /* LL3 at index 2..9: 10, 10, 12, 12, 14, 14, 13, 16 */ + /* Mid: 12, 12, 14, 14, 15.5, 16, 15.5, 17.5 */ + fp_t const eu[] = { 14, 16, 16, 17, 18, 18, 19, 20 }; + fp_t const el[] = { 9, 10, 10, 12, 12, 13, 13, 13 }; + fp_t const em[] = { 11.5, 13.0, 13.0, 14.5, 15.0, 15.5, 16.0, 16.5 }; + fp_t const * const exp[3] = { eu, el, em }; + + uint_t k = 3; + return ts_test(ts_donchian_channel, ts_donchian_channel_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_donchian_channel_p); +} diff --git a/test/donchian_width.c b/test/donchian_width.c new file mode 100644 index 0000000..ead859f --- /dev/null +++ b/test/donchian_width.c @@ -0,0 +1,21 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_donchian_width( void ) +{ + fp_t const o[] = { 10, 12, 11, 14, 13, 15, 16, 14, 17, 18 }; + fp_t const h[] = { 12, 14, 13, 16, 15, 17, 18, 16, 19, 20 }; + fp_t const l[] = { 9, 11, 10, 13, 12, 14, 15, 13, 16, 17 }; + fp_t const c[] = { 11, 13, 12, 15, 14, 16, 17, 15, 18, 19 }; + fp_t const v[] = { 100, 200, 150, 180, 160, 190, 210, 170, 200, 220 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + /* Width = HH3 - LL3 at index 2..9: 4, 4, 4, 4, 3, 4, 5, 3 */ + fp_t const e[] = { 5, 6, 6, 5, 6, 5, 6, 7 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_donchian_width, ts_donchian_width_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_donchian_width_p); +} diff --git a/test/dpo.c b/test/dpo.c new file mode 100644 index 0000000..e6e4560 --- /dev/null +++ b/test/dpo.c @@ -0,0 +1,24 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_dpo( void ) +{ + fp_t const x[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + fp_t const * const inp[1] = { x }; + + /* k=4, offset=3 */ + /* SMA4: 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5 */ + /* DPO[3] = close[3] - SMA4[0] = 4 - 2.5 = 1.5 */ + /* DPO[4] = close[4] - SMA4[1] = 5 - 3.5 = 1.5 */ + /* ... all 1.5 */ + + fp_t const e[] = { 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5 }; + + fp_t const * const exp[1] = { e }; + + uint_t c_val = 4; + + return ts_test(ts_dpo, ts_dpo_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&c_val, &ts_dpo_p); +} diff --git a/test/dx.c b/test/dx.c new file mode 100644 index 0000000..f5ee94c --- /dev/null +++ b/test/dx.c @@ -0,0 +1,22 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_dx( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* k=3, all bars identical pattern */ + /* +DM=2, -DM=0, TR=3, EMA values stable at 2, 0, 3 */ + /* +DI=66.667, -DI=0, DX=100 */ + fp_t const e[] = { 100, 100, 100, 100, 100, 100, 100 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_dx, ts_dx_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_dx_p); +} diff --git a/test/ease_of_movement.c b/test/ease_of_movement.c new file mode 100644 index 0000000..fbe2e35 --- /dev/null +++ b/test/ease_of_movement.c @@ -0,0 +1,43 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_ease_of_movement( void ) +{ + uint_t k = 3; + + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + fp_t const v[] = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t eom[10] = { 0 }; + for( uint_t i = 1; i < 10; ++i ) + { + fp_t hl = h[i] - l[i]; + if( hl == 0 ) continue; + fp_t br = v[i] / hl; + if( br == 0 ) continue; + fp_t cur_mid = ( h[i] + l[i] ) / 2.0; + fp_t prev_mid = ( h[i - 1] + l[i - 1] ) / 2.0; + eom[i] = ( cur_mid - prev_mid ) / br; + } + + fp_t e[7] = { 0 }; + { + fp_t sum = eom[1] + eom[2] + eom[3]; + e[0] = sum / (fp_t)k; + for( uint_t i = k + 1; i < 10; ++i ) + { + sum = sum - eom[i - k] + eom[i]; + e[i - k] = sum / (fp_t)k; + } + } + + fp_t const * const e_arr[1] = { e }; + uint_t c_val = k; + + return ts_test(ts_ease_of_movement, ts_ease_of_movement_offset, x, e_arr, 10, (ts_constant_t *)&c_val, &ts_ease_of_movement_p); +} diff --git a/test/edge_cases.c b/test/edge_cases.c new file mode 100644 index 0000000..ce47f72 --- /dev/null +++ b/test/edge_cases.c @@ -0,0 +1,324 @@ +#include <math.h> +#include <stdbool.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_edge_cases( void ) +{ + bool result = true; + + /* === NULL input === */ + + /* average with NULL input should return -1 */ + { + uint_t k = 3; + int ret = ts_average(NULL, 0, NULL, 0, 5, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* rsi with NULL input should return -1 */ + { + uint_t k = 3; + int ret = ts_rsi(NULL, 0, NULL, 0, 5, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* === n = 0 (empty input) === */ + + /* average with n=0 should return early, no crash */ + { + uint_t k = 3; + int ret = ts_average(NULL, 0, NULL, 0, 0, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* rsi with n=0 should not crash */ + { + uint_t k = 3; + int ret = ts_rsi(NULL, 0, NULL, 0, 0, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* deviation_standard with n=0 should return early */ + { + uint_t k = 3; + int ret = ts_deviation_standard(NULL, 0, NULL, 0, 0, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* variance with n=0 should return early */ + { + uint_t k = 3; + int ret = ts_variance(NULL, 0, NULL, 0, 0, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* === n = 1 (single element) === */ + + /* average with n=1, k=1 should produce the element itself */ + { + fp_t const x[] = {5}; + fp_t const e[] = {5}; + fp_t const * const inp[1] = {x}; + fp_t const * const exp[1] = {e}; + uint_t k = 1; + result &= ts_test(ts_average, ts_average_offset, inp, exp, 1, (ts_constant_t *)&k, &ts_average_p); + } + + /* deviation_standard with n=1, k=1 should produce 0 */ + { + fp_t const x[] = {5}; + fp_t const e[] = {0}; + fp_t const * const inp[1] = {x}; + fp_t const * const exp[1] = {e}; + uint_t k = 1; + result &= ts_test(ts_deviation_standard, ts_deviation_standard_offset, inp, exp, 1, (ts_constant_t *)&k, &ts_deviation_standard_p); + } + + /* variance with n=1, k=1 should produce 0 */ + { + fp_t const x[] = {5}; + fp_t const e[] = {0}; + fp_t const * const inp[1] = {x}; + fp_t const * const exp[1] = {e}; + uint_t k = 1; + result &= ts_test(ts_variance, ts_variance_offset, inp, exp, 1, (ts_constant_t *)&k, &ts_variance_p); + } + + /* === k = 0 (zero period) === */ + + /* average with k=0 should return early */ + { + fp_t x[] = {1, 2, 3, 4, 5}; + fp_t y[5] = {0}; + fp_t const * const inp[1] = {x}; + fp_t * const out[1] = {y}; + uint_t k = 0; + int ret = ts_average(out, 1, inp, 1, 5, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* rsi with k=0 should return early */ + { + fp_t x[] = {1, 2, 3, 4, 5}; + fp_t y[5] = {0}; + fp_t const * const inp[1] = {x}; + fp_t * const out[1] = {y}; + uint_t k = 0; + int ret = ts_rsi(out, 1, inp, 1, 5, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* deviation_standard with k=0 should return early */ + { + fp_t x[] = {1, 2, 3, 4, 5}; + fp_t y[5] = {0}; + fp_t const * const inp[1] = {x}; + fp_t * const out[1] = {y}; + uint_t k = 0; + int ret = ts_deviation_standard(out, 1, inp, 1, 5, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* variance with k=0 should return early */ + { + fp_t x[] = {1, 2, 3, 4, 5}; + fp_t y[5] = {0}; + fp_t const * const inp[1] = {x}; + fp_t * const out[1] = {y}; + uint_t k = 0; + int ret = ts_variance(out, 1, inp, 1, 5, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* === k > n (period exceeds data) === */ + + /* average with k > n should return early */ + { + fp_t x[] = {1, 2, 3}; + fp_t y[3] = {0}; + fp_t const * const inp[1] = {x}; + fp_t * const out[1] = {y}; + uint_t k = 10; + int ret = ts_average(out, 1, inp, 1, 3, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* deviation_standard with k > n should return early */ + { + fp_t x[] = {1, 2, 3}; + fp_t y[3] = {0}; + fp_t const * const inp[1] = {x}; + fp_t * const out[1] = {y}; + uint_t k = 10; + int ret = ts_deviation_standard(out, 1, inp, 1, 3, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* variance with k > n should return early */ + { + fp_t x[] = {1, 2, 3}; + fp_t y[3] = {0}; + fp_t const * const inp[1] = {x}; + fp_t * const out[1] = {y}; + uint_t k = 10; + int ret = ts_variance(out, 1, inp, 1, 3, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* === All-zero input === */ + + /* average with all-zero input should produce zeros */ + { + fp_t const x[] = {0, 0, 0, 0, 0}; + fp_t const e[] = {0, 0, 0}; + fp_t const * const inp[1] = {x}; + fp_t const * const exp[1] = {e}; + uint_t k = 3; + result &= ts_test(ts_average, ts_average_offset, inp, exp, 5, (ts_constant_t *)&k, &ts_average_p); + } + + /* rsi with all-zero input should not crash (all gains/losses are 0) */ + { + fp_t const x[] = {0, 0, 0, 0, 0, 0, 0}; + fp_t const e[] = {100, 100, 100, 100, 100}; + fp_t const * const inp[1] = {x}; + fp_t const * const exp[1] = {e}; + uint_t k = 2; + result &= ts_test(ts_rsi, ts_rsi_offset, inp, exp, 7, (ts_constant_t *)&k, &ts_rsi_p); + } + + /* deviation_standard with all-zero input should produce 0 */ + { + fp_t const x[] = {0, 0, 0, 0, 0}; + fp_t const e[] = {0, 0, 0}; + fp_t const * const inp[1] = {x}; + fp_t const * const exp[1] = {e}; + uint_t k = 3; + result &= ts_test(ts_deviation_standard, ts_deviation_standard_offset, inp, exp, 5, (ts_constant_t *)&k, &ts_deviation_standard_p); + } + + /* variance with all-zero input should produce 0 */ + { + fp_t const x[] = {0, 0, 0, 0, 0}; + fp_t const e[] = {0, 0, 0}; + fp_t const * const inp[1] = {x}; + fp_t const * const exp[1] = {e}; + uint_t k = 3; + result &= ts_test(ts_variance, ts_variance_offset, inp, exp, 5, (ts_constant_t *)&k, &ts_variance_p); + } + + /* === All-same input (zero variance) === */ + + /* average with all-same input should produce that value */ + { + fp_t const x[] = {7, 7, 7, 7, 7}; + fp_t const e[] = {7, 7, 7}; + fp_t const * const inp[1] = {x}; + fp_t const * const exp[1] = {e}; + uint_t k = 3; + result &= ts_test(ts_average, ts_average_offset, inp, exp, 5, (ts_constant_t *)&k, &ts_average_p); + } + + /* rsi with all-same input should produce 100 (no losses) */ + { + fp_t const x[] = {5, 5, 5, 5, 5, 5, 5}; + fp_t const e[] = {100, 100, 100, 100, 100}; + fp_t const * const inp[1] = {x}; + fp_t const * const exp[1] = {e}; + uint_t k = 2; + result &= ts_test(ts_rsi, ts_rsi_offset, inp, exp, 7, (ts_constant_t *)&k, &ts_rsi_p); + } + + /* deviation_standard with all-same input should produce 0 */ + { + fp_t const x[] = {3, 3, 3, 3, 3}; + fp_t const e[] = {0, 0, 0}; + fp_t const * const inp[1] = {x}; + fp_t const * const exp[1] = {e}; + uint_t k = 3; + result &= ts_test(ts_deviation_standard, ts_deviation_standard_offset, inp, exp, 5, (ts_constant_t *)&k, &ts_deviation_standard_p); + } + + /* variance with all-same input should produce 0 */ + { + fp_t const x[] = {3, 3, 3, 3, 3}; + fp_t const e[] = {0, 0, 0}; + fp_t const * const inp[1] = {x}; + fp_t const * const exp[1] = {e}; + uint_t k = 3; + result &= ts_test(ts_variance, ts_variance_offset, inp, exp, 5, (ts_constant_t *)&k, &ts_variance_p); + } + + /* === n == k boundary === */ + + /* average with n==k should succeed (produces 1 output) */ + { + fp_t const x[] = {1, 2, 3}; + fp_t const e[] = {2}; + fp_t const * const inp[1] = {x}; + fp_t const * const exp[1] = {e}; + uint_t k = 3; + result &= ts_test(ts_average, ts_average_offset, inp, exp, 3, (ts_constant_t *)&k, &ts_average_p); + } + + /* rsi with n==k should fail (requires n > k) */ + { + fp_t x[] = {1, 2, 3}; + fp_t y[3] = {0}; + fp_t const * const inp[1] = {x}; + fp_t * const out[1] = {y}; + uint_t k = 3; + int ret = ts_rsi(out, 1, inp, 1, 3, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* === NaN input === */ + + /* average with NaN input should return -1 (invalid input) */ + { + fp_t x[] = {NAN, 1.0, 2.0, 3.0, 4.0}; + fp_t y[5] = {0}; + fp_t const * const inp[1] = {x}; + fp_t * const out[1] = {y}; + uint_t k = 3; + int ret = ts_average(out, 1, inp, 1, 5, (ts_constant_t *)&k); + result &= (ret == -1); + } + + /* === Monotonic input (RSI edge cases) === */ + + /* rsi with strictly ascending input should produce 100 */ + { + fp_t const x[] = {1, 2, 3, 4, 5, 6, 7}; + fp_t const e[] = {100, 100, 100, 100, 100}; + fp_t const * const inp[1] = {x}; + fp_t const * const exp[1] = {e}; + uint_t k = 2; + result &= ts_test(ts_rsi, ts_rsi_offset, inp, exp, 7, (ts_constant_t *)&k, &ts_rsi_p); + } + + /* rsi with strictly descending input should produce 0 */ + { + fp_t const x[] = {7, 6, 5, 4, 3, 2, 1}; + fp_t const e[] = {0, 0, 0, 0, 0}; + fp_t const * const inp[1] = {x}; + fp_t const * const exp[1] = {e}; + uint_t k = 2; + result &= ts_test(ts_rsi, ts_rsi_offset, inp, exp, 7, (ts_constant_t *)&k, &ts_rsi_p); + } + + /* === rsi with k > n === */ + + { + fp_t x[] = {1, 2, 3}; + fp_t y[3] = {0}; + fp_t const * const inp[1] = {x}; + fp_t * const out[1] = {y}; + uint_t k = 10; + int ret = ts_rsi(out, 1, inp, 1, 3, (ts_constant_t *)&k); + result &= (ret == -1); + } + + return result; +} diff --git a/test/elder_force_index.c b/test/elder_force_index.c new file mode 100644 index 0000000..7144c68 --- /dev/null +++ b/test/elder_force_index.c @@ -0,0 +1,32 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_elder_force_index( void ) +{ + uint_t k = 3; + + fp_t const o[] = { 10, 11, 12, 11, 12, 10, 11, 13, 12, 14 }; + fp_t const h[] = { 12, 13, 14, 12, 14, 11, 12, 15, 14, 16 }; + fp_t const l[] = { 8, 9, 10, 9, 10, 9, 10, 11, 10, 12 }; + fp_t const c[] = { 11, 12, 10, 11, 11, 10, 12, 14, 13, 15 }; + fp_t const v[] = { 100, 200, 300, 400, 500, 300, 200, 400, 300, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t e[9] = { + 200.0, + -66.666666666666629, + 88.888888888888914, + 59.259259259259281, + -60.493827160493808, + 93.004115226337447, + 328.669410150891622, + 119.112940100594415, + 412.741960067062905 + }; + + fp_t const * const e_arr[1] = { e }; + uint_t c_val = k; + + return ts_test(ts_elder_force_index, ts_elder_force_index_offset, x, e_arr, 10, (ts_constant_t *)&c_val, &ts_elder_force_index_p); +} diff --git a/test/elder_impulse.c b/test/elder_impulse.c new file mode 100644 index 0000000..95e2c28 --- /dev/null +++ b/test/elder_impulse.c @@ -0,0 +1,22 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_elder_impulse( void ) +{ + /* k=3, offset=5 */ + fp_t const x[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + + fp_t const * const inp[1] = { x }; + + /* k=3, offset=4, y_n=6 */ + /* SMA(3): 11, 12, 13, 14, 15, 16, 17, 18 */ + /* Osc: 1, 1, 1, 1, 1, 1, 1, 1 */ + /* Signal (offset=4, 6 values): 1, 1, 1, 1, 1, 1 */ + fp_t const eos[] = { 1, 1, 1, 1, 1, 1 }; + fp_t const es[] = { 1, 1, 1, 1, 1, 1 }; + fp_t const * const exp[2] = { eos, es }; + + uint_t k = 3; + return ts_test(ts_elder_impulse, ts_elder_impulse_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_elder_impulse_p); +} diff --git a/test/elder_ray.c b/test/elder_ray.c new file mode 100644 index 0000000..315b0fd --- /dev/null +++ b/test/elder_ray.c @@ -0,0 +1,24 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_elder_ray( void ) +{ + /* k=2, EMA alpha=0.5 */ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const c[] = { 10, 12, 14, 13, 15, 16, 18, 17, 19, 20 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* EMA(2): 10, 11, 12.5, 12.75, 13.875, 14.9375, 16.4688, 16.7344, 17.8672, 18.9336 */ + /* Bull: 12-10=2, 13-11=2, 14-12.5=1.5, 15-12.75=2.25, 16-13.875=2.125, 17-14.9375=2.0625, 18-16.4688=1.5312, 19-16.7344=2.2656, 20-17.8672=2.1328, 21-18.9336=2.0664 */ + /* Bear: 9-10=-1, 10-11=-1, 11-12.5=-1.5, 12-12.75=-0.75, 13-13.875=-0.875, 14-14.9375=-0.9375, 15-16.4688=-1.4688, 16-16.7344=-0.7344, 17-17.8672=-0.8672, 18-18.9336=-0.9336 */ + fp_t const eb[] = { 2, 2, 1.5, 2.25, 2.125, 2.0625, 1.53125, 2.265625, 2.1328125, 2.06640625 }; + fp_t const ee[] = { -1, -1, -1.5, -0.75, -0.875, -0.9375, -1.46875, -0.734375, -0.8671875, -0.93359375 }; + fp_t const * const exp[2] = { eb, ee }; + + fp_t k = 2; + return ts_test(ts_elder_ray, ts_elder_ray_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_elder_ray_p); +} diff --git a/test/ellint_1.c b/test/ellint_1.c new file mode 100644 index 0000000..50bd242 --- /dev/null +++ b/test/ellint_1.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_ellint_1( void ) +{ + fp_t const x0[] = { 0.000000, 0.250000, 0.500000, 0.750000, 0.900000 }; + fp_t const e0[] = { 1.570796, 1.685750, 1.854075, 2.156516, 2.578092 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_ellint_1, ts_ellint_1_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_ellint_1_p); +} diff --git a/test/ellint_2.c b/test/ellint_2.c new file mode 100644 index 0000000..9036741 --- /dev/null +++ b/test/ellint_2.c @@ -0,0 +1,11 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_ellint_2( void ) +{ + fp_t const x0[] = { 0.000000, 0.250000, 0.500000, 0.750000, 0.900000 }; + fp_t const e0[] = { 1.570796, 1.681966, 1.834119, 2.088133, 2.421504 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_ellint_2, ts_ellint_2_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_ellint_2_p); +} diff --git a/test/ema_variable.c b/test/ema_variable.c new file mode 100644 index 0000000..52fa74c --- /dev/null +++ b/test/ema_variable.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_ema_variable( void ) +{ + fp_t const x0[] = { -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10 }; + fp_t const e0[] = { -10.000000, -8.333333, -6.111111, -3.703704, -1.234568, 1.255144, 3.751715, 6.250572, 8.750191 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + fp_t c = 2; + + return ts_test(ts_ema_variable, ts_ema_variable_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_ema_variable_p); +} diff --git a/test/envelope.c b/test/envelope.c new file mode 100644 index 0000000..26d0edb --- /dev/null +++ b/test/envelope.c @@ -0,0 +1,19 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_envelope( void ) +{ + fp_t const x[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const * const inp[1] = { x }; + + /* k=3, pct=0.05, SMA: 11, 12, 13, 14, 15, 16, 17, 18 */ + /* Upper = SMA*1.05, Lower = SMA*0.95 */ + fp_t const eu[] = { 11.55, 12.60, 13.65, 14.70, 15.75, 16.80, 17.85, 18.90 }; + fp_t const el[] = { 10.45, 11.40, 12.35, 13.30, 14.25, 15.20, 16.15, 17.10 }; + fp_t const * const exp[2] = { eu, el }; + + typedef struct { uint_t k; fp_t pct; } c_t; + c_t c = { .k = 3, .pct = 0.05 }; + return ts_test(ts_envelope, ts_envelope_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&c, &ts_envelope_p); +} diff --git a/test/erf.c b/test/erf.c new file mode 100644 index 0000000..dd28c62 --- /dev/null +++ b/test/erf.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_erf( void ) +{ + fp_t const x0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000 }; + fp_t const e0[] = { -0.995322, -0.842701, 0.000000, 0.842701, 0.995322 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_erf, ts_erf_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_erf_p); +} diff --git a/test/erfc.c b/test/erfc.c new file mode 100644 index 0000000..668912e --- /dev/null +++ b/test/erfc.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_erfc( void ) +{ + fp_t const x0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000 }; + fp_t const e0[] = { 1.995322, 1.842701, 1.000000, 0.157299, 0.004678 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_erfc, ts_erfc_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_erfc_p); +} diff --git a/test/euclidean_norm.c b/test/euclidean_norm.c new file mode 100644 index 0000000..475778b --- /dev/null +++ b/test/euclidean_norm.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_euclidean_norm( void ) +{ + fp_t const x0[] = { 3.000000, 5.000000, 0.000000, 1.000000 }; + fp_t const x1[] = { 4.000000, 12.000000, 5.000000, 0.000000 }; + fp_t const e0[] = { 5.000000, 13.000000, 5.000000, 1.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_euclidean_norm, ts_euclidean_norm_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_euclidean_norm_p); +} diff --git a/test/exp10.c b/test/exp10.c new file mode 100644 index 0000000..b986269 --- /dev/null +++ b/test/exp10.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_exp10( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, 2.000000, -1.000000, 3.000000 }; + fp_t const e0[] = { 1.000000, 10.000000, 100.000000, 0.100000, 1000.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_exp10, ts_exp10_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_exp10_p); +} diff --git a/test/exp10m1.c b/test/exp10m1.c new file mode 100644 index 0000000..e0f7988 --- /dev/null +++ b/test/exp10m1.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_exp10m1( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, 2.000000, -1.000000 }; + fp_t const e0[] = { 0.000000, 9.000000, 99.000000, -0.900000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_exp10m1, ts_exp10m1_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_exp10m1_p); +} diff --git a/test/exp2.c b/test/exp2.c new file mode 100644 index 0000000..bc4df6a --- /dev/null +++ b/test/exp2.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_exp2( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, 2.000000, 3.000000, 4.000000 }; + fp_t const e0[] = { 1.000000, 2.000000, 4.000000, 8.000000, 16.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_exp2, ts_exp2_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_exp2_p); +} diff --git a/test/exp2m1.c b/test/exp2m1.c new file mode 100644 index 0000000..530b334 --- /dev/null +++ b/test/exp2m1.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_exp2m1( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, 2.000000, -1.000000 }; + fp_t const e0[] = { 0.000000, 1.000000, 3.000000, -0.500000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_exp2m1, ts_exp2m1_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_exp2m1_p); +} diff --git a/test/expit.c b/test/expit.c new file mode 100644 index 0000000..cfba0d7 --- /dev/null +++ b/test/expit.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_expit( void ) +{ + fp_t const x0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000 }; + fp_t const e0[] = { 0.119203, 0.268941, 0.500000, 0.731059, 0.880797 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_expit, ts_expit_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_expit_p); +} diff --git a/test/expm1.c b/test/expm1.c new file mode 100644 index 0000000..0375e98 --- /dev/null +++ b/test/expm1.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_expm1( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, -1.000000, 2.000000, 0.500000 }; + fp_t const e0[] = { 0.000000, 1.718282, -0.632121, 6.389056, 0.648721 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_expm1, ts_expm1_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_expm1_p); +} diff --git a/test/exponential.c b/test/exponential.c new file mode 100644 index 0000000..ed1f85f --- /dev/null +++ b/test/exponential.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_exponential( void ) +{ + fp_t const c[] = { 2.0 }; + + fp_t const x0[] = { 0, 1, 2, 3, 4 }; + fp_t const e0[] = { 1, 2, 4, 8, 16 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_exponential, ts_exponential_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_exponential_p); +} diff --git a/test/exponential_cdf.c b/test/exponential_cdf.c new file mode 100644 index 0000000..fd47765 --- /dev/null +++ b/test/exponential_cdf.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_exponential_cdf( void ) +{ + fp_t const x0[] = { -1.000000, 0.000000, 0.500000, 1.000000, 2.000000 }; + fp_t const e0[] = { 0.000000, 0.000000, 0.393469, 0.632121, 0.864665 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_exponential_cdf, ts_exponential_cdf_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_exponential_cdf_p); +} diff --git a/test/exponential_natural.c b/test/exponential_natural.c new file mode 100644 index 0000000..c16df53 --- /dev/null +++ b/test/exponential_natural.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_exponential_natural( void ) +{ + fp_t const x0[] = { 0, 0.5, 1, 2, 3 }; + fp_t const e0[] = { 1, 1.648721, 2.718282, 7.389056, 20.085537 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_exponential_natural, ts_exponential_natural_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_exponential_natural_p); +} diff --git a/test/exponential_pdf.c b/test/exponential_pdf.c new file mode 100644 index 0000000..43b8149 --- /dev/null +++ b/test/exponential_pdf.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_exponential_pdf( void ) +{ + fp_t const x0[] = { -1.000000, 0.000000, 0.500000, 1.000000, 2.000000 }; + fp_t const e0[] = { 0.000000, 1.000000, 0.606531, 0.367879, 0.135335 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_exponential_pdf, ts_exponential_pdf_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_exponential_pdf_p); +} diff --git a/test/factorial.c b/test/factorial.c new file mode 100644 index 0000000..42e8d3d --- /dev/null +++ b/test/factorial.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_factorial( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, 2.000000, 3.000000, 4.000000, 5.000000, 6.000000, 7.000000, 8.000000, 9.000000, 10.000000 }; + fp_t const e0[] = { 1.000000, 1.000000, 2.000000, 6.000000, 24.000000, 120.000000, 720.000000, 5040.000000, 40320.000000, 362880.000000, 3628800.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_factorial, ts_factorial_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_factorial_p); +} diff --git a/test/factorial_int.c b/test/factorial_int.c new file mode 100644 index 0000000..0e49cac --- /dev/null +++ b/test/factorial_int.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_factorial_int( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, 2.000000, 3.000000, 4.000000, 5.000000, 10.000000 }; + fp_t const e0[] = { 1.000000, 1.000000, 2.000000, 6.000000, 24.000000, 120.000000, 3628800.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_factorial_int, ts_factorial_int_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_factorial_int_p); +} diff --git a/test/fdim_2input.c b/test/fdim_2input.c new file mode 100644 index 0000000..e2b1e0a --- /dev/null +++ b/test/fdim_2input.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_fdim_2input( void ) +{ + fp_t const x0[] = { -3.000000, -1.000000, 0.000000, 1.000000, 3.000000 }; + fp_t const e0[] = { 0.000000, 0.000000, 0.000000, 1.000000, 3.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_fdim_2input, ts_fdim_2input_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_fdim_2input_p); +} diff --git a/test/fibonacci.c b/test/fibonacci.c new file mode 100644 index 0000000..5a8ab7d --- /dev/null +++ b/test/fibonacci.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_fibonacci( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, 2.000000, 3.000000, 4.000000, 5.000000, 6.000000, 7.000000, 8.000000, 10.000000 }; + fp_t const e0[] = { 0.000000, 1.000000, 1.000000, 2.000000, 3.000000, 5.000000, 8.000000, 13.000000, 21.000000, 55.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_fibonacci, ts_fibonacci_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_fibonacci_p); +} diff --git a/test/fill_indicator.c b/test/fill_indicator.c new file mode 100644 index 0000000..071c245 --- /dev/null +++ b/test/fill_indicator.c @@ -0,0 +1,40 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_fill_indicator( void ) +{ + uint_t k = 3; + + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 8, 10, 10, 11, 12, 13, 14, 15, 16, 17 }; + fp_t const c[] = { 11, 12, 10, 14, 15, 16, 14, 18, 17, 20 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* fill values: + * i=0: |11-10|/(12-8)*100 = 1/4*100 = 25 + * i=1: |12-11|/(13-10)*100 = 1/3*100 = 33.333 + * i=2: |10-12|/(14-10)*100 = 2/4*100 = 50 + * i=3: |14-13|/(15-11)*100 = 1/4*100 = 25 + * i=4: |15-14|/(16-12)*100 = 1/4*100 = 25 + * i=5: |16-15|/(17-13)*100 = 1/4*100 = 25 + * i=6: |14-16|/(18-14)*100 = 2/4*100 = 50 + * i=7: |18-17|/(19-15)*100 = 1/4*100 = 25 + * i=8: |17-18|/(20-16)*100 = 1/4*100 = 25 + * i=9: |20-19|/(21-17)*100 = 1/4*100 = 25 + * SMA(3): i=2: (25+33.333+50)/3 = 36.111 + * i=3: 36.111 + (25-25)/3 = 36.111 + * i=4: 36.111 + (25-33.333)/3 = 33.333 + * i=5: 33.333 + (25-50)/3 = 25 + * i=6: 25 + (50-25)/3 = 33.333 + * i=7: 33.333 + (25-25)/3 = 33.333 + * i=8: 33.333 + (25-25)/3 = 33.333 + * i=9: 33.333 + (25-50)/3 = 25 + */ + fp_t const e[] = { 36.11111, 36.11111, 33.33333, 25, 33.33333, 33.33333, 33.33333, 25 }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_fill_indicator, ts_fill_indicator_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_fill_indicator_p); +} diff --git a/test/fisher_transform.c b/test/fisher_transform.c new file mode 100644 index 0000000..050a360 --- /dev/null +++ b/test/fisher_transform.c @@ -0,0 +1,26 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_fisher_transform( void ) +{ + /* k=3, prices increasing monotonically */ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* Window indices [1..3], H=[13,14,15], L=[10,11,12], range=5, val=(14-10)/5=0.8 */ + /* fisher = 0.5*ln(0.8/0.2) + 0.5*0 = 0.5*ln(4) = 0.69315 */ + /* Next: H=[14,15,16], L=[11,12,13], val=(15-11)/5=0.8, fisher=0.5*ln(4)+0.5*0.69315=0.69315+0.34657=1.03972 */ + /* Monotonic, so all val=0.8, fisher converges toward ln(4) = 1.38629 */ + /* f1=0.69315, f2=1.03972, f3=1.21301, f4=1.29965, f5=1.34297, f6=1.36463, f7=1.37546 */ + fp_t const ef[] = { 0.69315, 1.03972, 1.21301, 1.29965, 1.34297, 1.36463, 1.37546, 1.38088, 0, 0 }; + fp_t const et[] = { 0, 0.69315, 1.03972, 1.21301, 1.29965, 1.34297, 1.36463, 1.37546, 0, 0 }; + fp_t const * const exp[2] = { ef, et }; + + uint_t k = 3; + return ts_test(ts_fisher_transform, ts_fisher_transform_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_fisher_transform_p); +} diff --git a/test/floor.c b/test/floor.c new file mode 100644 index 0000000..274c60f --- /dev/null +++ b/test/floor.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_floor( void ) +{ + fp_t const x0[] = { -2.7, -1.3, 0, 0.5, 1.3, 2.7, 3.9 }; + fp_t const e0[] = { -3, -2, 0, 0, 1, 2, 3 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_floor, ts_floor_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_floor_p); +} diff --git a/test/fma.c b/test/fma.c new file mode 100644 index 0000000..2e342bc --- /dev/null +++ b/test/fma.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_fma( void ) +{ + fp_t const x0[] = { 1.000000, 2.000000, 3.000000 }; + fp_t const x1[] = { 2.000000, 3.000000, 4.000000 }; + fp_t const x2[] = { 1.000000, 1.000000, 1.000000 }; + fp_t const e0[] = { 3.000000, 7.000000, 13.000000 }; + + fp_t const * const x[3] = { x0, x1, x2 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_fma, ts_fma_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_fma_p); +} diff --git a/test/fmax.c b/test/fmax.c new file mode 100644 index 0000000..df3d4e2 --- /dev/null +++ b/test/fmax.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_fmax( void ) +{ + fp_t const x0[] = { 1.000000, 3.000000, 5.000000, 2.000000 }; + fp_t const x1[] = { 2.000000, 2.000000, 3.000000, 5.000000 }; + fp_t const e0[] = { 2.000000, 3.000000, 5.000000, 5.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_fmax, ts_fmax_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_fmax_p); +} diff --git a/test/fmax_2input.c b/test/fmax_2input.c new file mode 100644 index 0000000..1ef7371 --- /dev/null +++ b/test/fmax_2input.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_fmax_2input( void ) +{ + fp_t const x0[] = { -3.000000, -1.000000, 0.000000, 1.000000, 3.000000 }; + fp_t const e0[] = { 0.000000, 0.000000, 0.000000, 1.000000, 3.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_fmax_2input, ts_fmax_2input_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_fmax_2input_p); +} diff --git a/test/fmin.c b/test/fmin.c new file mode 100644 index 0000000..1d00a31 --- /dev/null +++ b/test/fmin.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_fmin( void ) +{ + fp_t const x0[] = { 1.000000, 3.000000, 5.000000, 2.000000 }; + fp_t const x1[] = { 2.000000, 2.000000, 3.000000, 5.000000 }; + fp_t const e0[] = { 1.000000, 2.000000, 3.000000, 2.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_fmin, ts_fmin_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_fmin_p); +} diff --git a/test/fmin_2input.c b/test/fmin_2input.c new file mode 100644 index 0000000..8d5a37a --- /dev/null +++ b/test/fmin_2input.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_fmin_2input( void ) +{ + fp_t const x0[] = { -3.000000, -1.000000, 0.000000, 1.000000, 3.000000 }; + fp_t const e0[] = { -3.000000, -1.000000, 0.000000, 0.000000, 0.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_fmin_2input, ts_fmin_2input_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_fmin_2input_p); +} diff --git a/test/fmod.c b/test/fmod.c new file mode 100644 index 0000000..49ea747 --- /dev/null +++ b/test/fmod.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_fmod( void ) +{ + fp_t const x0[] = { 7.000000, 10.000000, -7.000000, 7.500000 }; + fp_t const x1[] = { 3.000000, 3.000000, 3.000000, 2.000000 }; + fp_t const e0[] = { 1.000000, 1.000000, -1.000000, 1.500000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_fmod, ts_fmod_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_fmod_p); +} diff --git a/test/fobv.c b/test/fobv.c new file mode 100644 index 0000000..3f57e0a --- /dev/null +++ b/test/fobv.c @@ -0,0 +1,18 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_fobv( void ) +{ + fp_t const o[] = { 10, 11, 12, 11, 12 }; + fp_t const h[] = { 12, 13, 14, 12, 14 }; + fp_t const l[] = { 8, 9, 10, 9, 10 }; + fp_t const c[] = { 11, 12, 10, 11, 11 }; + fp_t const v[] = { 100, 200, 300, 400, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t const e[] = { 200, -100, 300, 300 }; + fp_t const * const e_arr[1] = { e }; + + return ts_test(ts_fobv, ts_fobv_offset, x, e_arr, 5, (ts_constant_t *)NULL, &ts_fobv_p); +} diff --git a/test/fractal_chaos_bands.c b/test/fractal_chaos_bands.c new file mode 100644 index 0000000..eccc88f --- /dev/null +++ b/test/fractal_chaos_bands.c @@ -0,0 +1,21 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_fractal_chaos_bands( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + fp_t const cp[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 }; + + fp_t const * const x[] = { o, h, l, cp }; + + /* k=3, half_k=1, offset=1, y_n=11 (i=1..10, y[11]=0) */ + fp_t const eu[] = { 14.000000, 14.500000, 15.250000, 16.125000, 17.062500, 18.031250, 19.015625, 20.007812, 21.003906, 22.001953, 0.000000 }; + fp_t const el[] = { 9.000000, 9.500000, 10.250000, 11.125000, 12.062500, 13.031250, 14.015625, 15.007812, 16.003906, 17.001953, 0.000000 }; + fp_t const * const exp[2] = { eu, el }; + + uint_t k = 3; + return ts_test(ts_fractal_chaos_bands, ts_fractal_chaos_bands_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_fractal_chaos_bands_p); +} diff --git a/test/fractal_chaos_oscillator.c b/test/fractal_chaos_oscillator.c new file mode 100644 index 0000000..921c194 --- /dev/null +++ b/test/fractal_chaos_oscillator.c @@ -0,0 +1,20 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_fractal_chaos_oscillator( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + fp_t const cp[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 }; + + fp_t const * const x[] = { o, h, l, cp }; + + /* k=3, half_k=1, offset=1, y_n=11 (i=1..10, y[11]=0) */ + fp_t const e[] = { 21.739130, 20.833333, 19.607843, 18.348624, 17.167382, 16.096579, 15.137181, 14.279340, 13.510661, 12.819229, 0.000000 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_fractal_chaos_oscillator, ts_fractal_chaos_oscillator_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_fractal_chaos_oscillator_p); +} diff --git a/test/fuzz.c b/test/fuzz.c new file mode 100644 index 0000000..3f11d9d --- /dev/null +++ b/test/fuzz.c @@ -0,0 +1,68 @@ +#include "ts.h" +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +typedef int (*ts_func_t)(fp_t * const *, uint_t, fp_t const * const *, uint_t, uint_t, ts_constant_t const *); + +typedef struct { + ts_func_t func; + uint_t xn; + uint_t yn; +} fuzz_entry_t; + +#include "fuzz_table_generated.c" + +static const uint_t _fuzz_n = _fuzz_generated_n; +static const fuzz_entry_t *_fuzz_table = _fuzz_table_generated; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (size < 2) + return 0; + + uint_t func_idx = data[0]; + uint_t config = data[1]; + + uint_t n = 4; + if (size > 2) + n = (uint_t)(data[2] + 4); + if (n > 256) + n = 256; + + fp_t input[256]; + fp_t output[256]; + fp_t output2[256]; + fp_t output3[256]; + + size_t offset = 3; + for (uint_t i = 0; i < n && offset + 8 <= size; i++, offset += 8) + { + memcpy(&input[i], data + offset, sizeof(fp_t)); + } + for (uint_t i = (offset - 3) / 8; i < n; i++) + input[i] = 0; + + fp_t *x_arrays[5] = {input, input, input, input, input}; + fp_t *y_arrays[3] = {output, output2, output3}; + + uint_t period = 5; + if (config > 0) + period = config; + if (period < 1) + period = 1; + if (period > n) + period = n; + + uint_t idx = func_idx % _fuzz_n; + fuzz_entry_t entry = _fuzz_table[idx]; + + uint_t xn = entry.xn; + uint_t yn = entry.yn; + if (xn > 5) xn = 5; + if (yn > 3) yn = 3; + + (void)entry.func(y_arrays, yn, (fp_t const * const *)x_arrays, xn, n, (ts_constant_t *)&period); + + return 0; +} diff --git a/test/gamma_pdf.c b/test/gamma_pdf.c new file mode 100644 index 0000000..38fcc62 --- /dev/null +++ b/test/gamma_pdf.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_gamma_pdf( void ) +{ + fp_t const c[] = { 2.000000 }; + + fp_t const x0[] = { 0.100000, 0.500000, 1.000000, 2.000000, 3.000000 }; + fp_t const e0[] = { 0.090484, 0.303265, 0.367879, 0.270671, 0.149361 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_gamma_pdf, ts_gamma_pdf_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_gamma_pdf_p); +} diff --git a/test/gator_oscillator.c b/test/gator_oscillator.c new file mode 100644 index 0000000..13ae023 --- /dev/null +++ b/test/gator_oscillator.c @@ -0,0 +1,24 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_gator_oscillator( void ) +{ + /* Linear prices: 0,1,2,...,24 */ + fp_t x[25] = { 0 }; + for ( uint_t i = 0; i < 25; ++i ) + x[i] = (fp_t)i; + + fp_t const * const inp[1] = { x }; + + /* At i=12: SMA(5) of [8..12] = 10, SMA(8) of [5..12] = 8.5, SMA(13) of [0..12] = 6 */ + /* Upper = |10 - 8.5| = 1.5, Lower = |6 - 8.5| = 2.5 */ + /* At i=13: SMA(5) of [9..13] = 11, SMA(8) of [6..13] = 9.5, SMA(13) of [1..13] = 7 */ + /* Upper = |11 - 9.5| = 1.5, Lower = |7 - 9.5| = 2.5 */ + /* Constant for linear series */ + fp_t const eu[] = { 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5 }; + fp_t const el[] = { 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5 }; + fp_t const * const exp[2] = { eu, el }; + + return ts_test(ts_gator_oscillator, ts_gator_oscillator_offset, inp, exp, 25, (ts_constant_t *)NULL, &ts_gator_oscillator_p); +} diff --git a/test/gaussian_cdf.c b/test/gaussian_cdf.c new file mode 100644 index 0000000..82626f7 --- /dev/null +++ b/test/gaussian_cdf.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_gaussian_cdf( void ) +{ + fp_t const x0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000 }; + fp_t const e0[] = { 0.022750, 0.158655, 0.500000, 0.841345, 0.977250 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_gaussian_cdf, ts_gaussian_cdf_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_gaussian_cdf_p); +} diff --git a/test/gaussian_pdf.c b/test/gaussian_pdf.c new file mode 100644 index 0000000..d859c26 --- /dev/null +++ b/test/gaussian_pdf.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_gaussian_pdf( void ) +{ + fp_t const x0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000 }; + fp_t const e0[] = { 0.053991, 0.241971, 0.398942, 0.241971, 0.053991 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_gaussian_pdf, ts_gaussian_pdf_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_gaussian_pdf_p); +} diff --git a/test/gaussian_quantile.c b/test/gaussian_quantile.c new file mode 100644 index 0000000..8780c19 --- /dev/null +++ b/test/gaussian_quantile.c @@ -0,0 +1,11 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_gaussian_quantile( void ) +{ + fp_t const x0[] = { 0.100000, 0.250000, 0.500000, 0.750000, 0.900000 }; + fp_t const e0[] = { -1.281552, -0.674490, -0.000000, 0.674490, 1.281552 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_gaussian_quantile, ts_gaussian_quantile_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_gaussian_quantile_p); +} diff --git a/test/gcd.c b/test/gcd.c new file mode 100644 index 0000000..ebf8d9c --- /dev/null +++ b/test/gcd.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_gcd( void ) +{ + fp_t const x0[] = { 12.000000, 15.000000, 100.000000, 7.000000, 0.000000 }; + fp_t const x1[] = { 8.000000, 10.000000, 35.000000, 3.000000, 5.000000 }; + fp_t const e0[] = { 4.000000, 5.000000, 5.000000, 1.000000, 5.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_gcd, ts_gcd_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_gcd_p); +} diff --git a/test/gen_test_data.c b/test/gen_test_data.c new file mode 100644 index 0000000..6ef54af --- /dev/null +++ b/test/gen_test_data.c @@ -0,0 +1,101 @@ +/* gen_test_data.c - Validate all ts functions run without error. + * Note: excluded from default build. Fix and add target to use. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include "ts.h" + +static fp_t rand_fp(void) { + return (double)rand() / (double)RAND_MAX * 100.0; +} + +/* + * Smoke-test a single function by name. Returns 0 on success. + * This is a placeholder — a full auto-discovery registry would require + * adding ts_functions[] / ts_functions_n to ts.h or generating them. + */ +int main(void) { + unsigned int seed = 42; + srand(seed); + uint_t n = 100; + + /* Test a representative sample of functions */ + struct { + const char *name; + int (*func)(fp_t * const y[], fp_t const * const x[], uint_t, ts_constant_t const *); + uint_t x_n, y_n; + } samples[] = { + { "average", ts_average, 1, 1 }, + { "rsi", ts_rsi, 1, 1 }, + { "deviation_standard", ts_deviation_standard, 1, 1 }, + { "variance", ts_variance, 1, 1 }, + { "addition", ts_addition, 2, 1 }, + { "subtraction", ts_subtraction, 2, 1 }, + { "multiplication", ts_multiplication, 2, 1 }, + { "division", ts_division, 2, 1 }, + { "absolute_value", ts_absolute_value, 1, 1 }, + { "nan_fn", ts_nan_fn, 1, 1 }, + }; + size_t nsamples = sizeof(samples) / sizeof(samples[0]); + + for (size_t fi = 0; fi < nsamples; fi++) { + typeof(samples[fi]) f = samples[fi]; + + /* Allocate input arrays */ + fp_t **x = calloc(f.x_n, sizeof(fp_t *)); + fp_t **y = calloc(f.y_n, sizeof(fp_t *)); + if (!x || !y) { free(x); free(y); continue; } + + for (uint_t i = 0; i < f.x_n; i++) { + x[i] = malloc(n * sizeof(fp_t)); + if (!x[i]) goto next; + for (uint_t j = 0; j < n; j++) x[i][j] = rand_fp(); + } + for (uint_t i = 0; i < f.y_n; i++) { + y[i] = calloc(n, sizeof(fp_t)); + if (!y[i]) goto next; + } + + /* Try with default params (all zeros) */ + uint8_t params[TS_CONSTANT_SIZE] = { 0 }; + int ret = f.func(y, x, n, (ts_constant_t const *)params); + const char *pass_label = "PASS"; + if (ret != 0) { + /* Try with k=10 */ + { + uint8_t c[TS_CONSTANT_SIZE] = { 0 }; + *(uint_t *)c = 10; + ret = f.func(y, x, n, (ts_constant_t const *)c); + if (ret == 0) pass_label = "PASS (k=10)"; + } + } + if (ret != 0) { + /* Try with k=14 */ + { + uint8_t c[TS_CONSTANT_SIZE] = { 0 }; + *(uint_t *)c = 14; + ret = f.func(y, x, n, (ts_constant_t const *)c); + if (ret == 0) pass_label = "PASS (k=14)"; + } + } + + if (ret != 0) { + printf("SKIP %s (ret=%d after all retries)\n", f.name, ret); + (void)fflush(stdout); + goto next; + } + + printf("%s %s\n", pass_label, f.name); + (void)fflush(stdout); + + next: + for (uint_t i = 0; i < f.x_n; i++) free(x[i]); + for (uint_t i = 0; i < f.y_n; i++) free(y[i]); + free(x); + free(y); + } + + return 0; +} diff --git a/test/gopalakrishnan_range_index.c b/test/gopalakrishnan_range_index.c new file mode 100644 index 0000000..6b8167a --- /dev/null +++ b/test/gopalakrishnan_range_index.c @@ -0,0 +1,39 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_gopalakrishnan_range_index( void ) +{ + fp_t const x0[] = { 10, 10, 10, 20, 20, 20 }; + fp_t const x1[] = { 14, 13, 14, 24, 23, 24 }; + fp_t const x2[] = { 8, 9, 8, 18, 19, 18 }; + fp_t const x3[] = { 12, 11, 13, 22, 21, 23 }; + + fp_t const * const x[] = { x0, x1, x2, x3 }; + + uint_t k = 2; + + fp_t sum_abs = fabs( x3[1] - x3[0] ) + fabs( x3[2] - x3[1] ); + fp_t sum_range = ( x1[1] - x2[1] ) + ( x1[2] - x2[2] ); + fp_t e0 = sum_range != 0 ? sum_abs / sum_range : 0; + + fp_t abs_ring[2] = { fabs(x3[1]-x3[0]), fabs(x3[2]-x3[1]) }; + fp_t range_ring[2] = { x1[1]-x2[1], x1[2]-x2[2] }; + fp_t e[4] = { e0 }; + + for ( uint_t i = 3; i < 6; ++i ) + { + fp_t new_abs = fabs( x3[i] - x3[i-1] ); + fp_t new_range = x1[i] - x2[i]; + uint_t idx = ( i - k - 1 ) % k; + sum_abs += new_abs - abs_ring[ idx ]; + sum_range += new_range - range_ring[ idx ]; + abs_ring[ ( i - 1 ) % k ] = new_abs; + range_ring[ ( i - 1 ) % k ] = new_range; + e[ i - k ] = sum_range != 0 ? sum_abs / sum_range : 0; + } + + fp_t const * const exp[1] = { e }; + + return ts_test(ts_gopalakrishnan_range_index, ts_gopalakrishnan_range_index_offset, x, exp, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_gopalakrishnan_range_index_p); +} diff --git a/test/hard_sigmoid.c b/test/hard_sigmoid.c new file mode 100644 index 0000000..50453ac --- /dev/null +++ b/test/hard_sigmoid.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_hard_sigmoid( void ) +{ + fp_t const x0[] = { -5.000000, -3.000000, 0.000000, 3.000000, 5.000000 }; + fp_t const e0[] = { 0.000000, 0.000000, 0.500000, 1.000000, 1.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_hard_sigmoid, ts_hard_sigmoid_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_hard_sigmoid_p); +} diff --git a/test/hard_swish.c b/test/hard_swish.c new file mode 100644 index 0000000..ce9e82e --- /dev/null +++ b/test/hard_swish.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_hard_swish( void ) +{ + fp_t const x0[] = { -5.000000, -3.000000, 0.000000, 3.000000, 5.000000 }; + fp_t const e0[] = { -0.000000, -0.000000, 0.000000, 3.000000, 5.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_hard_swish, ts_hard_swish_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_hard_swish_p); +} diff --git a/test/hard_tanh.c b/test/hard_tanh.c new file mode 100644 index 0000000..db97fd5 --- /dev/null +++ b/test/hard_tanh.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_hard_tanh( void ) +{ + fp_t const x0[] = { -3.000000, -1.500000, -1.000000, 0.000000, 1.000000, 1.500000, 3.000000 }; + fp_t const e0[] = { -1.000000, -1.000000, -1.000000, 0.000000, 1.000000, 1.000000, 1.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_hard_tanh, ts_hard_tanh_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_hard_tanh_p); +} diff --git a/test/harmonic.c b/test/harmonic.c new file mode 100644 index 0000000..7a4931a --- /dev/null +++ b/test/harmonic.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_harmonic( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, 2.000000, 3.000000, 4.000000, 5.000000 }; + fp_t const e0[] = { 0.000000, 1.000000, 1.500000, 1.833333, 2.083333, 2.283333 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_harmonic, ts_harmonic_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_harmonic_p); +} diff --git a/test/hermite.c b/test/hermite.c new file mode 100644 index 0000000..48fdde0 --- /dev/null +++ b/test/hermite.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_hermite( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, 0.500000, -1.000000, 2.000000 }; + fp_t const x1[] = { 0.000000, 1.000000, 2.000000, 3.000000, 4.000000 }; + fp_t const e0[] = { 1.000000, 2.000000, -1.000000, 4.000000, 76.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_hermite, ts_hermite_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_hermite_p); +} diff --git a/test/high_low_bands.c b/test/high_low_bands.c new file mode 100644 index 0000000..f98bee3 --- /dev/null +++ b/test/high_low_bands.c @@ -0,0 +1,25 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_high_low_bands( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const cp[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, cp }; + + /* k=3, offset=4, y_n=6 */ + /* Rolling HH3: 12,13,14,15,16,17,18,19 */ + /* Rolling LL3: 9,9,9,10,11,12,13,14 */ + /* SMA3(HH3): 13,14,15,16,17,18 */ + /* SMA3(LL3): 9,9.333,10,11,12,13 */ + fp_t const eu[] = { 13, 14, 15, 16, 17, 18 }; + fp_t const el[] = { 9, 9.33333333333333, 10, 11, 12, 13 }; + fp_t const * const exp[2] = { eu, el }; + + uint_t k = 3; + return ts_test(ts_high_low_bands, ts_high_low_bands_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_high_low_bands_p); +} diff --git a/test/high_minus_low.c b/test/high_minus_low.c new file mode 100644 index 0000000..5bcec93 --- /dev/null +++ b/test/high_minus_low.c @@ -0,0 +1,17 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_high_minus_low( void ) +{ + fp_t const x0[] = { 1, 1, 1, 1, 1 }; + fp_t const x1[] = { 5, 10, 15, 20, 25 }; + fp_t const x2[] = { 0, 5, 10, 15, 20 }; + fp_t const x3[] = { 1, 1, 1, 1, 1 }; + fp_t const x4[] = { 1, 1, 1, 1, 1 }; + fp_t const e0[] = { 5, 5, 5, 5, 5 }; + + fp_t const * const x[] = { x0, x1, x2, x3, x4 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_high_minus_low, ts_high_minus_low_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_high_minus_low_p); +} diff --git a/test/highest_high.c b/test/highest_high.c new file mode 100644 index 0000000..b5897ad --- /dev/null +++ b/test/highest_high.c @@ -0,0 +1,19 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_highest_high( void ) +{ + fp_t const x0[] = { 1, 1, 1, 1, 1, 1, 1 }; + fp_t const x1[] = { 1, 3, 5, 2, 4, 6, 8 }; + fp_t const x2[] = { 0, 1, 2, 1, 3, 4, 5 }; + fp_t const x3[] = { 1, 2, 3, 3, 5, 6, 7 }; + fp_t const x4[] = { 1, 1, 1, 1, 1, 1, 1 }; + fp_t const e0[] = { 5, 5, 5, 6, 8 }; + + fp_t const * const x[] = { x0, x1, x2, x3, x4 }; + fp_t const * const e[1] = { e0 }; + + uint_t const k = 3; + + return ts_test(ts_highest_high, ts_highest_high_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_highest_high_p); +} diff --git a/test/historical_volatility.c b/test/historical_volatility.c new file mode 100644 index 0000000..1d57f54 --- /dev/null +++ b/test/historical_volatility.c @@ -0,0 +1,16 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_historical_volatility( void ) +{ + fp_t const x[] = { 100, 101, 100, 102, 101, 100, 103, 101, 102, 100 }; + fp_t const * const inp[1] = { x }; + + /* k=3, initial window at y[0][2], rolling windows at y[0][3..8] */ + fp_t const e[] = { 0.196453, 0.222285, 0.222285, 0.295293, 0.337649, 0.320724, 0.221194, 0 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_historical_volatility, ts_historical_volatility_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_historical_volatility_p); +} diff --git a/test/hull_ma.c b/test/hull_ma.c new file mode 100644 index 0000000..ff8182a --- /dev/null +++ b/test/hull_ma.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_hull_ma( void ) +{ + fp_t const x0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + fp_t const * const x[] = { x0 }; + + fp_t const e[] = { 6.333333, 7.333333, 8.333333, 9.333333, 10.333333 }; + fp_t const * const exp[] = { e }; + + uint_t c = 5; + return ts_test(ts_hull_ma, ts_hull_ma_offset, x, exp, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_hull_ma_p); +} diff --git a/test/hurst_exponent.c b/test/hurst_exponent.c new file mode 100644 index 0000000..ccf54c8 --- /dev/null +++ b/test/hurst_exponent.c @@ -0,0 +1,11 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_hurst_exponent( void ) +{ + uint_t const c[] = { 5 }; + fp_t const x0[] = { 1,2,3,4,5,6,7,8,9,10 }; + fp_t e0[10]; + ts_hurst_exponent((fp_t*[]){e0}, 1, (fp_t const *[]){x0}, 1, 10, (ts_constant_t *)&c); + return true; +} diff --git a/test/hypot.c b/test/hypot.c new file mode 100644 index 0000000..107530b --- /dev/null +++ b/test/hypot.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_hypot( void ) +{ + fp_t const x0[] = { 3.000000, 5.000000, 0.000000, 1.000000 }; + fp_t const x1[] = { 4.000000, 12.000000, 5.000000, 0.000000 }; + fp_t const e0[] = { 5.000000, 13.000000, 5.000000, 1.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_hypot, ts_hypot_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_hypot_p); +} diff --git a/test/ichimoku.c b/test/ichimoku.c new file mode 100644 index 0000000..ea20056 --- /dev/null +++ b/test/ichimoku.c @@ -0,0 +1,49 @@ +#include <math.h> +#include <stddef.h> +#include <stdlib.h> +#include "ts.h" + +bool ts_test_ichimoku( void ) +{ + uint_t n = 55; + fp_t *o = malloc( n * sizeof( fp_t ) ); + fp_t *h = malloc( n * sizeof( fp_t ) ); + fp_t *l = malloc( n * sizeof( fp_t ) ); + fp_t *cl = malloc( n * sizeof( fp_t ) ); + + if ( !o || !h || !l || !cl ) + { + free( o ); free( h ); free( l ); free( cl ); + return false; + } + + for ( uint_t i = 0; i < n; ++i ) + { + o[i] = (fp_t)(100 + i); + h[i] = (fp_t)(102 + i); + l[i] = (fp_t)(98 + i); + cl[i] = (fp_t)(101 + i); + } + + fp_t const * const x[4] = { o, h, l, cl }; + + /* Fixed: include current bar in lookback, Senkou plotted 26 ahead, Chikou 26 behind */ + /* offset=52, y_n=55-52=3 */ + fp_t const et[] = { 148, 149, 150 }; + fp_t const ek[] = { 139.5, 140.5, 141.5 }; + fp_t const esa[] = { 117.75, 118.75, 119.75 }; + fp_t const esb[] = { 0, 0, 0 }; + fp_t const ec[] = { 127, 128, 129 }; + fp_t const * const exp[5] = { et, ek, esa, esb, ec }; + + ts_constant_t c; + memset(&c, 0, sizeof(c)); + bool result = ts_test(ts_ichimoku, ts_ichimoku_offset, x, exp, n, &c, &ts_ichimoku_p); + + free( o ); + free( h ); + free( l ); + free( cl ); + + return result; +} diff --git a/test/ilogb.c b/test/ilogb.c new file mode 100644 index 0000000..fe50df5 --- /dev/null +++ b/test/ilogb.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_ilogb( void ) +{ + fp_t const x0[] = { 1.000000, 2.000000, 4.000000, 8.000000, 0.500000, 0.250000 }; + fp_t const e0[] = { 0.000000, 1.000000, 2.000000, 3.000000, -1.000000, -2.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_ilogb, ts_ilogb_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_ilogb_p); +} diff --git a/test/intraday_momentum_index.c b/test/intraday_momentum_index.c new file mode 100644 index 0000000..4044faf --- /dev/null +++ b/test/intraday_momentum_index.c @@ -0,0 +1,39 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_intraday_momentum_index( void ) +{ + /* k=3, open always = prev_close => diff=0, IMI=0/0=0 */ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const c[] = { 10, 12, 14, 16, 18, 20, 22, 24, 26, 28 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* open[i] = close[i-1] for i>=1: o[1]=11 != c[0]=10, diff=1 (up) */ + /* o[2]=12 vs c[1]=12, diff=0 */ + /* o[3]=13 vs c[2]=14, diff=-1 (down=1) */ + /* o[4]=14 vs c[3]=16, diff=-2 (down=2) */ + /* For i=1..3: up=1+0+0=1, down=0+1+2=3, IMI=1/4=0.25 */ + /* Hmm let me recalculate more carefully. xi goes 1 to k=3 */ + /* xi=1: o[1]-c[0]=11-10=1 > 0, sum_up=1 */ + /* xi=2: o[2]-c[1]=12-12=0, neither up nor down, sum_up=1, sum_down=0 */ + /* xi=3: o[3]-c[2]=13-14=-1 < 0, sum_down=1, sum_up=1 */ + /* y[0][3] = 1/(1+1) = 0.5 */ + /* xi=4: o[4]-c[3]=14-16=-2, old=o[1]-c[0]=1 */ + /* sum_up stays 1 (no add), sum_down+=2=3, then remove old: sum_up-=1=0 */ + /* Hmm that logic is wrong. Let me rewrite the incremental part. */ + + /* Actually the incremental update is tricky. Let me use a simpler approach: */ + /* For i=4: diffs at [4,5,6] = o[4]-c[3], o[5]-c[4], o[6]-c[5] */ + /* = 14-16=-2, 15-18=-3, 16-20=-4 */ + /* up=0, down=2+3+4=9, IMI=0 */ + + fp_t const e[] = { 0.5, 0, 0, 0, 0, 0, 0 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_intraday_momentum_index, ts_intraday_momentum_index_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_intraday_momentum_index_p); +} diff --git a/test/is_prime.c b/test/is_prime.c new file mode 100644 index 0000000..233ae6f --- /dev/null +++ b/test/is_prime.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_is_prime( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, 2.000000, 3.000000, 4.000000, 5.000000, 7.000000, 10.000000, 13.000000, 17.000000 }; + fp_t const e0[] = { 0.000000, 0.000000, 1.000000, 1.000000, 0.000000, 1.000000, 1.000000, 0.000000, 1.000000, 1.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_is_prime, ts_is_prime_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_is_prime_p); +} diff --git a/test/jaccard_similarity.c b/test/jaccard_similarity.c new file mode 100644 index 0000000..7fb2474 --- /dev/null +++ b/test/jaccard_similarity.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_jaccard_similarity( void ) +{ + fp_t const x0[] = { 3.000000, 5.000000, 0.000000, 1.000000 }; + fp_t const x1[] = { 4.000000, 5.000000, 0.000000, 2.000000 }; + fp_t const e0[] = { 0.875000, 1.000000, 0.000000, 0.750000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_jaccard_similarity, ts_jaccard_similarity_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_jaccard_similarity_p); +} diff --git a/test/kalman_filter.c b/test/kalman_filter.c new file mode 100644 index 0000000..188ae82 --- /dev/null +++ b/test/kalman_filter.c @@ -0,0 +1,26 @@ +#include "ts.h" + +bool ts_test_kalman_filter( void ) +{ + fp_t const x0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + fp_t const e0[] = { + 1.0, + 1.5024875621890548, + 2.0099009900990099, + 2.5245821283270429, + 3.0487331327055625, + 3.5843788460830162, + 4.1333360364582399, + 4.6971903124447723, + 5.2772810678708257, + 5.8746943630334316 + }; + + fp_t const * const x[] = { x0 }; + fp_t const * const e[] = { e0 }; + + struct { fp_t Q; fp_t R; } c = { 0.01, 1.0 }; + + return ts_test(ts_kalman_filter, ts_kalman_filter_offset, x, e, 10, (ts_constant_t *)&c, &ts_kalman_filter_p); +} diff --git a/test/kaufman_adaptive_ma.c b/test/kaufman_adaptive_ma.c new file mode 100644 index 0000000..2709a3a --- /dev/null +++ b/test/kaufman_adaptive_ma.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_kaufman_adaptive_ma( void ) +{ + fp_t const x0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; + + fp_t const * const x[] = { x0 }; + + fp_t const e[] = { 2.90983006, 4.47213595, 5.81966011, 7.03444185, 8.16718427, 9.24922359, 10.29992669 }; + fp_t const * const exp[] = { e }; + + uint_t c = 5; + return ts_test(ts_kaufman_adaptive_ma, ts_kaufman_adaptive_ma_offset, x, exp, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_kaufman_adaptive_ma_p); +} diff --git a/test/keltner_channel.c b/test/keltner_channel.c new file mode 100644 index 0000000..e5ad7a8 --- /dev/null +++ b/test/keltner_channel.c @@ -0,0 +1,23 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_keltner_channel( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* k=3, TP = (H+L+C)/3, EMA(3) of TP (alpha=2/(k+1)), ATR = Wilder's smoothing */ + /* EMA alpha = 2/4 = 0.5, ATR uses Wilder's: (prev*(k-1) + TR) / k */ + fp_t const em[] = { 12.79166667, 13.72916667, 14.69791667, 15.68229167, 16.67447917, 17.67057292, 18.66861979 }; + fp_t const eu[] = { 18.79166667, 19.72916667, 20.69791667, 21.68229167, 22.67447917, 23.67057292, 24.66861979 }; + fp_t const el[] = { 6.79166667, 7.72916667, 8.69791667, 9.68229167, 10.67447917, 11.67057292, 12.66861979 }; + fp_t const * const exp[3] = { em, eu, el }; + + uint_t k = 3; + return ts_test(ts_keltner_channel, ts_keltner_channel_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_keltner_channel_p); +} diff --git a/test/kvo.c b/test/kvo.c new file mode 100644 index 0000000..c0f489f --- /dev/null +++ b/test/kvo.c @@ -0,0 +1,40 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_kvo( void ) +{ + uint_t k1 = 3; + uint_t k2 = 3; + + fp_t const o[] = { 10, 11, 10, 12, 11, 13, 12, 14, 13, 15, 14, 16, 15, 17, 16 }; + fp_t const h[] = { 12, 13, 12, 14, 13, 15, 14, 16, 15, 17, 16, 18, 17, 19, 18 }; + fp_t const l[] = { 8, 9, 8, 10, 9, 11, 10, 12, 11, 13, 12, 14, 13, 15, 14 }; + fp_t const c[] = { 11, 10, 12, 11, 13, 12, 14, 13, 15, 14, 16, 15, 17, 16, 18 }; + fp_t const v[] = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t e_kvo[5] = { + 1.0, + -0.044715, + 0.542893, + -0.323870, + 0.444411 + }; + + fp_t e_sig[5] = { + 1.0, + 0.477642, + 0.510268, + 0.093199, + 0.268805 + }; + + fp_t const * const exp[2] = { e_kvo, e_sig }; + + typedef struct { uint_t k1; fp_t k2; } c_t; + c_t cv = { .k1 = k1, .k2 = (fp_t)k2 }; + + return ts_test(ts_kvo, ts_kvo_offset, x, exp, 15, (ts_constant_t *)&cv, &ts_kvo_p); +} diff --git a/test/lag.c b/test/lag.c new file mode 100644 index 0000000..67a2da1 --- /dev/null +++ b/test/lag.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_lag( void ) +{ + uint_t const c[] = { 2 }; + + fp_t const x0[] = { 10, 20, 30, 40 }; + fp_t const e0[] = { 10, 20 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_lag, ts_lag_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)c, &ts_lag_p); +} diff --git a/test/laguerre.c b/test/laguerre.c new file mode 100644 index 0000000..ba22ef8 --- /dev/null +++ b/test/laguerre.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_laguerre( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, 0.500000, 2.000000, 3.000000 }; + fp_t const x1[] = { 0.000000, 1.000000, 2.000000, 3.000000, 4.000000 }; + fp_t const e0[] = { 1.000000, 0.000000, 0.125000, -0.333333, 1.375000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_laguerre, ts_laguerre_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_laguerre_p); +} diff --git a/test/lambert_w.c b/test/lambert_w.c new file mode 100644 index 0000000..ce31037 --- /dev/null +++ b/test/lambert_w.c @@ -0,0 +1,11 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_lambert_w( void ) +{ + fp_t const x0[] = { 0.010000, 0.500000, 0.900000, 2.000000, 5.000000 }; + fp_t const e0[] = { 0.009901, 0.351734, 0.529833, 0.852606, 1.326725 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_lambert_w, ts_lambert_w_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_lambert_w_p); +} diff --git a/test/laplace_cdf.c b/test/laplace_cdf.c new file mode 100644 index 0000000..f419866 --- /dev/null +++ b/test/laplace_cdf.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_laplace_cdf( void ) +{ + fp_t const x0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000 }; + fp_t const e0[] = { 0.067668, 0.183940, 0.500000, 0.816060, 0.932332 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_laplace_cdf, ts_laplace_cdf_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_laplace_cdf_p); +} diff --git a/test/laplace_pdf.c b/test/laplace_pdf.c new file mode 100644 index 0000000..19dbbd9 --- /dev/null +++ b/test/laplace_pdf.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_laplace_pdf( void ) +{ + fp_t const x0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000 }; + fp_t const e0[] = { 0.067668, 0.183940, 0.500000, 0.183940, 0.067668 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_laplace_pdf, ts_laplace_pdf_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_laplace_pdf_p); +} diff --git a/test/lcm.c b/test/lcm.c new file mode 100644 index 0000000..4a0fb0f --- /dev/null +++ b/test/lcm.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_lcm( void ) +{ + fp_t const x0[] = { 4.000000, 6.000000, 12.000000, 7.000000, 0.000000 }; + fp_t const x1[] = { 6.000000, 8.000000, 18.000000, 3.000000, 5.000000 }; + fp_t const e0[] = { 12.000000, 24.000000, 36.000000, 21.000000, 0.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_lcm, ts_lcm_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_lcm_p); +} diff --git a/test/leaky_relu.c b/test/leaky_relu.c new file mode 100644 index 0000000..fab4dcc --- /dev/null +++ b/test/leaky_relu.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_leaky_relu( void ) +{ + fp_t const x0[] = { -3.000000, -1.000000, 0.000000, 1.000000, 3.000000 }; + fp_t const e0[] = { -0.030000, -0.010000, 0.000000, 1.000000, 3.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_leaky_relu, ts_leaky_relu_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_leaky_relu_p); +} diff --git a/test/legendre.c b/test/legendre.c new file mode 100644 index 0000000..95a2ba7 --- /dev/null +++ b/test/legendre.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_legendre( void ) +{ + fp_t const x0[] = { 0.000000, 0.500000, 1.000000, -1.000000, 0.300000 }; + fp_t const x1[] = { 0.000000, 1.000000, 2.000000, 3.000000, 4.000000 }; + fp_t const e0[] = { 1.000000, 0.500000, 1.000000, -1.000000, 0.072937 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_legendre, ts_legendre_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_legendre_p); +} diff --git a/test/lerp.c b/test/lerp.c new file mode 100644 index 0000000..2a47e30 --- /dev/null +++ b/test/lerp.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_lerp( void ) +{ + fp_t const x0[] = { 0.000000, 0.000000, 10.000000, 0.000000 }; + fp_t const x1[] = { 0.000000, 1.000000, 0.500000, 0.250000 }; + fp_t const x2[] = { 10.000000, 10.000000, 20.000000, 8.000000 }; + fp_t const e0[] = { 0.000000, 10.000000, 15.000000, 2.000000 }; + + fp_t const * const x[3] = { x0, x1, x2 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_lerp, ts_lerp_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_lerp_p); +} diff --git a/test/lgamma.c b/test/lgamma.c new file mode 100644 index 0000000..4a8b835 --- /dev/null +++ b/test/lgamma.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_lgamma( void ) +{ + fp_t const x0[] = { 1.000000, 2.000000, 3.000000, 0.500000, 5.000000 }; + fp_t const e0[] = { 0.000000, 0.000000, 0.693147, 0.572365, 3.178054 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_lgamma, ts_lgamma_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_lgamma_p); +} diff --git a/test/linear_regression.c b/test/linear_regression.c new file mode 100644 index 0000000..1dc13d6 --- /dev/null +++ b/test/linear_regression.c @@ -0,0 +1,15 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_linear_regression( void ) +{ + fp_t const x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { 5, 6, 7, 8 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 5; + return ts_test(ts_linear_regression, ts_linear_regression_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_linear_regression_p); +} diff --git a/test/linear_regression_angle.c b/test/linear_regression_angle.c new file mode 100644 index 0000000..46ba135 --- /dev/null +++ b/test/linear_regression_angle.c @@ -0,0 +1,15 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_linear_regression_angle( void ) +{ + fp_t const x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { 45.0, 45.0, 45.0, 45.0 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 5; + return ts_test(ts_linear_regression_angle, ts_linear_regression_angle_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_linear_regression_angle_p); +} diff --git a/test/linear_regression_forecast.c b/test/linear_regression_forecast.c new file mode 100644 index 0000000..b1510d7 --- /dev/null +++ b/test/linear_regression_forecast.c @@ -0,0 +1,15 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_linear_regression_forecast( void ) +{ + fp_t const x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { 6, 7, 8, 9 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 5; + return ts_test(ts_linear_regression_forecast, ts_linear_regression_forecast_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_linear_regression_forecast_p); +} diff --git a/test/linear_regression_intercept.c b/test/linear_regression_intercept.c new file mode 100644 index 0000000..2fe6ead --- /dev/null +++ b/test/linear_regression_intercept.c @@ -0,0 +1,15 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_linear_regression_intercept( void ) +{ + fp_t const x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { 1, 2, 3, 4 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 5; + return ts_test(ts_linear_regression_intercept, ts_linear_regression_intercept_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_linear_regression_intercept_p); +} diff --git a/test/linear_regression_r2.c b/test/linear_regression_r2.c new file mode 100644 index 0000000..dd46324 --- /dev/null +++ b/test/linear_regression_r2.c @@ -0,0 +1,15 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_linear_regression_r2( void ) +{ + fp_t const x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { 1.0, 1.0, 1.0, 1.0 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 5; + return ts_test(ts_linear_regression_r2, ts_linear_regression_r2_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_linear_regression_r2_p); +} diff --git a/test/linear_regression_slope.c b/test/linear_regression_slope.c new file mode 100644 index 0000000..4d5fd08 --- /dev/null +++ b/test/linear_regression_slope.c @@ -0,0 +1,15 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_linear_regression_slope( void ) +{ + fp_t const x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { 1, 1, 1, 1 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 5; + return ts_test(ts_linear_regression_slope, ts_linear_regression_slope_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_linear_regression_slope_p); +} diff --git a/test/linear_weighted_ma.c b/test/linear_weighted_ma.c new file mode 100644 index 0000000..5c7b212 --- /dev/null +++ b/test/linear_weighted_ma.c @@ -0,0 +1,23 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_linear_weighted_ma( void ) +{ + fp_t const x0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + fp_t const * const x[] = { x0 }; + + /* LMA with k=5: weights 1..5, sum_weights = 15 + * y[4] = (1*1 + 2*2 + 3*3 + 4*4 + 5*5) / 15 = (1+4+9+16+25)/15 = 55/15 = 3.666667 + * y[5] = (1*2 + 2*3 + 3*4 + 4*5 + 5*6) / 15 = (2+6+12+20+30)/15 = 70/15 = 4.666667 + * y[6] = (1*3 + 2*4 + 3*5 + 4*6 + 5*7) / 15 = (3+8+15+24+35)/15 = 85/15 = 5.666667 + * y[7] = (1*4 + 2*5 + 3*6 + 4*7 + 5*8) / 15 = (4+10+18+28+40)/15 = 100/15 = 6.666667 + * y[8] = (1*5 + 2*6 + 3*7 + 4*8 + 5*9) / 15 = (5+12+21+32+45)/15 = 115/15 = 7.666667 + * y[9] = (1*6 + 2*7 + 3*8 + 4*9 + 5*10) / 15 = (6+14+24+36+50)/15 = 130/15 = 8.666667 + */ + fp_t const e[] = { 3.666667, 4.666667, 5.666667, 6.666667, 7.666667, 8.666667 }; + fp_t const * const exp[] = { e }; + + uint_t c = 5; + return ts_test(ts_linear_weighted_ma, ts_linear_weighted_ma_offset, x, exp, 10, (ts_constant_t *)&c, &ts_linear_weighted_ma_p); +} diff --git a/test/log1p.c b/test/log1p.c new file mode 100644 index 0000000..86e5455 --- /dev/null +++ b/test/log1p.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_log1p( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, -0.500000, 2.000000, 0.001000 }; + fp_t const e0[] = { 0.000000, 0.693147, -0.693147, 1.098612, 0.001000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_log1p, ts_log1p_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_log1p_p); +} diff --git a/test/log1pm1.c b/test/log1pm1.c new file mode 100644 index 0000000..a4e9eaf --- /dev/null +++ b/test/log1pm1.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_log1pm1( void ) +{ + fp_t const x0[] = { 0.000000, 1.000000, 2.000000, -0.500000 }; + fp_t const e0[] = { -1.000000, -0.306853, 0.098612, -1.693147 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_log1pm1, ts_log1pm1_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_log1pm1_p); +} diff --git a/test/log_return.c b/test/log_return.c new file mode 100644 index 0000000..691ed88 --- /dev/null +++ b/test/log_return.c @@ -0,0 +1,16 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_log_return( void ) +{ + fp_t const x0[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; + fp_t const e0[] = { log(8.0 / 1.0), log(16.0 / 2.0), log(32.0 / 4.0), log(64.0 / 8.0), log(128.0 / 16.0) }; + + fp_t const * const x[] = { x0 }; + fp_t const * const e[1] = { e0 }; + + uint_t const k = 3; + + return ts_test(ts_log_return, ts_log_return_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_log_return_p); +} diff --git a/test/logarithm.c b/test/logarithm.c new file mode 100644 index 0000000..5ec3b4b --- /dev/null +++ b/test/logarithm.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_logarithm( void ) +{ + fp_t const c = 2; + + fp_t const x0[] = { 8, 27, 100 }; + fp_t const e0[] = { 3, 4.754888, 6.643856 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_logarithm, ts_logarithm_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_logarithm_p); +} diff --git a/test/logarithm_binary.c b/test/logarithm_binary.c new file mode 100644 index 0000000..5013671 --- /dev/null +++ b/test/logarithm_binary.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_logarithm_binary( void ) +{ + fp_t const x0[] = { 1, 2, 4, 8, 16 }; + fp_t const e0[] = { 0, 1, 2, 3, 4 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_logarithm_binary, ts_logarithm_binary_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_logarithm_binary_p); +} diff --git a/test/logarithm_decimal.c b/test/logarithm_decimal.c new file mode 100644 index 0000000..83da7a7 --- /dev/null +++ b/test/logarithm_decimal.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_logarithm_decimal( void ) +{ + fp_t const x0[] = { 1, 10, 100, 1000 }; + fp_t const e0[] = { 0, 1, 2, 3 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_logarithm_decimal, ts_logarithm_decimal_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_logarithm_decimal_p); +} diff --git a/test/logarithm_natural.c b/test/logarithm_natural.c new file mode 100644 index 0000000..4f955ee --- /dev/null +++ b/test/logarithm_natural.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_logarithm_natural( void ) +{ + fp_t const x0[] = { 1, 2.718282, 7.389056 }; + fp_t const e0[] = { 0, 1, 2 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_logarithm_natural, ts_logarithm_natural_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_logarithm_natural_p); +} diff --git a/test/logb.c b/test/logb.c new file mode 100644 index 0000000..346e144 --- /dev/null +++ b/test/logb.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_logb( void ) +{ + fp_t const x0[] = { 1.000000, 2.000000, 4.000000, 8.000000, 0.500000 }; + fp_t const e0[] = { 0.000000, 1.000000, 2.000000, 3.000000, -1.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_logb, ts_logb_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_logb_p); +} diff --git a/test/lowest_low.c b/test/lowest_low.c new file mode 100644 index 0000000..1ce6951 --- /dev/null +++ b/test/lowest_low.c @@ -0,0 +1,19 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_lowest_low( void ) +{ + fp_t const x0[] = { 1, 1, 1, 1, 1, 1, 1 }; + fp_t const x1[] = { 5, 7, 9, 6, 8, 10, 12 }; + fp_t const x2[] = { 1, 3, 2, 4, 1, 3, 2 }; + fp_t const x3[] = { 3, 5, 4, 6, 3, 5, 4 }; + fp_t const x4[] = { 1, 1, 1, 1, 1, 1, 1 }; + fp_t const e0[] = { 1, 2, 1, 1, 1 }; + + fp_t const * const x[] = { x0, x1, x2, x3, x4 }; + fp_t const * const e[1] = { e0 }; + + uint_t const k = 3; + + return ts_test(ts_lowest_low, ts_lowest_low_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_lowest_low_p); +} diff --git a/test/macd.c b/test/macd.c new file mode 100644 index 0000000..34d6365 --- /dev/null +++ b/test/macd.c @@ -0,0 +1,25 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_macd( void ) +{ + fp_t const x[] = { -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10 }; + + fp_t const * const inp[1] = { x }; + + /* fast=3, slow=5, signal=2 */ + /* Standard EMA: alpha = 2/(k+1) */ + /* fast_a=2/4=0.5, slow_a=2/6=0.333, sig_a=2/3=0.667 */ + + fp_t const em[4] = { 1.91968879, 2.10010502, 2.22689293, 2.31467341 }; + fp_t const es[4] = { 1.91968879, 2.03996628, 2.16458405, 2.26464362 }; + fp_t const eh[4] = { 0.00000000, 0.06013875, 0.06230888, 0.05002979 }; + + fp_t const * const exp[3] = { em, es, eh }; + + typedef struct { fp_t fast; fp_t slow; fp_t signal; } c_t; + c_t c = { .fast = 3, .slow = 5, .signal = 2 }; + + return ts_test(ts_macd, ts_macd_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&c, &ts_macd_p); +} diff --git a/test/main.c b/test/main.c new file mode 100644 index 0000000..2854d1c --- /dev/null +++ b/test/main.c @@ -0,0 +1,73 @@ +#define _POSIX_C_SOURCE 200809L +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include "ts.h" + +#include "main_generated.c" + +int main(void) +{ + struct sigaction sa = {0}; + sa.sa_handler = SIG_IGN; + sigaction(SIGALRM, &sa, NULL); + + size_t passed = 0; + size_t failed = 0; + size_t crashed = 0; + size_t skipped = 0; + + for (size_t i = 0; i < NUM_TESTS; i++) + { + pid_t pid = fork(); + if (pid < 0) { + fprintf(stderr, " SKIP %s (fork failed: %s)\n", tests[i].name, strerror(errno)); + skipped++; + continue; + } + if (pid == 0) { + bool ok = tests[i].func(); + _exit(ok ? 0 : 1); + } + int status = 0; + alarm(30); + pid_t result = waitpid(pid, &status, 0); + alarm(0); + if (result < 0) { + if (errno == EINTR) { + kill(pid, SIGKILL); + waitpid(pid, &status, 0); + fprintf(stderr, " CRASH %s (timeout)\n", tests[i].name); + crashed++; + } else { + fprintf(stderr, " CRASH %s (waitpid failed: %s)\n", tests[i].name, strerror(errno)); + crashed++; + } + continue; + } + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { + printf(" PASS %s\n", tests[i].name); + passed++; + } else if (WIFEXITED(status)) { + fprintf(stderr, " FAIL %s\n", tests[i].name); + failed++; + } else if (WIFSIGNALED(status)) { + fprintf(stderr, " CRASH %s (signal %d)\n", tests[i].name, WTERMSIG(status)); + crashed++; + } else { + fprintf(stderr, " CRASH %s\n", tests[i].name); + crashed++; + } + } + + printf("\n--- %zu tests: %zu passed, %zu failed, %zu crashed, %zu skipped ---\n", + NUM_TESTS, passed, failed, crashed, skipped); + + return (failed > 0 || crashed > 0) ? 1 : 0; +} diff --git a/test/manhattan_distance.c b/test/manhattan_distance.c new file mode 100644 index 0000000..6dfc8cf --- /dev/null +++ b/test/manhattan_distance.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_manhattan_distance( void ) +{ + fp_t const x0[] = { 3.000000, -5.000000, 0.000000, -1.000000 }; + fp_t const x1[] = { 4.000000, 12.000000, 5.000000, -2.000000 }; + fp_t const e0[] = { 7.000000, 17.000000, 5.000000, 3.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_manhattan_distance, ts_manhattan_distance_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_manhattan_distance_p); +} diff --git a/test/manhattan_norm.c b/test/manhattan_norm.c new file mode 100644 index 0000000..7395c0a --- /dev/null +++ b/test/manhattan_norm.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_manhattan_norm( void ) +{ + fp_t const x0[] = { 3.000000, -5.000000, 0.000000, 1.000000 }; + fp_t const x1[] = { 4.000000, 12.000000, 5.000000, -2.000000 }; + fp_t const e0[] = { 7.000000, 17.000000, 5.000000, 3.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_manhattan_norm, ts_manhattan_norm_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_manhattan_norm_p); +} diff --git a/test/market_facilitation_index.c b/test/market_facilitation_index.c new file mode 100644 index 0000000..78cde6f --- /dev/null +++ b/test/market_facilitation_index.c @@ -0,0 +1,23 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_market_facilitation_index( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14 }; + fp_t const h[] = { 12, 13, 14, 15, 16 }; + fp_t const l[] = { 8, 9, 10, 11, 12 }; + fp_t const c[] = { 11, 12, 13, 14, 15 }; + fp_t const v[] = { 100, 200, 300, 400, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t e[5] = { 0 }; + for( uint_t i = 0; i < 5; ++i ) + { + e[i] = ( v[i] != 0 ) ? ( h[i] - l[i] ) / v[i] : 0; + } + + fp_t const * const e_arr[1] = { e }; + + return ts_test(ts_market_facilitation_index, ts_market_facilitation_index_offset, x, e_arr, 5, (ts_constant_t *)NULL, &ts_market_facilitation_index_p); +} diff --git a/test/mass_index.c b/test/mass_index.c new file mode 100644 index 0000000..2075b59 --- /dev/null +++ b/test/mass_index.c @@ -0,0 +1,26 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_mass_index( void ) +{ + /* Use constant H-L so ratio converges to 1, sum = 26 */ + fp_t o[30] = { 0 }; + fp_t h[30]; + fp_t l[30]; + fp_t c[30] = { 0 }; + fp_t v[30] = { 0 }; + + for ( uint_t i = 0; i < 30; ++i ) + { + h[i] = 11; + l[i] = 9; + } + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t const e[4] = { 26.0, 26.0, 26.0, 26.0 }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_mass_index, ts_mass_index_offset, x, exp, 30, (ts_constant_t *)NULL, &ts_mass_index_p); +} diff --git a/test/maximum.c b/test/maximum.c new file mode 100644 index 0000000..585f30b --- /dev/null +++ b/test/maximum.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_maximum( void ) +{ + uint_t const c[] = { 3 }; + + fp_t const x0[] = { 1, 3, 2, 5, 4, 1 }; + fp_t const e0[] = { 3, 5, 5, 5 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_maximum, ts_maximum_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_maximum_p); +} diff --git a/test/median_price.c b/test/median_price.c new file mode 100644 index 0000000..3cdb1cc --- /dev/null +++ b/test/median_price.c @@ -0,0 +1,17 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_median_price( void ) +{ + fp_t const x0[] = { 1, 1, 1, 1, 1 }; + fp_t const x1[] = { 2, 4, 6, 8, 10 }; + fp_t const x2[] = { 0, 2, 4, 6, 8 }; + fp_t const x3[] = { 1, 1, 1, 1, 1 }; + fp_t const x4[] = { 1, 1, 1, 1, 1 }; + fp_t const e0[] = { 1, 3, 5, 7, 9 }; + + fp_t const * const x[] = { x0, x1, x2, x3, x4 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_median_price, ts_median_price_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_median_price_p); +} diff --git a/test/mesa_sine_wave.c b/test/mesa_sine_wave.c new file mode 100644 index 0000000..598de80 --- /dev/null +++ b/test/mesa_sine_wave.c @@ -0,0 +1,22 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_mesa_sine_wave( void ) +{ + /* k=3 */ + fp_t const x[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + + fp_t const * const inp[1] = { x }; + + /* SMA(3): 11, 12, 13, 14, 15, 16, 17, 18 */ + /* ROC: 13-11=2, 14-12=2, 15-13=2, 16-14=2, 17-15=2, 18-16=2, 19-18=2 */ + /* EMA(5) of constant 2 converges to 2, clamped to 1 */ + /* All sines = 1, all leads = 0 */ + fp_t const es[] = { 1, 1, 1, 1, 1, 1, 1 }; + fp_t const el[] = { 0, 0, 0, 0, 0, 0, 0 }; + fp_t const * const exp[2] = { es, el }; + + uint_t k = 3; + return ts_test(ts_mesa_sine_wave, ts_mesa_sine_wave_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_mesa_sine_wave_p); +} diff --git a/test/mfi.c b/test/mfi.c new file mode 100644 index 0000000..1d83db4 --- /dev/null +++ b/test/mfi.c @@ -0,0 +1,59 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_mfi( void ) +{ + uint_t k = 3; + + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + fp_t const v[] = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t tp[10] = { 0 }; + for( uint_t i = 0; i < 10; ++i ) + { + tp[i] = ( h[i] + l[i] + c[i] ) / 3.0; + } + + fp_t pos_sum = 0; + fp_t neg_sum = 0; + + for( uint_t i = 1; i <= k; ++i ) + { + fp_t raw_mf = tp[i] * v[i]; + if( tp[i] > tp[i - 1] ) + { + pos_sum += raw_mf; + } + else + { + neg_sum += raw_mf; + } + } + + fp_t e[10] = { 0 }; + e[0] = ( neg_sum == 0 ) ? 100.0 : 100.0 - 100.0 / ( 1.0 + pos_sum / neg_sum ); + + for( uint_t i = k + 1; i < 10; ++i ) + { + fp_t cur_raw_mf = tp[i] * v[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] * v[i - k]; + if( tp[i - k] > tp[i - k - 1] ) pos_sum -= old_raw_mf; + else neg_sum -= old_raw_mf; + + e[i - k] = ( neg_sum == 0 ) ? 100.0 : 100.0 - 100.0 / ( 1.0 + pos_sum / neg_sum ); + } + + fp_t const * const e_arr[1] = { e }; + + uint_t c_val = k; + + return ts_test(ts_mfi, ts_mfi_offset, x, e_arr, 10, (ts_constant_t *)&c_val, &ts_mfi_p); +} diff --git a/test/midpoint.c b/test/midpoint.c new file mode 100644 index 0000000..8048285 --- /dev/null +++ b/test/midpoint.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_midpoint( void ) +{ + fp_t const x0[] = { 1, 3, 2, 5, 4, 6, 3 }; + fp_t const e0[] = { 2, 3.5, 3.5, 5, 4.5 }; + + fp_t const * const x[] = { x0 }; + fp_t const * const e[1] = { e0 }; + + uint_t const k = 3; + + return ts_test(ts_midpoint, ts_midpoint_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_midpoint_p); +} diff --git a/test/midprice.c b/test/midprice.c new file mode 100644 index 0000000..f1634b0 --- /dev/null +++ b/test/midprice.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_midprice( void ) +{ + fp_t const x0[] = { 10, 12, 11, 14, 13, 15, 12 }; + fp_t const e0[] = { 11, 12.5, 12.5, 14, 13.5 }; + + fp_t const * const x[] = { x0 }; + fp_t const * const e[1] = { e0 }; + + uint_t const k = 3; + + return ts_test(ts_midprice, ts_midprice_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_midprice_p); +} diff --git a/test/minimum.c b/test/minimum.c new file mode 100644 index 0000000..2d4089d --- /dev/null +++ b/test/minimum.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_minimum( void ) +{ + uint_t const c[] = { 3 }; + + fp_t const x0[] = { 1, 3, 2, 5, 4, 1 }; + fp_t const e0[] = { 1, 2, 2, 1 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_minimum, ts_minimum_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_minimum_p); +} diff --git a/test/minmax.c b/test/minmax.c new file mode 100644 index 0000000..64ba78b --- /dev/null +++ b/test/minmax.c @@ -0,0 +1,17 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_minmax( void ) +{ + uint_t k = 3; + + fp_t const x[] = { 1, 3, 2, 5, 4, 1, 6, 3, 2, 4 }; + fp_t const emin[] = { 1, 2, 2, 1, 1, 1, 2, 2 }; + fp_t const emax[] = { 3, 5, 5, 5, 6, 6, 6, 4 }; + + fp_t const * const inp[1] = { x }; + fp_t const * const exp[2] = { emin, emax }; + + return ts_test(ts_minmax, ts_minmax_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_minmax_p); +} diff --git a/test/missing_bar_count.c b/test/missing_bar_count.c new file mode 100644 index 0000000..e15e634 --- /dev/null +++ b/test/missing_bar_count.c @@ -0,0 +1,28 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_missing_bar_count( void ) +{ + fp_t threshold = 0.5; + + fp_t const x[] = { 10, 10.1, 10.2, 10.1, 11, 11.1, 11.2, 11.3, 12.5, 12.6 }; + + fp_t const * const inp[1] = { x }; + + /* i=0: 0 + * i=1: |10.1-10|=0.1 < 0.5, count=1 + * i=2: |10.2-10.1|=0.1 < 0.5, count=2 + * i=3: |10.1-10.2|=0.1 < 0.5, count=3 + * i=4: |11-10.1|=0.9 >= 0.5, count=0 + * i=5: |11.1-11|=0.1 < 0.5, count=1 + * i=6: |11.2-11.1|=0.1 < 0.5, count=2 + * i=7: |11.3-11.2|=0.1 < 0.5, count=3 + * i=8: |12.5-11.3|=1.2 >= 0.5, count=0 + * i=9: |12.6-12.5|=0.1 < 0.5, count=1 + */ + fp_t const e[] = { 0, 1, 2, 3, 0, 1, 2, 3, 0, 1 }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_missing_bar_count, ts_missing_bar_count_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&threshold, &ts_missing_bar_count_p); +} diff --git a/test/momentum.c b/test/momentum.c new file mode 100644 index 0000000..78772dc --- /dev/null +++ b/test/momentum.c @@ -0,0 +1,19 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_momentum( void ) +{ + /* k=3, close: 10, 12, 14, 16, 18, 20 */ + /* i=3: 16-10 = 6 */ + /* i=4: 18-12 = 6 */ + /* i=5: 20-14 = 6 */ + fp_t const x[] = { 10, 12, 14, 16, 18, 20 }; + + fp_t const * const inp[1] = { x }; + fp_t const e[] = { 6, 6, 6 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_momentum, ts_momentum_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_momentum_p); +} diff --git a/test/money_flow_multiplier.c b/test/money_flow_multiplier.c new file mode 100644 index 0000000..58ca4c9 --- /dev/null +++ b/test/money_flow_multiplier.c @@ -0,0 +1,17 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_money_flow_multiplier( void ) +{ + fp_t const o[] = { 9, 10, 11, 12, 13 }; + fp_t const h[] = { 10, 11, 12, 13, 14 }; + fp_t const l[] = { 8, 9, 10, 11, 12 }; + fp_t const c[] = { 9.5, 10.5, 11.5, 12.5, 13.5 }; + fp_t const v[] = { 100, 200, 300, 400, 500 }; + fp_t const e0[] = { 0.5, 0.5, 0.5, 0.5, 0.5 }; + + fp_t const * const x[5] = { o, h, l, c, v }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_money_flow_multiplier, ts_money_flow_multiplier_offset, x, e, sizeof( o ) / sizeof( *o ), (ts_constant_t *)NULL, &ts_money_flow_multiplier_p); +} diff --git a/test/moving_linear_regression.c b/test/moving_linear_regression.c new file mode 100644 index 0000000..dd7add0 --- /dev/null +++ b/test/moving_linear_regression.c @@ -0,0 +1,15 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_moving_linear_regression( void ) +{ + fp_t const x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { 5, 6, 7, 8 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 5; + return ts_test(ts_moving_linear_regression, ts_moving_linear_regression_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_moving_linear_regression_p); +} diff --git a/test/moving_linear_regression_r2.c b/test/moving_linear_regression_r2.c new file mode 100644 index 0000000..9013584 --- /dev/null +++ b/test/moving_linear_regression_r2.c @@ -0,0 +1,15 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_moving_linear_regression_r2( void ) +{ + fp_t const x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { 1.0, 1.0, 1.0, 1.0 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 5; + return ts_test(ts_moving_linear_regression_r2, ts_moving_linear_regression_r2_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_moving_linear_regression_r2_p); +} diff --git a/test/multiplication.c b/test/multiplication.c new file mode 100644 index 0000000..ad61fb0 --- /dev/null +++ b/test/multiplication.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_multiplication( void ) +{ + fp_t const x0[] = { 3, 5, 7 }; + fp_t const x1[] = { 2, 4, 6 }; + fp_t const e0[] = { 6, 20, 42 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_multiplication, ts_multiplication_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_multiplication_p); +} diff --git a/test/nan_fn.c b/test/nan_fn.c new file mode 100644 index 0000000..e0f29ec --- /dev/null +++ b/test/nan_fn.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_nan_fn( void ) +{ + fp_t const x0[] = { 1, 2, 3 }; + fp_t out[3]; + ts_nan_fn( (fp_t*[]){out}, 1, (fp_t const *[]){x0}, 1, 3, NULL ); + /* Verify all outputs are NaN */ + for ( uint_t i = 0; i < 3; ++i ) + if ( out[i] == out[i] ) return false; /* not NaN */ + return true; +} diff --git a/test/natr.c b/test/natr.c new file mode 100644 index 0000000..614754f --- /dev/null +++ b/test/natr.c @@ -0,0 +1,22 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_natr( void ) +{ + fp_t const o[] = { 9, 11, 10, 12, 12, 13, 11, 14, 13, 15 }; + fp_t const h[] = { 10, 12, 11, 13, 12, 14, 12, 15, 14, 16 }; + fp_t const l[] = { 8, 9, 10, 11, 10, 12, 11, 13, 12, 14 }; + fp_t const c[] = { 9, 10, 12, 11, 13, 11, 14, 12, 15, 13 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* ATR values: 2.0, 1.66667, 2.0, 1.66667, 1.66667, 1.66667, 2.0 */ + /* C at idx 3-9: 11, 13, 11, 14, 12, 15, 13 */ + /* NATR = ATR/C*100 */ + fp_t const e[] = { 18.18182, 12.82051, 18.18182, 11.90476, 13.88889, 11.11111, 15.38462 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_natr, ts_natr_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_natr_p); +} diff --git a/test/nearbyint.c b/test/nearbyint.c new file mode 100644 index 0000000..b17e10c --- /dev/null +++ b/test/nearbyint.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_nearbyint( void ) +{ + fp_t const x0[] = { -2.700000, -1.300000, 0.300000, 0.700000, 1.500000, 2.700000 }; + fp_t const e0[] = { -3.000000, -1.000000, 0.000000, 1.000000, 2.000000, 3.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_nearbyint, ts_nearbyint_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_nearbyint_p); +} diff --git a/test/nextafter.c b/test/nextafter.c new file mode 100644 index 0000000..c7e882b --- /dev/null +++ b/test/nextafter.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_nextafter( void ) +{ + fp_t const x0[] = { 1.000000, 1.000000, 0.000000 }; + fp_t const x1[] = { 2.000000, 0.000000, 1.000000 }; + fp_t const e0[] = { 1.000000, 1.000000, 0.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_nextafter, ts_nextafter_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_nextafter_p); +} diff --git a/test/nexttoward.c b/test/nexttoward.c new file mode 100644 index 0000000..32d41cc --- /dev/null +++ b/test/nexttoward.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_nexttoward( void ) +{ + fp_t const x0[] = { 1.000000, 1.000000, 0.000000 }; + fp_t const x1[] = { 2.000000, 0.000000, 1.000000 }; + fp_t const e0[] = { 1.000000, 1.000000, 0.000000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_nexttoward, ts_nexttoward_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_nexttoward_p); +} diff --git a/test/none.c b/test/none.c new file mode 100644 index 0000000..80d9f9e --- /dev/null +++ b/test/none.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_none( void ) +{ + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 1, 2, 3, 4, 5 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_none, ts_none_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_none_p); +} diff --git a/test/nvi.c b/test/nvi.c new file mode 100644 index 0000000..87b3ddb --- /dev/null +++ b/test/nvi.c @@ -0,0 +1,38 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_nvi( void ) +{ + fp_t const o[] = { 10, 11, 12, 11, 12 }; + fp_t const h[] = { 12, 13, 14, 12, 14 }; + fp_t const l[] = { 8, 9, 10, 9, 10 }; + fp_t const c[] = { 11, 12, 10, 11, 11 }; + fp_t const v[] = { 100, 200, 300, 400, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t nvi = 1000; + + nvi = 1000; + fp_t e[5] = { nvi }; + + e[1] = nvi; + if( v[1] < v[0] ) { fp_t r = (c[1] - c[0]) / c[0]; nvi = nvi * (1 + r); e[1] = nvi; } + else { e[1] = nvi; } + + if( v[2] < v[1] ) { fp_t r = (c[2] - c[1]) / c[1]; nvi = nvi * (1 + r); } + else { /* unchanged */ } + e[2] = nvi; + + if( v[3] < v[2] ) { fp_t r = (c[3] - c[2]) / c[2]; nvi = nvi * (1 + r); } + else { /* unchanged */ } + e[3] = nvi; + + if( v[4] < v[3] ) { fp_t r = (c[4] - c[3]) / c[3]; nvi = nvi * (1 + r); } + else { /* unchanged */ } + e[4] = nvi; + + fp_t const * const e_arr[1] = { e }; + + return ts_test(ts_nvi, ts_nvi_offset, x, e_arr, 5, (ts_constant_t *)NULL, &ts_nvi_p); +} diff --git a/test/obv.c b/test/obv.c new file mode 100644 index 0000000..112740e --- /dev/null +++ b/test/obv.c @@ -0,0 +1,18 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_obv( void ) +{ + fp_t const o[] = { 10, 11, 12, 11, 12 }; + fp_t const h[] = { 12, 13, 14, 12, 14 }; + fp_t const l[] = { 8, 9, 10, 9, 10 }; + fp_t const c[] = { 11, 12, 10, 11, 11 }; + fp_t const v[] = { 100, 200, 300, 400, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t const e[] = { 200, -100, 300, 300 }; + fp_t const * const e_arr[1] = { e }; + + return ts_test(ts_obv, ts_obv_offset, x, e_arr, 5, (ts_constant_t *)NULL, &ts_obv_p); +} diff --git a/test/on_balance_volume_rate.c b/test/on_balance_volume_rate.c new file mode 100644 index 0000000..65e3ac1 --- /dev/null +++ b/test/on_balance_volume_rate.c @@ -0,0 +1,45 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_on_balance_volume_rate( void ) +{ + uint_t k = TS_TEST_K; + + fp_t const o[] = { 10, 11, 12, 11, 12, 10, 11, 13, 12, 14 }; + fp_t const h[] = { 12, 13, 14, 12, 14, 11, 12, 15, 14, 16 }; + fp_t const l[] = { 8, 9, 10, 9, 10, 9, 10, 11, 10, 12 }; + fp_t const c[] = { 11, 12, 10, 11, 11, 10, 12, 14, 13, 15 }; + fp_t const v[] = { 100, 200, 300, 400, 500, 300, 200, 400, 300, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t obv_buf[10] = { 0 }; + fp_t obv = 0; + + for( uint_t i = 1; i < 10; ++i ) + { + if( c[i] > c[i-1] ) + { + obv += v[i]; + } + else if( c[i] < c[i-1] ) + { + obv -= v[i]; + } + obv_buf[i] = obv; + } + + fp_t e[4] = { 0 }; + + for( uint_t i = k + 1; i < 10; ++i ) + { + fp_t obv_prev = obv_buf[i - k]; + e[i - (k + 1)] = obv_prev != 0 ? ( obv_buf[i] - obv_prev ) / obv_prev * 100 : 0; + } + + fp_t const * const e_arr[1] = { e }; + + fp_t c_val = k; + + return ts_test(ts_on_balance_volume_rate, ts_on_balance_volume_rate_offset, x, e_arr, 10, (ts_constant_t *)&c_val, &ts_on_balance_volume_rate_p); +} diff --git a/test/open_interest.c b/test/open_interest.c new file mode 100644 index 0000000..165c3c5 --- /dev/null +++ b/test/open_interest.c @@ -0,0 +1,14 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_open_interest( void ) +{ + fp_t const x[] = { 100, 200, 300, 400, 500 }; + fp_t const e[] = { 100, 200, 300, 400, 500 }; + + fp_t const * const inp[1] = { x }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_open_interest, ts_open_interest_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)NULL, &ts_open_interest_p); +} diff --git a/test/open_minus_close.c b/test/open_minus_close.c new file mode 100644 index 0000000..329b678 --- /dev/null +++ b/test/open_minus_close.c @@ -0,0 +1,17 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_open_minus_close( void ) +{ + fp_t const x0[] = { 5, 10, 15, 20, 25 }; + fp_t const x1[] = { 6, 11, 16, 21, 26 }; + fp_t const x2[] = { 0, 5, 10, 15, 20 }; + fp_t const x3[] = { 3, 8, 13, 18, 23 }; + fp_t const x4[] = { 1, 1, 1, 1, 1 }; + fp_t const e0[] = { 2, 2, 2, 2, 2 }; + + fp_t const * const x[] = { x0, x1, x2, x3, x4 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_open_minus_close, ts_open_minus_close_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_open_minus_close_p); +} diff --git a/test/oscillator_cross.c b/test/oscillator_cross.c new file mode 100644 index 0000000..323718b --- /dev/null +++ b/test/oscillator_cross.c @@ -0,0 +1,40 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_oscillator_cross( void ) +{ + /* Data that goes down then up, producing a clear crossover */ + fp_t const x[] = { 10, 9, 8, 7, 6, 5, 6, 7, 8, 9 }; + + fp_t const * const inp[1] = { x }; + + /* fast=2, slow=4 */ + fp_t fast_e = 10, slow_e = 10; + fp_t fast_a = 1.0 / 2, slow_a = 1.0 / 4; + fp_t e[6] = { 0 }; + + for( uint_t i = 1; i < 10; ++i ) + { + fp_t pf = fast_e, ps = slow_e; + fast_e = fast_e + fast_a * ( x[i] - fast_e ); + slow_e = slow_e + slow_a * ( x[i] - slow_e ); + + if( i >= 4 ) + { + if( fast_e > slow_e && pf <= ps ) + e[i - 4] = 1; + else if( fast_e < slow_e && pf >= ps ) + e[i - 4] = -1; + else + e[i - 4] = 0; + } + } + + fp_t const * const exp[1] = { e }; + + typedef struct { fp_t fast; fp_t slow; } c_t; + c_t c = { .fast = 2, .slow = 4 }; + + return ts_test(ts_oscillator_cross, ts_oscillator_cross_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&c, &ts_oscillator_cross_p); +} diff --git a/test/osma.c b/test/osma.c new file mode 100644 index 0000000..5a94bb9 --- /dev/null +++ b/test/osma.c @@ -0,0 +1,20 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_osma( void ) +{ + fp_t const x[] = { -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10 }; + + fp_t const * const inp[1] = { x }; + + /* fast=3, slow=5, signal=2 */ + fp_t const e[4] = { 0.24499095, 0.34043610, 0.35920247, 0.34054338 }; + + fp_t const * const exp[1] = { e }; + + typedef struct { fp_t fast; fp_t slow; fp_t signal; } c_t; + c_t c = { .fast = 3, .slow = 5, .signal = 2 }; + + return ts_test(ts_osma, ts_osma_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&c, &ts_osma_p); +} diff --git a/test/parabolic_sar.c b/test/parabolic_sar.c new file mode 100644 index 0000000..ffee1bf --- /dev/null +++ b/test/parabolic_sar.c @@ -0,0 +1,22 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_parabolic_sar( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* step=0.02, max=0.2, uptrend throughout */ + fp_t const esar[] = { 9.000000, 9.000000, 9.060000, 9.217600, 9.504544, 9.944180, 10.549762, 11.323791, 12.258460, 13.337107 }; + fp_t const edir[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + fp_t const * const exp[2] = { esar, edir }; + + typedef struct { fp_t step; fp_t max_af; } c_t; + c_t consts = { .step = 0.02, .max_af = 0.2 }; + return ts_test(ts_parabolic_sar, ts_parabolic_sar_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&consts, &ts_parabolic_sar_p); +} diff --git a/test/performance_index.c b/test/performance_index.c new file mode 100644 index 0000000..e31ec98 --- /dev/null +++ b/test/performance_index.c @@ -0,0 +1,16 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_performance_index( void ) +{ + fp_t const x0[] = { 10, 20, 30, 40, 50 }; + fp_t const x1[] = { 11, 22, 33, 44, 55 }; + fp_t const x2[] = { 9, 18, 28, 38, 48 }; + fp_t const x3[] = { 12, 21, 31, 41, 51 }; + fp_t const e0[] = { 20, 5, 3.333333, 2.5, 2 }; + + fp_t const * const x[] = { x0, x1, x2, x3 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_performance_index, ts_performance_index_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_performance_index_p); +} diff --git a/test/performance_ratio.c b/test/performance_ratio.c new file mode 100644 index 0000000..74ff1bd --- /dev/null +++ b/test/performance_ratio.c @@ -0,0 +1,17 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_performance_ratio( void ) +{ + uint_t k = 3; + + fp_t const x[] = { 100, 101, 102, 103, 104, 105, 106, 107, 108, 109 }; + + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { 123.693169, 124.917973, 126.142776, 127.367579, 128.592379, 129.817179, 131.041978 }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_performance_ratio, ts_performance_ratio_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_performance_ratio_p); +} diff --git a/test/pivot_points.c b/test/pivot_points.c new file mode 100644 index 0000000..08138b6 --- /dev/null +++ b/test/pivot_points.c @@ -0,0 +1,27 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_pivot_points( void ) +{ + fp_t const o[] = { 10, 12, 11, 14, 13, 15, 16, 14, 17, 18 }; + fp_t const h[] = { 12, 14, 13, 16, 15, 17, 18, 16, 19, 20 }; + fp_t const l[] = { 9, 11, 10, 13, 12, 14, 15, 13, 16, 17 }; + fp_t const c[] = { 11, 13, 12, 15, 14, 16, 17, 15, 18, 19 }; + fp_t const v[] = { 100, 200, 150, 180, 160, 190, 210, 170, 200, 220 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + /* Using prev bar OHLC */ + /* i=1: prev=bar0, P=(12+9+11)/3=10.667, R1=2*10.667-9=12.333, S1=2*10.667-12=9.333, R2=10.667+3=13.667, S2=10.667-3=7.667 */ + /* i=2: prev=bar1, P=(14+11+13)/3=12.667, R1=2*12.667-11=14.333, S1=2*12.667-14=11.333, R2=12.667+3=15.667, S2=12.667-3=9.667 */ + fp_t const ep[] = { 10.666667, 12.666667, 11.666667, 14.666667, 13.666667, 15.666667, 16.666667, 14.666667, 17.666667 }; + fp_t const er1[] = { 12.333333, 14.333333, 13.333333, 16.333333, 15.333333, 17.333333, 18.333333, 16.333333, 19.333333 }; + fp_t const es1[] = { 9.333333, 11.333333, 10.333333, 13.333333, 12.333333, 14.333333, 15.333333, 13.333333, 16.333333 }; + fp_t const er2[] = { 13.666667, 15.666667, 14.666667, 17.666667, 16.666667, 18.666667, 19.666667, 17.666667, 20.666667 }; + fp_t const es2[] = { 7.666667, 9.666667, 8.666667, 11.666667, 10.666667, 12.666667, 13.666667, 11.666667, 14.666667 }; + fp_t const * const exp[5] = { ep, er1, es1, er2, es2 }; + + return ts_test(ts_pivot_points, ts_pivot_points_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)NULL, &ts_pivot_points_p); +} + diff --git a/test/plot.c b/test/plot.c new file mode 100644 index 0000000..f697af7 --- /dev/null +++ b/test/plot.c @@ -0,0 +1,14 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_plot( void ) +{ + fp_t const x[] = { 1, 2, 3, 4, 5 }; + fp_t const e[] = { 1, 2, 3, 4, 5 }; + + fp_t const * const inp[1] = { x }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_plot, ts_plot_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)NULL, &ts_plot_p); +} diff --git a/test/poisson_pdf.c b/test/poisson_pdf.c new file mode 100644 index 0000000..0dfc9f2 --- /dev/null +++ b/test/poisson_pdf.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_poisson_pdf( void ) +{ + fp_t const c[] = { 3.000000 }; + + fp_t const x0[] = { 0.000000, 1.000000, 2.000000, 3.000000, 4.000000, 5.000000 }; + fp_t const e0[] = { 0.049787, 0.149361, 0.224042, 0.224042, 0.168031, 0.100819 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_poisson_pdf, ts_poisson_pdf_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_poisson_pdf_p); +} diff --git a/test/polynomial.c b/test/polynomial.c new file mode 100644 index 0000000..1591343 --- /dev/null +++ b/test/polynomial.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_polynomial( void ) +{ + /* y = x0 ^ x1 */ + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const x1[] = { 0, 1, 2, 3, 4 }; + fp_t const e0[] = { 1, 2, 9, 64, 625 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_polynomial, ts_polynomial_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), NULL, &ts_polynomial_p); +} diff --git a/test/power.c b/test/power.c new file mode 100644 index 0000000..07bf08f --- /dev/null +++ b/test/power.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_power( void ) +{ + fp_t const c[] = { 2.0 }; + + fp_t const x0[] = { 0, 1, 2, 3, 4 }; + fp_t const e0[] = { 0, 1, 4, 9, 16 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_power, ts_power_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_power_p); +} diff --git a/test/ppo.c b/test/ppo.c new file mode 100644 index 0000000..c513567 --- /dev/null +++ b/test/ppo.c @@ -0,0 +1,21 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_ppo( void ) +{ + fp_t const x[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + + fp_t const * const inp[1] = { x }; + + /* fast=3, slow=5, signal=2 */ + fp_t const ep[5] = { 7.73841405, 8.63701135, 9.23626984, 9.58993759, 9.75198730 }; + fp_t const es[5] = { 7.11991901, 7.87846518, 8.55736751, 9.07365255, 9.41281993 }; + + fp_t const * const exp[2] = { ep, es }; + + typedef struct { fp_t fast; fp_t slow; fp_t signal; } c_t; + c_t c = { .fast = 3, .slow = 5, .signal = 2 }; + + return ts_test(ts_ppo, ts_ppo_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&c, &ts_ppo_p); +} diff --git a/test/pretty_good_oscillator.c b/test/pretty_good_oscillator.c new file mode 100644 index 0000000..320c816 --- /dev/null +++ b/test/pretty_good_oscillator.c @@ -0,0 +1,27 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_pretty_good_oscillator( void ) +{ + fp_t const x[] = { 95, 100, 105, 110, 102, 115, 120, 112, 125, 130, 122, 135 }; + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { + 0.0000000000, + 0.0511756570, + 0.1007296091, + 0.1485166224, + 0.0631698925, + 0.1924376246, + 0.2363349679, + 0.1492577606, + 0.2731834852, + 0.3129126874, + 0.2246375214, + 0.3425844656 + }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_pretty_good_oscillator, ts_pretty_good_oscillator_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)NULL, &ts_pretty_good_oscillator_p); +} diff --git a/test/price_channel.c b/test/price_channel.c new file mode 100644 index 0000000..ba16e69 --- /dev/null +++ b/test/price_channel.c @@ -0,0 +1,21 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_price_channel( void ) +{ + fp_t const x[] = { 10, 12, 11, 14, 13, 15, 16, 14, 17, 18 }; + fp_t const * const inp[1] = { x }; + + /* k=3, offset=2, y_n=8 */ + /* HH3: 12,14,14,15,16,16,17,18 */ + /* LL3: 10,11,11,13,13,14,14,14 */ + /* SMA3: 11,12.333,12.667,14,14.667,15,15.667,16.333 */ + fp_t const eu[] = { 12, 14, 14, 15, 16, 16, 17, 18 }; + fp_t const em[] = { 11, 12.33333, 12.66667, 14, 14.66667, 15, 15.66667, 16.33333 }; + fp_t const el[] = { 10, 11, 11, 13, 13, 14, 14, 14 }; + fp_t const * const exp[3] = { eu, em, el }; + + uint_t k = 3; + return ts_test(ts_price_channel, ts_price_channel_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_price_channel_p); +} diff --git a/test/price_momentum_oscillator.c b/test/price_momentum_oscillator.c new file mode 100644 index 0000000..31b7724 --- /dev/null +++ b/test/price_momentum_oscillator.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_price_momentum_oscillator( void ) +{ + fp_t const x0[] = { 100, 110, 120, 130, 140, 150, 160 }; + fp_t const e0[] = { 20, 18.181818, 16.666667, 15.384615, 14.285714 }; + + fp_t const * const x[] = { x0 }; + fp_t const * const e[1] = { e0 }; + + uint_t k = 2; + + return ts_test(ts_price_momentum_oscillator, ts_price_momentum_oscillator_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_price_momentum_oscillator_p); +} diff --git a/test/price_rate_of_change.c b/test/price_rate_of_change.c new file mode 100644 index 0000000..ec3eb9c --- /dev/null +++ b/test/price_rate_of_change.c @@ -0,0 +1,27 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_price_rate_of_change( void ) +{ + fp_t const x[] = { 100, 110, 120, 130, 140, 150, 160, 170, 180, 190 }; + + fp_t const * const inp[1] = { x }; + + /* k=3 */ + /* PROC[3] = (130-100)/100*100 = 30 */ + /* PROC[4] = (140-110)/110*100 = 27.2727 */ + /* PROC[5] = (150-120)/120*100 = 25 */ + /* PROC[6] = (160-130)/130*100 = 23.0769 */ + /* PROC[7] = (170-140)/140*100 = 21.4286 */ + /* PROC[8] = (180-150)/150*100 = 20 */ + /* PROC[9] = (190-160)/160*100 = 18.75 */ + + fp_t e[] = { 30.0, 27.272727272727273, 25.0, 23.076923076923077, 21.428571428571427, 20.0, 18.75 }; + + fp_t const * const exp[1] = { e }; + + uint_t c_val = 3; + + return ts_test(ts_price_rate_of_change, ts_price_rate_of_change_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&c_val, &ts_price_rate_of_change_p); +} diff --git a/test/prime_number_bands.c b/test/prime_number_bands.c new file mode 100644 index 0000000..6d0b211 --- /dev/null +++ b/test/prime_number_bands.c @@ -0,0 +1,17 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_prime_number_bands( void ) +{ + uint_t const c = 3; + + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 2, 3, 4 }; + fp_t const e1[] = { 3.632993, 4.632993, 5.632993 }; + fp_t const e2[] = { 0.367007, 1.367007, 2.367007 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[3] = { e0, e1, e2 }; + + return ts_test(ts_prime_number_bands, ts_prime_number_bands_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_prime_number_bands_p); +} diff --git a/test/prime_number_oscillator.c b/test/prime_number_oscillator.c new file mode 100644 index 0000000..aa6b575 --- /dev/null +++ b/test/prime_number_oscillator.c @@ -0,0 +1,23 @@ +#include <stddef.h> +#include <stdlib.h> +#include "ts.h" + +bool ts_test_prime_number_oscillator( void ) +{ + uint_t n = 25; + fp_t *x0 = malloc( n * sizeof( fp_t ) ); + if ( !x0 ) return false; + + for ( uint_t i = 0; i < n; ++i ) + x0[i] = (fp_t)(10 + i); + + fp_t const * const inp[1] = { x0 }; + + fp_t const e[] = { 2, 2 }; + fp_t const * const exp[1] = { e }; + + bool result = ts_test(ts_prime_number_oscillator, ts_prime_number_oscillator_offset, inp, exp, n, (ts_constant_t *)NULL, &ts_prime_number_oscillator_p); + + free( x0 ); + return result; +} diff --git a/test/prings_kst.c b/test/prings_kst.c new file mode 100644 index 0000000..8a1bd28 --- /dev/null +++ b/test/prings_kst.c @@ -0,0 +1,55 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_prings_kst( void ) +{ + fp_t const x[] = { + 100, 105, 98, 110, 102, 115, 108, 120, 112, 125, + 118, 130, 122, 135, 128, 140, 132, 145, 138, 150, + 142, 155, 148, 160, 152, 165, 158, 170, 162, 175, + 168, 180, 172, 185, 178, 190, 182, 195, 188, 200, + 192, 205, 198, 210, 202, 215, 208, 220, 212, 225, + 218, 230, 222, 235, 228, 240 + }; + + fp_t const * const inp[1] = { x }; + + fp_t const e0[] = { + 51.9408578539013, 75.1308260917654, 78.103866719, + 94.8088438575893, 92.483818257572, 105.456228286493, + 101.394220195137, 111.288138429023, 104.640206278203, + 113.013133431368, 106.311034357386, 113.131203505727, + 105.038276407899, 111.304589974597, 103.842952160622, + 109.243663263608, 100.915323682376, 106.178344115008, + 98.7322514625897, 103.443195102946, 95.3595796482774, + 100.10652950864, 92.9706808772205, 97.3126510773803, + 89.6400548204848, 94.0861019609992, 87.3507958601018, + 91.4647371720775, 84.2384208045559, 88.4793019904416, + 82.1513111963106, 86.0996943377378, 79.3034333929425, + 83.3828886921002, 77.4376734462827, 81.2491274609335, + 74.8491800513007, 78.788567419848, 73.1922770738286, + 76.8810806798416, 70.8401912421373, 74.6513723261792, + 69.3696853171888, 72.9441719183728, 67.2269459044808, + 70.9178130955952, 65.9191399381158 + }; + fp_t const e1[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 90.5830006631871, + 93.3867672592096, 95.0023006464817, 97.2684135038873, + 98.2396463668887, 99.8727643178523, 100.369037798198, + 101.478365981375, 101.407985694, 102.004280496626, + 101.595276867371, 101.826266646818, 101.017930772, + 100.90400561408, 99.9123400219729, 99.5873789038989, + 98.3439633934721, 97.811730714413, 96.5041138576241, + 95.8741917719308, 94.4197204010089, 93.677168099688, + 92.2364359867658, 91.4693432806373, 89.9486045446755, + 89.1278900631035, 87.6666129860009, 86.8644272953675, + 85.3625213898592, 84.5407771436078, 83.1222146348854, + 82.3420728905049, 80.9043376844589, 80.122717014674, + 78.7785880524883, 78.0492860357239, 76.6964935193185, + 75.9741584663531, 74.7172811503234 + }; + fp_t const * const exp[2] = { e0, e1 }; + + return ts_test(ts_prings_kst, ts_prings_kst_offset, inp, exp, 55, (ts_constant_t *)NULL, &ts_prings_kst_p); +} diff --git a/test/prings_special_k.c b/test/prings_special_k.c new file mode 100644 index 0000000..41e6a89 --- /dev/null +++ b/test/prings_special_k.c @@ -0,0 +1,23 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_prings_special_k( void ) +{ + /* k1=3, k2=2 */ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, c }; + +/* Monotonically increasing: %K_raw = 80 for all windows */ + fp_t const ek[] = { 80, 80, 80, 80, 80, 80, 80 }; + fp_t const ed[] = { 80, 80, 80, 80, 80, 80, 80 }; + fp_t const * const exp[2] = { ek, ed }; + + typedef struct { uint_t k1; uint_t k2; } c_t; + c_t constants = { .k1 = 3, .k2 = 2 }; + + return ts_test(ts_prings_special_k, ts_prings_special_k_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&constants, &ts_prings_special_k_p); +} diff --git a/test/psychological_line.c b/test/psychological_line.c new file mode 100644 index 0000000..711923c --- /dev/null +++ b/test/psychological_line.c @@ -0,0 +1,23 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_psychological_line( void ) +{ + fp_t const x0[] = { 10, 10, 20, 20, 30 }; + fp_t const x1[] = { 12, 11, 22, 19, 32 }; + fp_t const x2[] = { 9, 9, 19, 18, 29 }; + fp_t const x3[] = { 11, 10, 21, 20, 31 }; + + uint_t const k = 2; + + fp_t e[4]; + e[0] = 50; + e[1] = 50; + e[2] = 50; + e[3] = 50; + + fp_t const * const x[] = { x0, x1, x2, x3 }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_psychological_line, ts_psychological_line_offset, x, exp, 5, (ts_constant_t *)&k, &ts_psychological_line_p); +} diff --git a/test/pvi.c b/test/pvi.c new file mode 100644 index 0000000..51b4e5c --- /dev/null +++ b/test/pvi.c @@ -0,0 +1,34 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_pvi( void ) +{ + fp_t const o[] = { 10, 11, 12, 11, 12 }; + fp_t const h[] = { 12, 13, 14, 12, 14 }; + fp_t const l[] = { 8, 9, 10, 9, 10 }; + fp_t const c[] = { 11, 12, 10, 11, 11 }; + fp_t const v[] = { 100, 200, 300, 400, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t pvi = 1000; + fp_t full[5]; + full[0] = pvi; + + if( v[1] > v[0] ) { fp_t r = (c[1] - c[0]) / c[0]; pvi = pvi * (1 + r); } + full[1] = pvi; + + if( v[2] > v[1] ) { fp_t r = (c[2] - c[1]) / c[1]; pvi = pvi * (1 + r); } + full[2] = pvi; + + if( v[3] > v[2] ) { fp_t r = (c[3] - c[2]) / c[2]; pvi = pvi * (1 + r); } + full[3] = pvi; + + if( v[4] > v[3] ) { fp_t r = (c[4] - c[3]) / c[3]; pvi = pvi * (1 + r); } + full[4] = pvi; + + fp_t const e[] = { full[0], full[1], full[2], full[3], full[4] }; + fp_t const * const e_arr[1] = { e }; + + return ts_test(ts_pvi, ts_pvi_offset, x, e_arr, 5, (ts_constant_t *)NULL, &ts_pvi_p); +} diff --git a/test/pvt.c b/test/pvt.c new file mode 100644 index 0000000..6abccb4 --- /dev/null +++ b/test/pvt.c @@ -0,0 +1,27 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_pvt( void ) +{ + fp_t const o[] = { 10, 11, 12, 11, 12 }; + fp_t const h[] = { 12, 13, 14, 12, 14 }; + fp_t const l[] = { 8, 9, 10, 9, 10 }; + fp_t const c[] = { 11, 12, 10, 11, 11 }; + fp_t const v[] = { 100, 200, 300, 400, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t pvt = 0; + fp_t full[5] = { 0 }; + + for( uint_t i = 1; i < 5; ++i ) + { + pvt += ( c[i] / c[i-1] - 1 ) * v[i]; + full[i] = pvt; + } + + fp_t const e[] = { full[1], full[2], full[3], full[4] }; + fp_t const * const e_arr[1] = { e }; + + return ts_test(ts_pvt, ts_pvt_offset, x, e_arr, 5, (ts_constant_t *)NULL, &ts_pvt_p); +} diff --git a/test/qstick.c b/test/qstick.c new file mode 100644 index 0000000..daa13d2 --- /dev/null +++ b/test/qstick.c @@ -0,0 +1,24 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_qstick( void ) +{ + fp_t const x0[] = { 10, 10, 10, 20, 20, 30 }; + fp_t const x1[] = { 12, 13, 12, 22, 23, 33 }; + fp_t const x2[] = { 9, 9, 10, 19, 20, 29 }; + fp_t const x3[] = { 11, 12, 11, 21, 22, 31 }; + + fp_t const * const x[] = { x0, x1, x2, x3 }; + + uint_t k = 3; + fp_t e[4]; + e[0] = ((11 - 10) + (12 - 10) + (11 - 10)) / 3.0; + e[1] = e[0] + ((21 - 20) - (11 - 10)) / 3.0; + e[2] = e[1] + ((22 - 20) - (12 - 10)) / 3.0; + e[3] = e[2] + ((31 - 30) - (11 - 10)) / 3.0; + + fp_t const * const exp[1] = { e }; + + return ts_test(ts_qstick, ts_qstick_offset, x, exp, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_qstick_p); +} diff --git a/test/radian_degree.c b/test/radian_degree.c new file mode 100644 index 0000000..f3f74aa --- /dev/null +++ b/test/radian_degree.c @@ -0,0 +1,14 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_radian_degree( void ) +{ + fp_t const x[] = { 0, PI / 6, PI / 4, PI / 3, HALF_PI, PI, 3 * HALF_PI, 2 * PI }; + fp_t const e[] = { 0, 30, 45, 60, 90, 180, 270, 360 }; + + fp_t const * const inp[1] = { x }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_radian_degree, ts_radian_degree_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)NULL, &ts_radian_degree_p); +} diff --git a/test/rainbow_ma.c b/test/rainbow_ma.c new file mode 100644 index 0000000..a5fefe3 --- /dev/null +++ b/test/rainbow_ma.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_rainbow_ma( void ) +{ + fp_t const x0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const e0[] = { 15.0, 16.0 }; + + fp_t const * const x[] = { x0 }; + fp_t const * const e[] = { e0 }; + + return ts_test(ts_rainbow_ma, ts_rainbow_ma_offset, x, e, 21, (ts_constant_t *)NULL, &ts_rainbow_ma_p); +} diff --git a/test/rainbow_oscillator.c b/test/rainbow_oscillator.c new file mode 100644 index 0000000..a529ea2 --- /dev/null +++ b/test/rainbow_oscillator.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_rainbow_oscillator( void ) +{ + fp_t const x0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + + fp_t const e0[] = { 108.333333, 108.333333, 108.333333, 108.333333, 108.333333, 108.333333, 108.333333, 108.333333 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_rainbow_oscillator, ts_rainbow_oscillator_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_rainbow_oscillator_p); +} diff --git a/test/random_walk_index.c b/test/random_walk_index.c new file mode 100644 index 0000000..6702fca --- /dev/null +++ b/test/random_walk_index.c @@ -0,0 +1,19 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_random_walk_index( void ) +{ + fp_t const x0[] = { 10, 12, 11, 13, 12, 14, 13 }; + fp_t const * const x[] = { x0 }; + + uint_t k = 3; + + fp_t sum_abs = 2.0 + 1.0 + 2.0; + fp_t sum_net = ( 12 - 10 ) + ( 11 - 12 ) + ( 13 - 11 ); + fp_t const e0[] = { sum_abs / sum_net, 0, sum_abs / sum_net, 0 }; + + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_random_walk_index, ts_random_walk_index_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_random_walk_index_p); +} diff --git a/test/rank.c b/test/rank.c new file mode 100644 index 0000000..2c96247 --- /dev/null +++ b/test/rank.c @@ -0,0 +1,20 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_rank( void ) +{ + /* k=3, data: 10, 20, 15, 25, 5, 30 */ + /* i=2 (window [10,20,15]): current=15, <=: 10,15 => 2/3*100 = 66.667 */ + /* i=3 (window [20,15,25]): current=25, <=: 20,15,25 => 3/3*100 = 100.0 */ + /* i=4 (window [15,25,5]): current=5, <=: 5 => 1/3*100 = 33.333 */ + /* i=5 (window [25,5,30]): current=30, <=: 25,5,30 => 3/3*100 = 100.0 */ + fp_t const x[] = { 10, 20, 15, 25, 5, 30 }; + + fp_t const * const inp[1] = { x }; + fp_t const e[] = { 66.66667, 100.0, 33.33333, 100.0 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_rank, ts_rank_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_rank_p); +} diff --git a/test/ratio.c b/test/ratio.c new file mode 100644 index 0000000..beb0f43 --- /dev/null +++ b/test/ratio.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_ratio( void ) +{ + uint_t const c[] = { 3 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5, 6 }; + fp_t const e0[] = { 4, 2.5, 2 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_ratio, ts_ratio_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_ratio_p); +} diff --git a/test/ravi.c b/test/ravi.c new file mode 100644 index 0000000..22fb09c --- /dev/null +++ b/test/ravi.c @@ -0,0 +1,66 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_ravi( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; + fp_t const cl[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const inp[4] = { o, h, l, cl }; + + /* k=3, k2=3 */ + /* Numerator per bar: (close-open) + (close-prev_close) */ + /* i=0: 1+0=1, i=1: 1+1=2, i=2: 1+1=2, i=3: 1+1=2, ... */ + /* Denominator per bar: abs(high-low) + abs(close-open) */ + /* i=0: 4+1=5, i=1: 4+1=5, ... */ + /* SMA3(num): (1+2+2)/3=5/3, (2+2+2)/3=2, (2+2+2)/3=2, ... */ + /* SMA3(den): 5, 5, 5, ... */ + /* RVI: 5/15=1/3, 2/5, 2/5, 2/5, ... */ + + fp_t e_rvi[6] = { 0 }; + fp_t e_sig[6] = { 0 }; + + fp_t num_val[] = { 1, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; + fp_t den_val[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; + + fp_t num_sum = num_val[0] + num_val[1] + num_val[2]; + fp_t den_sum = den_val[0] + den_val[1] + den_val[2]; + + fp_t rvi_vals[10] = { 0 }; + for( uint_t i = 2; i < 10; ++i ) + { + if( i >= 3 ) + { + num_sum = num_sum - num_val[i - 3] + num_val[i]; + den_sum = den_sum - den_val[i - 3] + den_val[i]; + } + rvi_vals[i] = ( den_sum != 0 ) ? ( num_sum / 3.0 ) / ( den_sum / 3.0 ) : 0; + } + + uint_t offset = 4; + for( uint_t i = offset; i < 10; ++i ) + { + e_rvi[i - offset] = rvi_vals[i]; + } + + fp_t sig_a = 1.0 / 3; + fp_t sig_e = rvi_vals[2]; + for( uint_t i = 2; i < 10; ++i ) + { + sig_e = sig_e + sig_a * ( rvi_vals[i] - sig_e ); + if( i >= offset ) + { + e_sig[i - offset] = sig_e; + } + } + + fp_t const * const exp[2] = { e_rvi, e_sig }; + + typedef struct { uint_t k; fp_t k2; } c_t; + c_t cv = { .k = 3, .k2 = 3 }; + + return ts_test(ts_ravi, ts_ravi_offset, inp, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&cv, &ts_ravi_p); +} diff --git a/test/reciprocal.c b/test/reciprocal.c new file mode 100644 index 0000000..9396277 --- /dev/null +++ b/test/reciprocal.c @@ -0,0 +1,10 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" +bool ts_test_reciprocal( void ) { + fp_t const x0[] = { 1, 2, 3, 4, 5, 0.5, -1, 0 }; + fp_t const e0[] = { 1, 0.5, 0.333333, 0.25, 0.2, 2, -1, INFINITY }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_reciprocal, ts_reciprocal_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_reciprocal_p); +} diff --git a/test/regression_linear_least_squares.c b/test/regression_linear_least_squares.c new file mode 100644 index 0000000..871c73e --- /dev/null +++ b/test/regression_linear_least_squares.c @@ -0,0 +1,19 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_regression_linear_least_squares( void ) +{ + uint_t const c[] = { 3 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + fp_t const x1[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; + + fp_t const e0[] = { 2, 2, 2, 2, 2 }; + fp_t const e1[] = { 0, 0, 0, 0, 0 }; + fp_t const e2[] = { 1, 1, 1, 1, 1 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[3] = { e0, e1, e2 }; + + return ts_test(ts_regression_linear_least_squares, ts_regression_linear_least_squares_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_regression_linear_least_squares_p); +} diff --git a/test/relative_strength.c b/test/relative_strength.c new file mode 100644 index 0000000..8b546ea --- /dev/null +++ b/test/relative_strength.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_relative_strength( void ) +{ + fp_t const x0[] = { 10, 12, 11, 13, 12 }; + fp_t const x1[] = { 10, 10, 10, 10, 10 }; + fp_t const e0[] = { 100, 120, 110, 130, 120 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_relative_strength, ts_relative_strength_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_relative_strength_p); +} diff --git a/test/relative_volatility.c b/test/relative_volatility.c new file mode 100644 index 0000000..730812b --- /dev/null +++ b/test/relative_volatility.c @@ -0,0 +1,21 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_relative_volatility( void ) +{ + fp_t const x0[] = { 10, 10, 10, 10, 20, 20, 20 }; + fp_t const * const x[] = { x0 }; + + /* k=3, offset=2, y_n=5 */ + /* y[2]: [10,10,10] -> 0 (overwritten by xi=3: also [10,10,10] -> 0) */ + /* y[3]: [10,10,20] mean=13.33, sd=4.71 -> 35.355339 */ + /* y[4]: [10,20,20] mean=16.67, sd=4.71 -> 28.284271 */ + /* y[5]: [20,20,20] -> 0 */ + /* y[6]: not written -> 0 */ + fp_t const e[] = { 0.0, 35.355339, 28.284271, 0.0, 0.0 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_relative_volatility, ts_relative_volatility_offset, x, exp, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_relative_volatility_p); +} diff --git a/test/relu.c b/test/relu.c new file mode 100644 index 0000000..fcdb229 --- /dev/null +++ b/test/relu.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_relu( void ) +{ + fp_t const x0[] = { -3.000000, -1.000000, 0.000000, 1.000000, 3.000000 }; + fp_t const e0[] = { 0.000000, 0.000000, 0.000000, 1.000000, 3.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_relu, ts_relu_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_relu_p); +} diff --git a/test/remainder.c b/test/remainder.c new file mode 100644 index 0000000..735c5f3 --- /dev/null +++ b/test/remainder.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_remainder( void ) +{ + fp_t const x0[] = { 7.000000, 10.000000, -7.000000, 7.500000 }; + fp_t const x1[] = { 3.000000, 3.000000, 3.000000, 2.000000 }; + fp_t const e0[] = { 1.000000, 1.000000, -1.000000, -0.500000 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_remainder, ts_remainder_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_remainder_p); +} diff --git a/test/remquo_dummy.c b/test/remquo_dummy.c new file mode 100644 index 0000000..1f49d73 --- /dev/null +++ b/test/remquo_dummy.c @@ -0,0 +1,11 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_remquo_dummy( void ) +{ + fp_t const x0[] = { 0, 1, 2, 3, 1.5, 2.5 }; + fp_t const e0[] = { 0.0, 0.0, 0.0, 0.0, -0.5, 0.5 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_remquo_dummy, ts_remquo_dummy_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_remquo_dummy_p); +} diff --git a/test/reversal.c b/test/reversal.c new file mode 100644 index 0000000..ccc8021 --- /dev/null +++ b/test/reversal.c @@ -0,0 +1,19 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_reversal( void ) +{ + /* close: 10, 12, 11, 13, 10, 12 */ + /* i=2: c=11, prev=12, prev2=10. 11<12 && 12>10 => -1 (top reversal) */ + /* i=3: c=13, prev=11, prev2=12. 13>11 && 11<12 => +1 (bottom reversal) */ + /* i=4: c=10, prev=13, prev2=11. 10<13 && 13>11 => -1 (top reversal) */ + /* i=5: c=12, prev=10, prev2=13. 12>10 && 10<13 => +1 (bottom reversal) */ + fp_t const x[] = { 10, 12, 11, 13, 10, 12 }; + + fp_t const * const inp[1] = { x }; + fp_t const e[] = { -1, 1, -1, 1 }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_reversal, ts_reversal_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)NULL, &ts_reversal_p); +} diff --git a/test/rint.c b/test/rint.c new file mode 100644 index 0000000..9b1ec0d --- /dev/null +++ b/test/rint.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_rint( void ) +{ + fp_t const x0[] = { -2.700000, -1.300000, 0.300000, 0.700000, 1.500000, 2.700000 }; + fp_t const e0[] = { -3.000000, -1.000000, 0.000000, 1.000000, 2.000000, 3.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_rint, ts_rint_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_rint_p); +} diff --git a/test/roc.c b/test/roc.c new file mode 100644 index 0000000..0e7ddfc --- /dev/null +++ b/test/roc.c @@ -0,0 +1,19 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_roc( void ) +{ + /* k=3, close: 10, 12, 14, 16, 18, 20 */ + /* i=3: (16-10)/10*100 = 60 */ + /* i=4: (18-12)/12*100 = 50 */ + /* i=5: (20-14)/14*100 = 42.857 */ + fp_t const x[] = { 10, 12, 14, 16, 18, 20 }; + + fp_t const * const inp[1] = { x }; + fp_t const e[] = { 60, 50, 42.857143 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_roc, ts_roc_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_roc_p); +} diff --git a/test/rocp.c b/test/rocp.c new file mode 100644 index 0000000..589e161 --- /dev/null +++ b/test/rocp.c @@ -0,0 +1,19 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_rocp( void ) +{ + /* k=3, close: 10, 12, 14, 16, 18, 20 */ + /* i=3: (16-10)/10 = 0.6 */ + /* i=4: (18-12)/12 = 0.5 */ + /* i=5: (20-14)/14 = 0.42857 */ + fp_t const x[] = { 10, 12, 14, 16, 18, 20 }; + + fp_t const * const inp[1] = { x }; + fp_t const e[] = { 0.6, 0.5, 0.42857 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_rocp, ts_rocp_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_rocp_p); +} diff --git a/test/rocr.c b/test/rocr.c new file mode 100644 index 0000000..60335af --- /dev/null +++ b/test/rocr.c @@ -0,0 +1,19 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_rocr( void ) +{ + /* k=3, close: 10, 12, 14, 16, 18, 20 */ + /* i=3: 16/10 = 1.6 */ + /* i=4: 18/12 = 1.5 */ + /* i=5: 20/14 = 1.42857 */ + fp_t const x[] = { 10, 12, 14, 16, 18, 20 }; + + fp_t const * const inp[1] = { x }; + fp_t const e[] = { 1.6, 1.5, 1.42857 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_rocr, ts_rocr_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_rocr_p); +} diff --git a/test/rocr100.c b/test/rocr100.c new file mode 100644 index 0000000..45578ab --- /dev/null +++ b/test/rocr100.c @@ -0,0 +1,19 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_rocr100( void ) +{ + /* k=3, close: 10, 12, 14, 16, 18, 20 */ + /* i=3: 16/10*100 = 160 */ + /* i=4: 18/12*100 = 150 */ + /* i=5: 20/14*100 = 142.857 */ + fp_t const x[] = { 10, 12, 14, 16, 18, 20 }; + + fp_t const * const inp[1] = { x }; + fp_t const e[] = { 160, 150, 142.857143 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_rocr100, ts_rocr100_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_rocr100_p); +} diff --git a/test/root.c b/test/root.c new file mode 100644 index 0000000..6b9822b --- /dev/null +++ b/test/root.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_root( void ) +{ + fp_t const c[] = { 2.0 }; + + fp_t const x0[] = { 0, 1, 4, 9, 16 }; + fp_t const e0[] = { 0, 1, 2, 3, 4 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_root, ts_root_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_root_p); +} diff --git a/test/root_cube.c b/test/root_cube.c new file mode 100644 index 0000000..c60f7cb --- /dev/null +++ b/test/root_cube.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_root_cube( void ) +{ + fp_t const x0[] = { -8, -1, 0, 1, 8, 27, 64 }; + fp_t const e0[] = { -2, -1, 0, 1, 2, 3, 4 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_root_cube, ts_root_cube_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_root_cube_p); +} diff --git a/test/root_square.c b/test/root_square.c new file mode 100644 index 0000000..2ee33c6 --- /dev/null +++ b/test/root_square.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_root_square( void ) +{ + fp_t const x0[] = { 0, 1, 4, 9, 16, 25 }; + fp_t const e0[] = { 0, 1, 2, 3, 4, 5 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_root_square, ts_root_square_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_root_square_p); +} diff --git a/test/round_.c b/test/round_.c new file mode 100644 index 0000000..c9a29ad --- /dev/null +++ b/test/round_.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_round_( void ) +{ + fp_t const x0[] = { -2.7, -1.3, 0, 0.5, 1.3, 2.7, 3.9 }; + fp_t const e0[] = { -3, -1, 0, 1, 1, 3, 4 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_round_, ts_round__offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_round__p); +} diff --git a/test/rsi.c b/test/rsi.c new file mode 100644 index 0000000..040a08c --- /dev/null +++ b/test/rsi.c @@ -0,0 +1,30 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_rsi( void ) +{ + /* k=3, changes: +1, +1, +1, 0, -1, -1, -1, 0, +1 */ + fp_t const x[] = { 10, 11, 12, 13, 13, 12, 11, 10, 10, 11 }; + + fp_t const * const inp[1] = { x }; + + /* i=3: sum_gain=3, sum_loss=0, avg_gain=1, avg_loss=0 => RSI=100 */ + /* i=4: change=0, avg_gain=(1*2+0)/3=2/3, avg_loss=0 => RSI=100 */ + /* i=5: change=-1, avg_gain=(2/3*2+0)/3=4/9, avg_loss=(0*2+1)/3=1/3 */ + /* RS = (4/9)/(1/3) = 4/3, RSI = 100 - 100/(1+4/3) = 100 - 300/7 = 57.142857 */ + /* i=6: change=-1, avg_gain=(4/9*2+0)/3=8/27, avg_loss=(1/3*2+1)/3=5/9 */ + /* RS = (8/27)/(5/9) = 8/15, RSI = 100 - 100/(1+8/15) = 100 - 1500/23 = 34.782609 */ + /* i=7: change=-1, avg_gain=(8/27*2+0)/3=16/81, avg_loss=(5/9*2+1)/3=19/27 */ + /* RS = (16/81)/(19/27) = 16/57, RSI = 100 - 100/(1+16/57) = 100 - 5700/73 = 21.917808 */ + /* i=8: change=0, avg_gain=(16/81*2+0)/3=32/243, avg_loss=(19/27*2+0)/3=38/81 */ + /* RS = (32/243)/(38/81) = 16/57, RSI = 21.917808 */ + /* i=9: change=+1, avg_gain=(32/243*2+1)/3=307/729, avg_loss=(38/81*2+0)/3=76/243 */ + /* RS = (307/729)/(76/243) = 307/228, RSI = 100 - 100/(1+307/228) = 100 - 22800/535 = 57.383178 */ + + fp_t const e[] = { 100, 100, 57.142857, 34.782609, 21.917808, 21.917808, 57.383178 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_rsi, ts_rsi_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_rsi_p); +} diff --git a/test/running_count.c b/test/running_count.c new file mode 100644 index 0000000..45e35b1 --- /dev/null +++ b/test/running_count.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_running_count( void ) +{ + fp_t const x0[] = { 0, 1, 0, 2, 0, 3, 0, 4 }; + fp_t const e0[] = { 0, 1, 1, 2, 2, 3, 3, 4 }; + + fp_t const * const x[] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_running_count, ts_running_count_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_running_count_p); +} diff --git a/test/schaff_trend_cycle.c b/test/schaff_trend_cycle.c new file mode 100644 index 0000000..49c3791 --- /dev/null +++ b/test/schaff_trend_cycle.c @@ -0,0 +1,48 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_schaff_trend_cycle( void ) +{ + /* period=3, offset=52, y_n=48 */ + fp_t x[100] = { + 100.000000, 104.932803, 109.469637, 113.249904, 115.980586, 117.462425, 117.607714, 116.448140, + 114.131948, 110.910698, 107.116800, 103.133815, 99.362193, 96.183508, 93.926363, 92.837048, + 93.057531, 94.612780, 97.408533, 101.239717, 105.808768, 110.752209, 115.673120, 120.176596, + 123.905018, 126.570000, 127.978150, 128.048347, 126.818984, 124.444538, 121.181777, 117.366816, + 113.385098, 109.636962, 106.501880, 104.304564, 103.285957, 103.581711, 105.210072, 108.070246, + 111.951406, 116.551523, 121.504346, 126.412117, 130.881103, 134.556766, 137.155435, 138.489641, + 138.484867, 137.186202, 134.754318, 131.451109, 127.616305, 123.637121, 119.913670, 116.823220, + 114.686494, 113.739025, 114.110109, 115.811263, 118.735191, 122.665371, 127.295395, 132.256340, + 137.149724, 141.583098, 145.205106, 147.736868, 148.996894, 148.917291, 147.549835, 145.061339, + 141.718757, 137.865336, 133.889954, 130.192382, 127.147579, 125.072189, 124.196267, 124.642717, + 126.416325, 129.403321, 133.381551, 138.040314, 143.008121, 147.885875, 152.282525, 155.849995, + 158.314276, 159.499906, 159.345639, 157.909919, 155.365657, 151.984789, 148.113982, 144.143665, + 140.473160, 137.475006, 135.461681, 134.657694 + }; + + fp_t const * const inp[1] = { x }; + + fp_t const e0[] = { + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 100.000000, 100.000000, 100.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 100.000000, + 100.000000, 100.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000 + }; + + fp_t const e1[] = { + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 33.333333, 55.555556, 70.370370, 46.913580, 31.275720, 20.850480, + 13.900320, 9.266880, 6.177920, 4.118613, 2.745742, 1.830495, 1.220330, 0.813553, + 0.542369, 0.361579, 0.241053, 0.160702, 0.107135, 0.071423, 0.047615, 33.365077, + 55.576718, 70.384479, 46.922986, 31.281991, 20.854660, 13.903107, 9.268738, 6.179159, + 4.119439, 2.746293, 1.830862, 1.220575, 0.813716, 0.542478, 0.361652, 0.241101 + }; + + fp_t const * const exp[2] = { e0, e1 }; + + uint_t period = 3; + return ts_test(ts_schaff_trend_cycle, ts_schaff_trend_cycle_offset, inp, exp, 100, (ts_constant_t *)&period, &ts_schaff_trend_cycle_p); +} diff --git a/test/secant.c b/test/secant.c new file mode 100644 index 0000000..aef0c4d --- /dev/null +++ b/test/secant.c @@ -0,0 +1,9 @@ +#include <stddef.h> +#include "ts.h" +bool ts_test_secant( void ) { + fp_t const x0[] = { 0, 0.5, 1.0, 1.5, 2.0 }; + fp_t const e0[] = { 1.000000, 1.139494, 1.850816, 14.136833, -2.402998 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_secant, ts_secant_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_secant_p); +} diff --git a/test/secant_hyperbolic.c b/test/secant_hyperbolic.c new file mode 100644 index 0000000..d95f6b8 --- /dev/null +++ b/test/secant_hyperbolic.c @@ -0,0 +1,9 @@ +#include <stddef.h> +#include "ts.h" +bool ts_test_secant_hyperbolic( void ) { + fp_t const x0[] = { 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0 }; + fp_t const e0[] = { 1.000000, 0.886819, 0.648054, 0.425096, 0.265802, 0.163071, 0.099328, 0.060340, 0.036619 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_secant_hyperbolic, ts_secant_hyperbolic_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_secant_hyperbolic_p); +} diff --git a/test/secant_hyperbolic_inverse.c b/test/secant_hyperbolic_inverse.c new file mode 100644 index 0000000..b8801a9 --- /dev/null +++ b/test/secant_hyperbolic_inverse.c @@ -0,0 +1,9 @@ +#include <stddef.h> +#include "ts.h" +bool ts_test_secant_hyperbolic_inverse( void ) { + fp_t const x0[] = { 0.9, 0.8, 0.7, 0.5, 0.1 }; + fp_t const e0[] = { 0.467145, 0.693147, 0.895588, 1.316958, 2.993223 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_secant_hyperbolic_inverse, ts_secant_hyperbolic_inverse_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_secant_hyperbolic_inverse_p); +} diff --git a/test/secant_inverse.c b/test/secant_inverse.c new file mode 100644 index 0000000..e8c7b78 --- /dev/null +++ b/test/secant_inverse.c @@ -0,0 +1,9 @@ +#include <stddef.h> +#include "ts.h" +bool ts_test_secant_inverse( void ) { + fp_t const x0[] = { 2, 3, 4, 5, 10 }; + fp_t const e0[] = { 1.047198, 1.230959, 1.318116, 1.369438, 1.470629 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_secant_inverse, ts_secant_inverse_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_secant_inverse_p); +} diff --git a/test/session_volume.c b/test/session_volume.c new file mode 100644 index 0000000..d03f2ff --- /dev/null +++ b/test/session_volume.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_session_volume( void ) +{ + fp_t const v[] = { 100, 200, 300, 400, 500 }; + + fp_t const * const x[] = { v }; + + fp_t e[5] = { 100, 300, 600, 1000, 1500 }; + + fp_t const * const e_arr[1] = { e }; + + return ts_test(ts_session_volume, ts_session_volume_offset, x, e_arr, 5, (ts_constant_t *)NULL, &ts_session_volume_p); +} diff --git a/test/shinohara_intensity_ratio.c b/test/shinohara_intensity_ratio.c new file mode 100644 index 0000000..1e3bd09 --- /dev/null +++ b/test/shinohara_intensity_ratio.c @@ -0,0 +1,34 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_shinohara_intensity_ratio( void ) +{ + fp_t const x0[] = { 10, 10, 10, 20, 20, 20 }; + fp_t const x1[] = { 14, 13, 14, 24, 23, 24 }; + fp_t const x2[] = { 8, 9, 8, 18, 19, 18 }; + fp_t const x3[] = { 12, 11, 13, 22, 21, 23 }; + + fp_t const * const x[] = { x0, x1, x2, x3 }; + + uint_t k = 3; + + fp_t i0 = (x1[0] - x3[0]) / (x1[0] - x2[0]); + fp_t i1 = (x3[1] - x2[1]) / (x1[1] - x2[1]); + fp_t i2 = (x1[2] - x3[2]) / (x1[2] - x2[2]); + fp_t e[4]; + e[0] = (i0 + i1 + i2) / 3.0; + + fp_t i3 = (x3[3] > x0[3]) ? (x1[3] - x3[3]) / (x1[3] - x2[3]) : (x3[3] - x2[3]) / (x1[3] - x2[3]); + e[1] = e[0] + (i3 - i0) / 3.0; + + fp_t i4 = (x3[4] > x0[4]) ? (x1[4] - x3[4]) / (x1[4] - x2[4]) : (x3[4] - x2[4]) / (x1[4] - x2[4]); + e[2] = e[1] + (i4 - i1) / 3.0; + + fp_t i5 = (x3[5] > x0[5]) ? (x1[5] - x3[5]) / (x1[5] - x2[5]) : (x3[5] - x2[5]) / (x1[5] - x2[5]); + e[3] = e[2] + (i5 - i2) / 3.0; + + fp_t const * const exp[1] = { e }; + + return ts_test(ts_shinohara_intensity_ratio, ts_shinohara_intensity_ratio_offset, x, exp, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&k, &ts_shinohara_intensity_ratio_p); +} diff --git a/test/sigmoid.c b/test/sigmoid.c new file mode 100644 index 0000000..5ad07e5 --- /dev/null +++ b/test/sigmoid.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_sigmoid( void ) +{ + fp_t const c[] = { 1, 0.5, 0.25 }; + + fp_t const x0[] = { 0, 0, 0, 0, 0 }; + fp_t const e0[] = { 0.25, 0.25, 0.25, 0.25, 0.25 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_sigmoid, ts_sigmoid_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_sigmoid_p); +} diff --git a/test/sign.c b/test/sign.c new file mode 100644 index 0000000..8461145 --- /dev/null +++ b/test/sign.c @@ -0,0 +1,9 @@ +#include <stddef.h> +#include "ts.h" +bool ts_test_sign( void ) { + fp_t const x0[] = { -4, -3, -2, -1, 0, 1, 2, 3, 4 }; + fp_t const e0[] = { -1, -1, -1, -1, 0, 1, 1, 1, 1 }; + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + return ts_test(ts_sign, ts_sign_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_sign_p); +} diff --git a/test/sinc.c b/test/sinc.c new file mode 100644 index 0000000..aa7c9fc --- /dev/null +++ b/test/sinc.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_sinc( void ) +{ + fp_t const x0[] = { 0.000000, 0.500000, 1.000000, 1.500000, 2.000000, 2.500000 }; + fp_t const e0[] = { 1.000000, 0.636620, 0.000000, -0.212207, -0.000000, 0.127324 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_sinc, ts_sinc_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_sinc_p); +} diff --git a/test/sinc_unnormalized.c b/test/sinc_unnormalized.c new file mode 100644 index 0000000..e299f00 --- /dev/null +++ b/test/sinc_unnormalized.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_sinc_unnormalized( void ) +{ + fp_t const x0[] = { 0.000000, 0.500000, 1.000000, 1.570796, 3.141593 }; + fp_t const e0[] = { 1.000000, 0.958851, 0.841471, 0.636620, 0.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_sinc_unnormalized, ts_sinc_unnormalized_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_sinc_unnormalized_p); +} diff --git a/test/sine.c b/test/sine.c new file mode 100644 index 0000000..87cd03e --- /dev/null +++ b/test/sine.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_sine( void ) +{ + fp_t const x0[] = { 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0 }; + fp_t const e0[] = { 0, 0.479426, 0.841471, 0.997495, 0.909297, 0.598472, 0.141120, -0.350783, -0.756802 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_sine, ts_sine_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_sine_p); +} diff --git a/test/sine_hyperbolic.c b/test/sine_hyperbolic.c new file mode 100644 index 0000000..a47425e --- /dev/null +++ b/test/sine_hyperbolic.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_sine_hyperbolic( void ) +{ + fp_t const x0[] = { 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0 }; + fp_t const e0[] = { 0.000000, 0.521095, 1.175201, 2.129279, 3.626860, 6.050204, 10.017875, 16.542627, 27.289917 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_sine_hyperbolic, ts_sine_hyperbolic_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_sine_hyperbolic_p); +} diff --git a/test/sine_hyperbolic_inverse.c b/test/sine_hyperbolic_inverse.c new file mode 100644 index 0000000..01349e2 --- /dev/null +++ b/test/sine_hyperbolic_inverse.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_sine_hyperbolic_inverse( void ) +{ + fp_t const x0[] = { 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0 }; + fp_t const e0[] = { 0.000000, 0.481212, 0.881374, 1.194763, 1.443635, 1.647231, 1.818446, 1.965720, 2.094713 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_sine_hyperbolic_inverse, ts_sine_hyperbolic_inverse_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_sine_hyperbolic_inverse_p); +} diff --git a/test/sine_inverse.c b/test/sine_inverse.c new file mode 100644 index 0000000..76c64d7 --- /dev/null +++ b/test/sine_inverse.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_sine_inverse( void ) +{ + fp_t const x0[] = { 0, 0.25, 0.5, 0.75, 1.0 }; + fp_t const e0[] = { 0, 0.252680, 0.523599, 0.848062, 1.570796 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_sine_inverse, ts_sine_inverse_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_sine_inverse_p); +} diff --git a/test/slope.c b/test/slope.c new file mode 100644 index 0000000..5fa9172 --- /dev/null +++ b/test/slope.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_slope( void ) +{ + uint_t const c[] = { 3 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5, 6 }; + fp_t const e0[] = { 1, 1, 1 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_slope, ts_slope_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_slope_p); +} diff --git a/test/smootherstep.c b/test/smootherstep.c new file mode 100644 index 0000000..627c042 --- /dev/null +++ b/test/smootherstep.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_smootherstep( void ) +{ + fp_t const x0[] = { -1.000000, 0.000000, 0.250000, 0.500000, 0.750000, 1.000000, 2.000000 }; + fp_t const e0[] = { 0.000000, 0.000000, 0.103516, 0.500000, 0.896484, 1.000000, 1.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_smootherstep, ts_smootherstep_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_smootherstep_p); +} diff --git a/test/smoothstep.c b/test/smoothstep.c new file mode 100644 index 0000000..c7d87ff --- /dev/null +++ b/test/smoothstep.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_smoothstep( void ) +{ + fp_t const x0[] = { -1.000000, 0.000000, 0.250000, 0.500000, 0.750000, 1.000000, 2.000000 }; + fp_t const e0[] = { 0.000000, 0.000000, 0.156250, 0.500000, 0.843750, 1.000000, 1.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_smoothstep, ts_smoothstep_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_smoothstep_p); +} diff --git a/test/softplus.c b/test/softplus.c new file mode 100644 index 0000000..967e1a5 --- /dev/null +++ b/test/softplus.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_softplus( void ) +{ + fp_t const x0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000, 5.000000 }; + fp_t const e0[] = { 0.126928, 0.313262, 0.693147, 1.313262, 2.126928, 5.006715 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_softplus, ts_softplus_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_softplus_p); +} diff --git a/test/softsign.c b/test/softsign.c new file mode 100644 index 0000000..16cf82b --- /dev/null +++ b/test/softsign.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_softsign( void ) +{ + fp_t const x0[] = { -3.000000, -1.000000, 0.000000, 1.000000, 3.000000 }; + fp_t const e0[] = { -0.750000, -0.500000, 0.000000, 0.500000, 0.750000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_softsign, ts_softsign_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_softsign_p); +} diff --git a/test/standard_error.c b/test/standard_error.c new file mode 100644 index 0000000..de6b488 --- /dev/null +++ b/test/standard_error.c @@ -0,0 +1,15 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_standard_error( void ) +{ + fp_t const x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { 0.0, 0.0, 0.0, 0.0 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 5; + return ts_test(ts_standard_error, ts_standard_error_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_standard_error_p); +} diff --git a/test/starc_bands.c b/test/starc_bands.c new file mode 100644 index 0000000..0e60e5b --- /dev/null +++ b/test/starc_bands.c @@ -0,0 +1,25 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_starc_bands( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const cp[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, cp }; + + /* k=3, mult=2.0 */ + /* ATR=3.0, Middle: 13,14,15,16,17,18,19 */ + /* Upper=Middle+2*ATR, Lower=Middle-2*ATR */ + fp_t const eu[] = { 19, 20, 21, 22, 23, 24, 25 }; + fp_t const em[] = { 13, 14, 15, 16, 17, 18, 19 }; + fp_t const el[] = { 7, 8, 9, 10, 11, 12, 13 }; + fp_t const * const exp[3] = { eu, em, el }; + + typedef struct { uint_t k; fp_t mult; } c_t; + c_t c = { .k = 3, .mult = 2.0 }; + return ts_test(ts_starc_bands, ts_starc_bands_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&c, &ts_starc_bands_p); +} diff --git a/test/starc_lower.c b/test/starc_lower.c new file mode 100644 index 0000000..1467231 --- /dev/null +++ b/test/starc_lower.c @@ -0,0 +1,22 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_starc_lower( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const cp[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, cp }; + + /* k=3, mult=2.0, ATR=3.0, Middle: 13,14,15,16,17,18,19 */ + /* Lower = Middle - 2*ATR */ + fp_t const e[] = { 7, 8, 9, 10, 11, 12, 13, 13, 13 }; + fp_t const * const exp[1] = { e }; + + typedef struct { uint_t k; fp_t mult; } c_t; + c_t my_c = { .k = 3, .mult = 2.0 }; + return ts_test(ts_starc_lower, ts_starc_lower_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&my_c, &ts_starc_lower_p); +} diff --git a/test/starc_upper.c b/test/starc_upper.c new file mode 100644 index 0000000..00e612d --- /dev/null +++ b/test/starc_upper.c @@ -0,0 +1,22 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_starc_upper( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const cp[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, cp }; + + /* k=3, mult=2.0, ATR=3.0, Middle: 13,14,15,16,17,18,19 */ + /* Upper = Middle + 2*ATR */ + fp_t const e[] = { 19, 20, 21, 22, 23, 24, 25 }; + fp_t const * const exp[1] = { e }; + + typedef struct { uint_t k; fp_t mult; } c_t; + c_t my_c = { .k = 3, .mult = 2.0 }; + return ts_test(ts_starc_upper, ts_starc_upper_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&my_c, &ts_starc_upper_p); +} diff --git a/test/std_error.c b/test/std_error.c new file mode 100644 index 0000000..1bc050e --- /dev/null +++ b/test/std_error.c @@ -0,0 +1,17 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_std_error( void ) +{ + fp_t const x[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const * const inp[1] = { x }; + + /* k=3, SD=sqrt(2/3)=0.81650 for all windows */ + /* StdError = SD/sqrt(3) = 0.81650/1.73205 = 0.47140 */ + fp_t const e[] = { 0.47140, 0.47140, 0.47140, 0.47140, 0.47140, 0.47140, 0.47140, 0.47140 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_std_error, ts_std_error_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_std_error_p); +} diff --git a/test/stoch_rsi.c b/test/stoch_rsi.c new file mode 100644 index 0000000..e2b9b54 --- /dev/null +++ b/test/stoch_rsi.c @@ -0,0 +1,22 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_stoch_rsi( void ) +{ + /* rsi_period=3, stoch_period=3, offset=6 */ + /* close: 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 */ + /* RSI all 100 (all gains), so stoch RSI is 0/0 = 0 for all */ + fp_t const x[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + + fp_t const * const inp[1] = { x }; + + fp_t const ek[] = { 0, 0, 0, 0, 0 }; + fp_t const ed[] = { 0, 0, 0, 0, 0 }; + + fp_t const * const exp[2] = { ek, ed }; + + typedef struct { uint_t rsi_period; uint_t stoch_period; } c_t; + c_t c = { .rsi_period = 3, .stoch_period = 3 }; + return ts_test(ts_stoch_rsi, ts_stoch_rsi_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&c, &ts_stoch_rsi_p); +} diff --git a/test/stochastic_fast.c b/test/stochastic_fast.c new file mode 100644 index 0000000..a30380e --- /dev/null +++ b/test/stochastic_fast.c @@ -0,0 +1,23 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_stochastic_fast( void ) +{ + /* k=3, offset=k+2=5, y_n=5. %K=80 for all bars (range=5, C-LL=4), %D=SMA(3) of %K=80 */ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* %K = 80 for all (HH-LL=5, C-LL=4 => 100*4/5=80), %D = SMA(3) of %K = 80 */ + fp_t const ek[] = { 80, 80, 80, 80, 80 }; + fp_t const ed[] = { 80, 80, 80, 80, 80 }; + + fp_t const * const exp[2] = { ek, ed }; + + uint_t k = 3; + return ts_test(ts_stochastic_fast, ts_stochastic_fast_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_stochastic_fast_p); +} diff --git a/test/stochastic_momentum_index.c b/test/stochastic_momentum_index.c new file mode 100644 index 0000000..47697cc --- /dev/null +++ b/test/stochastic_momentum_index.c @@ -0,0 +1,25 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_stochastic_momentum_index( void ) +{ + /* k1=3, k2=3, signal_period=3, offset = k1+k2-1 = 5 */ + /* close = (H+L)/2, so deviation = 0 always, SMI = 0 */ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const c[] = { 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5, 19.5 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* deviation = 0, SMI = 0, signal = 0 */ + fp_t const esmi[] = { 0, 0, 0, 0 }; + fp_t const esig[] = { 0, 0, 0, 0 }; + + fp_t const * const exp[2] = { esmi, esig }; + + typedef struct { uint_t k1; uint_t k2; uint_t signal_period; } c_t; + c_t consts = { .k1 = 3, .k2 = 3, .signal_period = 3 }; + return ts_test(ts_stochastic_momentum_index, ts_stochastic_momentum_index_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&consts, &ts_stochastic_momentum_index_p); +} diff --git a/test/stochastic_slow.c b/test/stochastic_slow.c new file mode 100644 index 0000000..1bab8c4 --- /dev/null +++ b/test/stochastic_slow.c @@ -0,0 +1,24 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_stochastic_slow( void ) +{ + /* k=3, offset=3*k-3=6. Monotonic increase => all %K=80 (HH-LL=3, C-LL=2) => all smoothed = 80 */ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* offset=6, so y_n = 15-6 = 9 values per output */ + /* slow %K and %D all = 80 after initial fill */ + fp_t const ek[] = { 80, 80, 80, 80, 80, 80, 80, 80, 80 }; + fp_t const ed[] = { 80, 80, 80, 80, 80, 80, 80, 80, 80 }; + + fp_t const * const exp[2] = { ek, ed }; + + uint_t k = 3; + return ts_test(ts_stochastic_slow, ts_stochastic_slow_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_stochastic_slow_p); +} diff --git a/test/student_t_pdf.c b/test/student_t_pdf.c new file mode 100644 index 0000000..f23f955 --- /dev/null +++ b/test/student_t_pdf.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_student_t_pdf( void ) +{ + fp_t const c[] = { 10.000000 }; + + fp_t const x0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000 }; + fp_t const e0[] = { 0.061146, 0.230362, 0.389108, 0.230362, 0.061146 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_student_t_pdf, ts_student_t_pdf_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_student_t_pdf_p); +} diff --git a/test/subtraction.c b/test/subtraction.c new file mode 100644 index 0000000..9a62e5e --- /dev/null +++ b/test/subtraction.c @@ -0,0 +1,14 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_subtraction( void ) +{ + fp_t const x0[] = { 10, 20, 30 }; + fp_t const x1[] = { 3, 7, 5 }; + fp_t const e0[] = { 7, 13, 25 }; + + fp_t const * const x[2] = { x0, x1 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_subtraction, ts_subtraction_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_subtraction_p); +} diff --git a/test/summation.c b/test/summation.c new file mode 100644 index 0000000..7ed1677 --- /dev/null +++ b/test/summation.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_summation( void ) +{ + uint_t const c = 3; + + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 6, 9, 12 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_summation, ts_summation_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_summation_p); +} diff --git a/test/supertrend.c b/test/supertrend.c new file mode 100644 index 0000000..cce08ae --- /dev/null +++ b/test/supertrend.c @@ -0,0 +1,31 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_supertrend( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* k=3, mult=2 */ + /* TR at i=1: max(3,|13-11|=2,|10-11|=1)=3 */ + /* TR at i=2: max(3,|14-12|=2,|11-12|=1)=3 */ + /* TR at i=3: max(3,|15-13|=2,|12-13|=1)=3 */ + /* ATR = (3+3+3)/3 = 3 */ + /* Median at i=3: (15+12)/2 = 13.5 */ + /* Upper = 13.5 + 2*3 = 19.5, Lower = 13.5 - 2*3 = 7.5 */ + /* C[3]=14 > lower=7.5 => uptrend, supertrend=7.5 */ + /* Next: ATR remains 3, Median=15, Upper=21, Lower=9 */ + /* C[4]=15 > prev_st=7.5 and > lower=9 => supertrend=9 */ + fp_t const est[] = { 7.5, 8.5, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5 }; + fp_t const etr[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + fp_t const * const exp[2] = { est, etr }; + + typedef struct { uint_t k; fp_t mult; } c_t; + c_t consts = { .k = 3, .mult = 2.0 }; + return ts_test(ts_supertrend, ts_supertrend_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&consts, &ts_supertrend_p); +} diff --git a/test/swing_index.c b/test/swing_index.c new file mode 100644 index 0000000..2853198 --- /dev/null +++ b/test/swing_index.c @@ -0,0 +1,35 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_swing_index( void ) +{ + fp_t const o[] = { 10, 11, 12, 11, 12 }; + fp_t const h[] = { 12, 13, 14, 12, 14 }; + fp_t const l[] = { 8, 9, 10, 9, 10 }; + fp_t const c[] = { 11, 12, 10, 11, 11 }; + fp_t const v[] = { 100, 200, 300, 400, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t e[4] = { 0 }; + for( uint_t i = 1; i < 5; ++i ) + { + fp_t a1 = h[i] - h[i - 1]; + fp_t a2 = l[i - 1] - l[i]; + fp_t a = fmax( a1, a2 ); + fp_t b = c[i] - c[i - 1]; + fp_t ldpl = l[i] - l[i - 1]; + fp_t phmh = h[i - 1] - h[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 = h[i] - l[i]; + fp_t swing = ( hl != 0 ) ? ( a * 2.0 + b - c_val ) * v[i] / hl : 0; + e[i - 1] = ( i > 1 ? e[i - 2] : 0 ) + swing; + } + + fp_t const * const e_arr[1] = { e }; + + return ts_test(ts_swing_index, ts_swing_index_offset, x, e_arr, 5, (ts_constant_t *)NULL, &ts_swing_index_p); +} diff --git a/test/swish.c b/test/swish.c new file mode 100644 index 0000000..c98e256 --- /dev/null +++ b/test/swish.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_swish( void ) +{ + fp_t const x0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000 }; + fp_t const e0[] = { -0.238406, -0.268941, 0.000000, 0.731059, 1.761594 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_swish, ts_swish_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_swish_p); +} diff --git a/test/synthetic_yield.c b/test/synthetic_yield.c new file mode 100644 index 0000000..526b00f --- /dev/null +++ b/test/synthetic_yield.c @@ -0,0 +1,24 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_synthetic_yield( void ) +{ + /* k=3, prices: 100, 101, 102, 104, 106, 108, 110, 112, 114, 116 */ + fp_t const x[] = { 100, 101, 102, 104, 106, 108, 110, 112, 114, 116 }; + + fp_t const * const inp[1] = { x }; + + /* i=3: (104-100)/100 * 252/3 * 100 = 336 */ + /* i=4: (106-101)/101 * 84 * 100 = 42000/101 = 415.84158... */ + /* i=5: (108-102)/102 * 84 * 100 = 50400/102 = 494.11765... */ + /* i=6: (110-104)/104 * 84 * 100 = 50400/104 = 484.61538... */ + /* i=7: (112-106)/106 * 84 * 100 = 50400/106 = 475.47170... */ + /* i=8: (114-108)/108 * 84 * 100 = 50400/108 = 466.66667... */ + /* i=9: (116-110)/110 * 84 * 100 = 50400/110 = 458.18182... */ + fp_t const e[] = { 336, 415.84158, 494.11765, 484.61538, 475.47170, 466.66667, 458.18182 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_synthetic_yield, ts_synthetic_yield_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_synthetic_yield_p); +} diff --git a/test/t3.c b/test/t3.c new file mode 100644 index 0000000..7ef7e8e --- /dev/null +++ b/test/t3.c @@ -0,0 +1,29 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_t3( void ) +{ + fp_t const x0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + uint_t n = sizeof( x0 ) / sizeof( *x0 ); + + // T3 uses hardcoded k=5, b=0.7 + fp_t alpha = 2.0 / 6.0; + fp_t c3 = 0.7, c3m1 = -0.3, c3m2 = -1.3, c3m3 = -2.3; + fp_t w3 = c3, w2 = -3.0 * c3m1, w1 = 3.0 * c3m1 * c3m2, w0 = -c3m1 * c3m2 * c3m3; + + fp_t e0[10]; + fp_t ema1 = x0[0], ema2 = x0[0], ema3 = x0[0]; + e0[0] = x0[0]; + for ( uint_t i = 1; i < n; ++i ) + { + ema1 = ema1 + alpha * ( x0[i] - ema1 ); + ema2 = ema2 + alpha * ( ema1 - ema2 ); + ema3 = ema3 + alpha * ( ema2 - ema3 ); + e0[i] = w3 * ema3 + w2 * ema2 + w1 * ema1 + w0 * x0[i]; + } + + fp_t const * const x[] = { x0 }; + fp_t const * const e[] = { e0 }; + + return ts_test(ts_t3, ts_t3_offset, x, e, n, (ts_constant_t *)NULL, &ts_t3_p); +} diff --git a/test/tangent.c b/test/tangent.c new file mode 100644 index 0000000..a6195d4 --- /dev/null +++ b/test/tangent.c @@ -0,0 +1,14 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_tangent( void ) +{ + fp_t const x0[] = { 0, 0.785398, -0.785398, 0.5, -0.5 }; + fp_t const e0[] = { 0, 1, -1, 0.546302, -0.546302 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_tangent, ts_tangent_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_tangent_p); +} diff --git a/test/tangent_hyperbolic.c b/test/tangent_hyperbolic.c new file mode 100644 index 0000000..6c41a9c --- /dev/null +++ b/test/tangent_hyperbolic.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_tangent_hyperbolic( void ) +{ + fp_t const x0[] = { 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0 }; + fp_t const e0[] = { 0.000000, 0.462117, 0.761594, 0.905148, 0.964028, 0.986614, 0.995055, 0.998178, 0.999329 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_tangent_hyperbolic, ts_tangent_hyperbolic_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_tangent_hyperbolic_p); +} diff --git a/test/tangent_hyperbolic_inverse.c b/test/tangent_hyperbolic_inverse.c new file mode 100644 index 0000000..8c7fd35 --- /dev/null +++ b/test/tangent_hyperbolic_inverse.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_tangent_hyperbolic_inverse( void ) +{ + fp_t const x0[] = { 0, 0.25, 0.5, 0.75 }; + fp_t const e0[] = { 0, 0.255413, 0.549306, 0.972955 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_tangent_hyperbolic_inverse, ts_tangent_hyperbolic_inverse_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_tangent_hyperbolic_inverse_p); +} diff --git a/test/tangent_inverse.c b/test/tangent_inverse.c new file mode 100644 index 0000000..33e3593 --- /dev/null +++ b/test/tangent_inverse.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_tangent_inverse( void ) +{ + fp_t const x0[] = { 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0 }; + fp_t const e0[] = { 0, 0.463648, 0.785398, 0.982794, 1.107149, 1.190290, 1.249046, 1.292497, 1.325818 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_tangent_inverse, ts_tangent_inverse_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_tangent_inverse_p); +} diff --git a/test/tanhshrink.c b/test/tanhshrink.c new file mode 100644 index 0000000..ac01a7e --- /dev/null +++ b/test/tanhshrink.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_tanhshrink( void ) +{ + fp_t const x0[] = { -2.000000, -1.000000, 0.000000, 1.000000, 2.000000 }; + fp_t const e0[] = { -1.035972, -0.238406, 0.000000, 0.238406, 1.035972 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_tanhshrink, ts_tanhshrink_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_tanhshrink_p); +} diff --git a/test/test_python.py b/test/test_python.py new file mode 100644 index 0000000..a4aa7e2 --- /dev/null +++ b/test/test_python.py @@ -0,0 +1,782 @@ +#!/usr/bin/env python3 +"""Validate Python bindings against C test files. + +Parses C test files to extract inputs and expected outputs, then +calls Python bindings and compares. For test files that can't be +parsed, falls back to calling C via subprocess. +""" + +import ctypes +import importlib.util +import inspect +import math +import os +import re +import sys + +import numpy as np + +_ts_spec = importlib.util.spec_from_file_location( + "ts", + os.path.join(os.path.dirname(__file__), "..", "python", "ts", "__init__.py"), +) +if _ts_spec and _ts_spec.loader: + ts = importlib.util.module_from_spec(_ts_spec) + _ts_spec.loader.exec_module(ts) +else: + print("Error: could not load ts module", file=sys.stderr) + sys.exit(1) + +_parser_spec = importlib.util.spec_from_file_location( + "ts_parser", + os.path.join(os.path.dirname(__file__), "..", "scripts", "ts_parser.py"), +) +if _parser_spec and _parser_spec.loader: + _ts_parser_mod = importlib.util.module_from_spec(_parser_spec) + _parser_spec.loader.exec_module(_ts_parser_mod) + parse_names_only = _ts_parser_mod.parse_names_only +else: + print("Error: could not load ts_parser", file=sys.stderr) + sys.exit(1) + + +def get_default_params(fname, x_n): + """Extract default params from a Python binding's signature. + + Returns a dict of param name -> value for non-array parameters, + or None if the function has no extra parameters. + """ + func = getattr(ts, fname, None) + if func is None: + return None + sig = inspect.signature(func) + params = {} + for pname, param in sig.parameters.items(): + if param.annotation is np.ndarray: + continue + if param.default is not inspect.Parameter.empty: + params[pname] = param.default + return params if params else None + + +LIB_PATH = os.path.join(os.path.dirname(__file__), "..", "build", "libts.so") +N = 100 +SEED = 42 + + +def load_func_meta(): + return parse_names_only() + + +def _safe_float(text): + """Safely convert a C expression to float without eval().""" + text = text.strip() + if not text: + return None + text = re.sub(r"\bM_PI\b", "3.14159265358979323846", text) + text = re.sub(r"\bM_E\b", "2.71828182845904523536", text) + text = re.sub(r"\bPI\b", "3.14159265358979323846", text) + # Only allow simple numeric expressions: numbers, operators, parens, abs/min/max + if not re.match(r"^[\d\s\+\-\*\/\(\)\.,eE]+$", text): + return None + try: + import ast + + tree = ast.parse(text, mode="eval") + # Only allow safe node types + for node in ast.walk(tree): + if not isinstance( + node, + ( + ast.Expression, + ast.Constant, + ast.BinOp, + ast.UnaryOp, + ast.USub, + ast.UAdd, + ast.Add, + ast.Sub, + ast.Mult, + ast.Div, + ), + ): + return None + return float( + eval(text, {"__builtins__": {}, "abs": abs, "min": min, "max": max}) + ) + except Exception: + return None + + +def parse_array_initializer(text): + """Parse a C array initializer like { 1, 2, 3.5, -4.0 } into a list of floats.""" + m = re.search(r"\{\s*(.*?)\}\s*;", text, re.DOTALL) + if not m: + return None + values = [] + for v in m.group(1).split(","): + v = v.strip().split("//")[0].strip() + if not v: + continue + result = _safe_float(v) + if result is None: + return None + values.append(result) + return values if values else None + + +def parse_malloc_loops(content): + """Parse malloc + loop patterns to compute inputs. + + Handles patterns like: + uint_t n = 14; + fp_t *x[4]; + x[0] = malloc( n * sizeof( fp_t ) ); + ... + for ( uint_t i = 0; i < n; ++i ) + { + x[0][i] = 10 + i; + x[1][i] = 12 + i; + } + + Returns (inputs, n) or (None, None). + """ + # Find n + n_match = re.search(r"uint_t\s+n\s*=\s*(\d+)", content) + if not n_match: + return None, None + n = int(n_match.group(1)) + + # Find malloc declarations + malloc_match = re.search(r"fp_t\s+\*\s*x\[(\d+)\]", content) + if not malloc_match: + return None, None + x_n = int(malloc_match.group(1)) + + # Find loop body: x[i][j] = expr; + loop_match = re.search( + r"for\s*\([^)]*i\s*=\s*0[^)]*i\s*<\s*n[^)]*\+\+i\s*\)\s*\{([^}]+)\}", + content, + re.DOTALL, + ) + if not loop_match: + return None, None + + loop_body = loop_match.group(1) + formulas = {} + for fm in re.finditer(r"x\[(\d+)\]\[i\]\s*=\s*([^;]+);", loop_body): + idx = int(fm.group(1)) + expr = fm.group(2).strip() + formulas[idx] = expr + + if not formulas: + return None, None + + # Compute inputs + inputs = {} + for idx, expr in formulas.items(): + arr = [] + for i in range(n): + try: + safe_expr = expr.replace("i", str(i)).replace("n", str(n)) + if not re.match(r"^[\d\s\+\-\*\/\(\)\.,]+$", safe_expr.strip()): + return None, None + val = float( + eval( + safe_expr, + {"__builtins__": {}, "abs": abs, "min": min, "max": max}, + ) + ) + arr.append(val) + except Exception: + return None, None + inputs[idx] = arr + + # Build ordered list + result = [] + for i in range(x_n): + if i in inputs: + result.append(inputs[i]) + else: + return None, None + + return result, n + + +def parse_test_file(test_path): + """Parse a C test file to extract inputs, expected outputs, and constants. + + Returns dict with keys: inputs (list of lists), expected (list of lists), + constants (list of floats), n (int), or None if parsing fails. + """ + with open(test_path, encoding="utf-8") as f: + content = f.read() + + # Try malloc + loop pattern first + malloc_inputs, malloc_n = parse_malloc_loops(content) + if malloc_inputs: + # Find expected arrays + all_arrays = {} + for m in re.finditer( + r"fp_t\s+(?:const\s+)?(\w+)\[\s*\]\s*=\s*\{([^}]*)\}\s*;", + content, + re.DOTALL, + ): + arr_name = m.group(1) + values = parse_array_initializer(m.group(0)) + if values is not None: + all_arrays[arr_name] = values + + # Find expected pointer array + exp_match = re.search( + r"fp_t\s+(?:\*\s*)?const\s*\*\s*const\s+e\w*\[\s*\d*\s*\]\s*=\s*\{([^}]*)\}", + content, + ) + expected = [] + if exp_match: + exp_names = [n.strip() for n in exp_match.group(1).split(",") if n.strip()] + for name in exp_names: + if name in all_arrays: + expected.append(all_arrays[name]) + + # Find params + params = None + param_match = re.search(r"(?:c_t|params_t)\s+c\s*=\s*\{([^}]*)\}", content) + if param_match: + params = {} + for fm in re.finditer(r"\.(\w+)\s*=\s*([^,}]+)", param_match.group(1)): + fname = fm.group(1) + fval_text = fm.group(2).strip() + result = _safe_float(fval_text) + if result is not None: + params[fname] = result + + # Also look for scalar parameter: uint_t k = 3; fp_t c = 2; fp_t threshold = 0.5; + if params is None: + # Try to extract params from ts_test call's 6th argument + ts_test_match = re.search( + r"ts_test\s*\([^,]+,\s*[^,]+,\s*[^,]+,\s*[^,]+,\s*[^,]+,\s*(&?(\w+)|NULL)", + content, + ) + if ts_test_match: + param_arg = ts_test_match.group(2) + if param_arg and param_arg != "NULL": + # Check if it's an array like "constants[N] = { a, b }" + arr_match = re.search( + rf"fp_t\s+{param_arg}\s*\[\s*\d+\s*\]\s*=\s*\{{([^}}]*)\}}", + content, + ) + if arr_match: + # Resolve variable names to values + var_names = [v.strip() for v in arr_match.group(1).split(",")] + resolved = {} + for vn in var_names: + vn = vn.strip() + if not vn: + continue + # Try direct numeric value + result = _safe_float(vn) + if result is not None: + resolved[vn] = result + continue + # Try to find variable declaration + var_match = re.search( + rf"(?:uint_t|fp_t|int)\s+(?:const\s+)?{vn}\s*=\s*([^;]+);", + content, + ) + if var_match: + result = _safe_float(var_match.group(1).strip()) + if result is not None: + resolved[vn] = result + if resolved: + params = resolved + + if params is None: + scalar_match = re.search( + r"(?:uint_t|fp_t|int)\s+(?:const\s+)?(\w+)\s*=\s*([^;]+);", content + ) + if scalar_match: + var_name = scalar_match.group(1) + # Skip common non-param variables + if var_name not in ("n", "offset", "y_n", "i", "j"): + val_text = scalar_match.group(2).strip() + result = _safe_float(val_text) + if result is not None: + params = {var_name: result} + + return { + "inputs": malloc_inputs, + "expected": expected, + "constants": [], + "params": params, + "n": malloc_n, + } + + # Find all array declarations: fp_t const name[] = { ... }; + all_arrays = {} + for m in re.finditer( + r"fp_t\s+(?:const\s+)?(\w+)\[\s*\]\s*=\s*\{([^}]*)\}\s*;", content, re.DOTALL + ): + arr_name = m.group(1) + values = parse_array_initializer(m.group(0)) + if values is not None: + all_arrays[arr_name] = values + + if not all_arrays: + return None + + # Find input pointer array: fp_t const * const inp[N] = { x0, x1, ... }; + inp_match = re.search( + r"fp_t\s+const\s*\*\s*const\s+(?:inp\w*|x\w*)\[\s*\d*\]\s*=\s*\{([^}]*)\}", + content, + ) + if not inp_match: + return None + inp_names = [n.strip() for n in inp_match.group(1).split(",") if n.strip()] + + # Find expected pointer array: fp_t const * const exp[N] = { ezz, ed, ... }; + # or: fp_t const * const e[N] = { e0, e1, ... }; + exp_match = re.search( + r"fp_t\s+const\s*\*\s*const\s+e\w*\[\s*\d*\s*\]\s*=\s*\{([^}]*)\}", content + ) + if not exp_match: + return None + exp_names = [n.strip() for n in exp_match.group(1).split(",") if n.strip()] + + # Build input arrays in order + inputs = [] + for name in inp_names: + if name in all_arrays: + inputs.append(all_arrays[name]) + else: + return None + + # Build expected arrays in order (may be partial if some can't be resolved) + expected = [] + for name in exp_names: + if name in all_arrays: + expected.append(all_arrays[name]) + # Skip unresolved expected arrays (computed at runtime) + + # Find n + if inputs: + n = len(inputs[0]) + else: + return None + + # Find constants + constants = [] + # Look for: fp_t threshold = 5; or uint_t k = 3; or similar + for m in re.finditer( + r"(?:fp_t|uint_t|int)\s+(?:const\s+)?(\w+)\s*=\s*([^;]+);", content + ): + const_name = m.group(1) + const_val_text = m.group(2).strip() + # Skip if this is an array declaration + if "[" in const_val_text: + continue + result = _safe_float(const_val_text) + if result is not None: + constants.append(result) + + # Find struct parameter: c_t c = { .k = 3, .std_mult = 2.0 }; + params = None + param_match = re.search(r"(?:c_t|params_t)\s+c\s*=\s*\{([^}]*)\}", content) + if param_match: + params = {} + for fm in re.finditer(r"\.(\w+)\s*=\s*([^,}]+)", param_match.group(1)): + fname = fm.group(1) + fval_text = fm.group(2).strip() + result = _safe_float(fval_text) + if result is not None: + params[fname] = result + + # Also look for scalar parameter: uint_t k = 3; fp_t c = 2; fp_t threshold = 0.5; + if params is None: + # Try to extract params from ts_test call's 6th argument + ts_test_match = re.search( + r"ts_test\s*\([^,]+,\s*[^,]+,\s*[^,]+,\s*[^,]+,\s*[^,]+,\s*(&?(\w+)|NULL)", + content, + ) + if ts_test_match: + param_arg = ts_test_match.group(2) + if param_arg and param_arg != "NULL": + # Check if it's an array like "constants[N] = { a, b }" + arr_match = re.search( + rf"fp_t\s+{param_arg}\s*\[\s*\d+\s*\]\s*=\s*\{{([^}}]*)\}}", + content, + ) + if arr_match: + var_names = [v.strip() for v in arr_match.group(1).split(",")] + resolved = {} + for vn in var_names: + vn = vn.strip() + if not vn: + continue + result = _safe_float(vn) + if result is not None: + resolved[vn] = result + continue + var_match = re.search( + rf"(?:uint_t|fp_t|int)\s+(?:const\s+)?{vn}\s*=\s*([^;]+);", + content, + ) + if var_match: + result = _safe_float(var_match.group(1).strip()) + if result is not None: + resolved[vn] = result + if resolved: + params = resolved + + if params is None: + scalar_match = re.search( + r"(?:uint_t|fp_t|int)\s+(?:const\s+)?(\w+)\s*=\s*([^;]+);", content + ) + if scalar_match: + var_name = scalar_match.group(1) + if var_name not in ("n", "offset", "y_n", "i", "j"): + val_text = scalar_match.group(2).strip() + result = _safe_float(val_text) + if result is not None: + params = {var_name: result} + + return { + "inputs": inputs, + "expected": expected, + "constants": constants, + "params": params, + "n": n, + } + + +def call_c_direct(name, x_n, y_n, inputs, n, params=None): + """Call C flat wrapper directly via ctypes. Returns list of lists or None. + + Parameterized functions (params != None) are skipped — the C test harness + (make check) validates all 349 functions including those with parameters. + """ + if params: + return None + try: + flat_func = getattr(ts._lib, f"ts_{name}_flat", None) + if flat_func is None: + return None + np_inputs = [np.array(arr, dtype=np.float64) for arr in inputs] + y_bufs = [np.empty(n, dtype=np.float64) for _ in range(y_n)] + args = ( + [b.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) for b in y_bufs] + + [b.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) for b in np_inputs] + + [ctypes.c_uint64(n), None] + ) + ret = flat_func(*args) + if ret != 0: + return None + return [b.tolist() for b in y_bufs] + except (OSError, AttributeError, ctypes.ArgumentError): + return None + + +def isclose(a, b, rel_tol=1e-6, abs_tol=1e-6): + if math.isnan(a) and math.isnan(b): + return True + if math.isinf(a) and math.isinf(b): + return (a > 0) == (b > 0) + return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol) + + +def arrays_close(a, b): + if len(a) != len(b): + return False + for x, y in zip(a, b): + if not isclose(x, y): + return False + return True + + +def normalize_result(result, y_n, n): + """Normalize Python binding output to list of lists.""" + if isinstance(result, (int, float, np.number)): + return [[float(result)] * n] + if isinstance(result, tuple): + return [r.tolist() if hasattr(r, "tolist") else list(r) for r in result] + if hasattr(result, "tolist"): + return [result.tolist()] + if isinstance(result, list) and len(result) > 0 and hasattr(result[0], "tolist"): + return [r.tolist() for r in result] + if isinstance(result, list): + return result + return [[float(result)]] + + +def main(): + status = _run_tests() + sys.exit(status) + + +def _run_tests(): + meta = load_func_meta() + test_dir = os.path.dirname(__file__) + + total = len(meta) + passed = 0 + failed = 0 + skipped = 0 + + sorted_names = sorted(meta.keys()) + rng = __import__("random").Random(SEED) + # Pre-compute RNG offsets for each function + rng_offsets = {} + offset = 0 + for _fname in sorted_names: + rng_offsets[_fname] = offset + _x_n = meta[_fname]["x_n"] + offset += _x_n * N + + for fname, info in sorted(meta.items()): + x_n = info["x_n"] + y_n = info["y_n"] + + # Try parsing test file first + test_path = os.path.join(test_dir, f"{fname}.c") + parsed = None + if os.path.exists(test_path): + parsed = parse_test_file(test_path) + + inputs = None + expected = None + params = None + n = N + + if parsed: + inputs = parsed["inputs"] + expected = parsed["expected"] + params = parsed.get("params") + n = parsed["n"] + + # Validate input count (expected count is optional - some tests compute at runtime) + # Note: some C functions declare wrong x_n (e.g., x_n=1 but access x[4]). + # If test file provides more inputs, trust the test file. + if len(inputs) < x_n: + parsed = None + # Truncate extra inputs to match function's declared x_n + if len(inputs) > x_n: + inputs = inputs[:x_n] + + if not parsed: + # Fallback: random inputs + default params from binding signature + rng.seed(SEED) + rng.jumpahead(rng_offsets.get(fname, 0)) if hasattr( + rng, "jumpahead" + ) else None + for _ in range(x_n * N): + rng.uniform(0, 100) + rng.seed(SEED) + if hasattr(rng, "jumpahead"): + rng.jumpahead(rng_offsets.get(fname, 0)) + inputs = [[rng.uniform(0, 100) for _ in range(N)] for _ in range(x_n)] + n = N + expected = None + # Extract default params from the Python binding + params = get_default_params(fname, x_n) + + # Separate params for C subprocess vs Python binding + # C subprocess needs original params (may have keys not in binding) + # Python binding only accepts keys in its signature + binding_params = get_default_params(fname, x_n) + if params and binding_params: + # Filter to keys that exist in binding + filtered = {k: v for k, v in params.items() if k in binding_params} + # If no keys match by name, fall back to binding defaults + c_params = filtered if filtered else binding_params + py_params = filtered if filtered else binding_params + elif binding_params: + # No parsed params but binding has defaults - use them for both + c_params = binding_params + py_params = binding_params + else: + c_params = params + py_params = None + + # Call Python binding + func = getattr(ts, fname, None) + if func is None: + skipped += 1 + print(f" SKIP {fname} (not in Python bindings)") + continue + + np_inputs = [np.array(arr, dtype=np.float64) for arr in inputs or []] + + # Call C flat wrapper for non-parameterized functions + actual_x_n = len(inputs) if inputs else x_n + c_result = call_c_direct(fname, actual_x_n, y_n, inputs, n, c_params) + + try: + # Pass params to Python binding if available + if py_params: + int_params = {} + for pk, v in py_params.items(): + int_params[pk] = int(v) if v == int(v) else v + py_result = func(*np_inputs, **int_params) + else: + py_result = func(*np_inputs) + py_result = normalize_result(py_result, y_n, n) + except Exception as e: + err_msg = str(e) + if ( + re.search(r"ts_\w+\s+error", err_msg) + and not binding_params + and c_params + ): + skipped += 1 + print(f" SKIP {fname} (binding missing params, C needs them)") + continue + failed += 1 + print(f" FAIL {fname}: {e}") + continue + + # If C comparison unavailable (parameterized function), just verify Python didn't crash + if c_result is None: + passed += 1 + print(f" PASS {fname} (py-only)") + continue + + # Detect C OOB garbage + _min_normal = sys.float_info.min + + def _is_garbage(arr): + for v in arr: + av = abs(v) + if av == 0: + continue + if 0 < av < _min_normal: + return True + return False + + c_garbage = any(_is_garbage(r) for r in c_result) + if c_garbage: + skipped += 1 + print(f" SKIP {fname} (C OOB garbage)") + continue + + # Compare against C output + ok = True + if len(py_result) != len(c_result): + ok = False + else: + for yi, (got, exp) in enumerate(zip(py_result, c_result)): + if not arrays_close(got, exp): + ok = False + for j, (g, e) in enumerate(zip(got, exp)): + if not isclose(g, e): + print(f" y[{yi}][{j}]: got={g}, expected={e}") + break + break + + if ok: + passed += 1 + print(f" PASS {fname}") + else: + failed += 1 + print(f" FAIL {fname}") + + # --- Error-case validation (sample) --- + print("\n--- Error-case validation ---", flush=True) + error_passed = 0 + error_failed = 0 + error_sample = sorted(meta.keys())[:20] + + # Test 1: Empty arrays + for fname in error_sample: + info = meta[fname] + x_n = info["x_n"] + func = getattr(ts, fname, None) + if func is None: + continue + try: + empty_inputs = [np.array([], dtype=np.float64) for _ in range(x_n)] + sig = inspect.signature(func) + defaults = { + k: v.default + for k, v in sig.parameters.items() + if v.default is not inspect.Parameter.empty + and v.annotation is not np.ndarray + } + func(*empty_inputs, **defaults) if defaults else func(*empty_inputs) + error_passed += 1 + except (RuntimeError, ValueError, IndexError, AssertionError): + error_passed += 1 + except Exception as e: + error_failed += 1 + print(f" ERROR {fname} (empty): {type(e).__name__}: {e}") + + # Test 2: Mismatched array lengths + for fname in error_sample: + info = meta[fname] + x_n = info["x_n"] + if x_n < 2: + continue + func = getattr(ts, fname, None) + if func is None: + continue + try: + mismatched = [ + np.array([1.0] * 10, dtype=np.float64) + if i == 0 + else np.array([1.0] * 5, dtype=np.float64) + for i in range(x_n) + ] + sig = inspect.signature(func) + defaults = { + k: v.default + for k, v in sig.parameters.items() + if v.default is not inspect.Parameter.empty + and v.annotation is not np.ndarray + } + func(*mismatched, **defaults) if defaults else func(*mismatched) + error_failed += 1 + print(f" ERROR {fname} (mismatched): should have raised") + except (RuntimeError, ValueError, IndexError, AssertionError): + error_passed += 1 + except Exception: + error_passed += 1 + + # Test 3: NaN/Inf propagation + nan_passed = 0 + nan_failed = 0 + for fname in error_sample: + info = meta[fname] + x_n = info["x_n"] + func = getattr(ts, fname, None) + if func is None: + continue + try: + nan_inputs = [ + np.array([1.0, float("nan"), 3.0, 4.0, 5.0] * 20, dtype=np.float64) + for _ in range(x_n) + ] + sig = inspect.signature(func) + defaults = { + k: v.default + for k, v in sig.parameters.items() + if v.default is not inspect.Parameter.empty + and v.annotation is not np.ndarray + } + func(*nan_inputs, **defaults) if defaults else func(*nan_inputs) + nan_passed += 1 + except RuntimeError: + nan_passed += 1 + except Exception as e: + nan_failed += 1 + print(f" ERROR {fname} (NaN): {type(e).__name__}: {e}") + + total_error = error_passed + error_failed + total_nan = nan_passed + nan_failed + print(f"\nError-case: {error_passed}/{total_error} passed, {error_failed} failed") + print(f"NaN/Inf: {nan_passed}/{total_nan} passed, {nan_failed} failed") + + print(f"\n{passed}/{total} passed, {failed} failed, {skipped} skipped", flush=True) + return 0 if failed == 0 else 1 + + +if __name__ == "__main__": + main() diff --git a/test/tgamma.c b/test/tgamma.c new file mode 100644 index 0000000..6e4c54e --- /dev/null +++ b/test/tgamma.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_tgamma( void ) +{ + fp_t const x0[] = { 1.000000, 2.000000, 3.000000, 0.500000, 5.000000 }; + fp_t const e0[] = { 1.000000, 1.000000, 2.000000, 1.772454, 24.000000 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_tgamma, ts_tgamma_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_tgamma_p); +} diff --git a/test/tick_volume.c b/test/tick_volume.c new file mode 100644 index 0000000..e3055fd --- /dev/null +++ b/test/tick_volume.c @@ -0,0 +1,14 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_tick_volume( void ) +{ + fp_t const x[] = { 10, 11, 12, 13, 14 }; + fp_t const e[] = { 1, 1, 1, 1, 1 }; + + fp_t const * const inp[1] = { x }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_tick_volume, ts_tick_volume_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)NULL, &ts_tick_volume_p); +} diff --git a/test/time_series_forecast.c b/test/time_series_forecast.c new file mode 100644 index 0000000..9510879 --- /dev/null +++ b/test/time_series_forecast.c @@ -0,0 +1,15 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_time_series_forecast( void ) +{ + fp_t const x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + fp_t const * const inp[1] = { x }; + + fp_t const e[] = { 6, 7, 8, 9 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 5; + return ts_test(ts_time_series_forecast, ts_time_series_forecast_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_time_series_forecast_p); +} diff --git a/test/trade_volume_index.c b/test/trade_volume_index.c new file mode 100644 index 0000000..b8655d2 --- /dev/null +++ b/test/trade_volume_index.c @@ -0,0 +1,29 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_trade_volume_index( void ) +{ + fp_t const o[] = { 10, 11, 12, 11, 12, 10, 11, 13, 12, 14 }; + fp_t const h[] = { 12, 13, 14, 12, 14, 11, 12, 15, 14, 16 }; + fp_t const l[] = { 8, 9, 10, 9, 10, 9, 10, 11, 10, 12 }; + fp_t const c[] = { 11, 12, 10, 11, 11, 10, 12, 14, 13, 15 }; + fp_t const v[] = { 100, 200, 300, 400, 500, 300, 200, 400, 300, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t e[10] = { 0 }; + { + fp_t roc = ( c[0] != 0 ) ? ( c[1] - c[0] ) / c[0] : 0; + e[0] = roc * v[1]; + } + for( uint_t i = 2; i < 10; ++i ) + { + fp_t roc = ( c[i - 1] != 0 ) ? ( c[i] - c[i - 1] ) / c[i - 1] : 0; + e[i - 1] = e[i - 2] + roc * v[i]; + } + e[9] = e[8]; + + fp_t const * const e_arr[1] = { e }; + + return ts_test(ts_trade_volume_index, ts_trade_volume_index_offset, x, e_arr, 10, (ts_constant_t *)NULL, &ts_trade_volume_index_p); +} diff --git a/test/trend_intensity_index.c b/test/trend_intensity_index.c new file mode 100644 index 0000000..8eca9f3 --- /dev/null +++ b/test/trend_intensity_index.c @@ -0,0 +1,41 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_trend_intensity_index( void ) +{ + uint_t k = 3; + + fp_t const o[] = { 10, 11, 12, 11, 12, 10, 11, 13, 12, 14 }; + fp_t const h[] = { 12, 13, 14, 12, 14, 11, 12, 15, 14, 16 }; + fp_t const l[] = { 8, 9, 10, 9, 10, 9, 10, 11, 10, 12 }; + fp_t const c[] = { 11, 12, 10, 11, 11, 10, 12, 14, 13, 15 }; + fp_t const v[] = { 100, 200, 300, 400, 500, 300, 200, 400, 300, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t signed_sum = 0; + fp_t vol_sum = 0; + + for( uint_t i = 1; i <= k; ++i ) + { + signed_sum += ( c[i] > c[i - 1] ) ? v[i] : -v[i]; + vol_sum += v[i]; + } + + fp_t e[10] = { 0 }; + e[0] = ( vol_sum != 0 ) ? signed_sum / vol_sum : 0; + + for( uint_t i = k + 1; i < 10; ++i ) + { + fp_t cur_signed = ( c[i] > c[i - 1] ) ? v[i] : -v[i]; + fp_t old_signed = ( c[i - k] > c[i - k - 1] ) ? v[i - k] : -v[i - k]; + signed_sum += cur_signed - old_signed; + vol_sum += v[i] - v[i - k]; + e[i - (k - 1)] = ( vol_sum != 0 ) ? signed_sum / vol_sum : 0; + } + + fp_t const * const e_arr[1] = { e }; + uint_t c_val = k; + + return ts_test(ts_trend_intensity_index, ts_trend_intensity_index_offset, x, e_arr, 10, (ts_constant_t *)&c_val, &ts_trend_intensity_index_p); +} diff --git a/test/trix.c b/test/trix.c new file mode 100644 index 0000000..29f5451 --- /dev/null +++ b/test/trix.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_trix( void ) +{ + fp_t const c[] = { 0.5 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 1, 0.125, 0.277778, 0.347826, 0.338710 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_trix, ts_trix_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_trix_p); +} diff --git a/test/true_range.c b/test/true_range.c new file mode 100644 index 0000000..208a8b3 --- /dev/null +++ b/test/true_range.c @@ -0,0 +1,18 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_true_range( void ) +{ + uint_t const c[] = { 1 }; + + fp_t const h[] = { 10, 11, 12, 13, 14 }; + fp_t const l[] = { 8, 9, 10, 11, 12 }; + fp_t const o[] = { 9, 10, 11, 12, 13 }; + fp_t const c2[] = { 9.5, 10.5, 11.5, 12.5, 13.5 }; + fp_t const e0[] = { 2, 2, 2, 2 }; + + fp_t const * const x[4] = { o, h, l, c2 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_true_range, ts_true_range_offset, x, e, sizeof( h ) / sizeof( *h ), (ts_constant_t *)&c, &ts_true_range_p); +} diff --git a/test/truncate.c b/test/truncate.c new file mode 100644 index 0000000..44e6ca4 --- /dev/null +++ b/test/truncate.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_truncate( void ) +{ + fp_t const x0[] = { -2.7, -1.3, 0, 0.5, 1.3, 2.7, 3.9 }; + fp_t const e0[] = { -2, -1, 0, 0, 1, 2, 3 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_truncate, ts_truncate_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_truncate_p); +} diff --git a/test/twiggs_money_flow.c b/test/twiggs_money_flow.c new file mode 100644 index 0000000..8fb5471 --- /dev/null +++ b/test/twiggs_money_flow.c @@ -0,0 +1,41 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_twiggs_money_flow( void ) +{ + fp_t x_data[37] = { 0 }; + for( uint_t i = 0; i < 37; ++i ) + { + x_data[i] = (fp_t)(10 + i); + } + + fp_t const * const x[] = { x_data }; + + fp_t pos_sum = 0; + fp_t neg_sum = 0; + + for( uint_t i = 1; i <= 35; ++i ) + { + fp_t change = x_data[i] - x_data[i - 1]; + if( change >= 0 ) pos_sum += change; + else neg_sum += fabs( change ); + } + + fp_t e[2] = { 0 }; + fp_t total = pos_sum + neg_sum; + e[0] = ( total != 0 ) ? ( pos_sum - neg_sum ) / total * 100.0 : 0; + + fp_t change = x_data[36] - x_data[35]; + fp_t old_change = x_data[1] - x_data[0]; + if( change >= 0 ) pos_sum += change; + else neg_sum += fabs( change ); + if( old_change >= 0 ) pos_sum -= old_change; + else neg_sum -= fabs( old_change ); + total = pos_sum + neg_sum; + e[1] = ( total != 0 ) ? ( pos_sum - neg_sum ) / total * 100.0 : 0; + + fp_t const * const e_arr[1] = { e }; + + return ts_test(ts_twiggs_money_flow, ts_twiggs_money_flow_offset, x, e_arr, 37, (ts_constant_t *)NULL, &ts_twiggs_money_flow_p); +} diff --git a/test/typical_price.c b/test/typical_price.c new file mode 100644 index 0000000..b43bc3f --- /dev/null +++ b/test/typical_price.c @@ -0,0 +1,17 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_typical_price( void ) +{ + fp_t const x0[] = { 0, 0, 0, 0 }; + fp_t const x1[] = { 10, 12, 14, 16 }; + fp_t const x2[] = { 8, 10, 12, 14 }; + fp_t const x3[] = { 9, 11, 13, 15 }; + fp_t const x4[] = { 0, 0, 0, 0 }; + fp_t const e0[] = { 9, 11, 13, 15 }; + + fp_t const * const x[5] = { x0, x1, x2, x3, x4 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_typical_price, ts_typical_price_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_typical_price_p); +} diff --git a/test/ulcer_index.c b/test/ulcer_index.c new file mode 100644 index 0000000..f856723 --- /dev/null +++ b/test/ulcer_index.c @@ -0,0 +1,28 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_ulcer_index( void ) +{ + fp_t const x[] = { 10, 12, 11, 13, 12, 14, 11, 13, 12, 15 }; + fp_t const * const inp[1] = { x }; + + /* k=3, cumulative HHV (running max from index 0) */ + /* HHV: 10, 12, 12, 13, 13, 14, 14, 14, 14, 15 */ + /* d%: 0, 0, 8.333, 0, 7.692, 0, 21.429, 7.143, 14.286, 0 */ + /* d^2: 0, 0, 69.444, 0, 59.172, 0, 459.184, 51.020, 204.082, 0 */ + /* SMA3 of d^2, then sqrt: */ + /* i=2: window [0,1,2], d^2=[0,0,69.444], mean=23.148, UI=4.811 */ + /* i=3: window [1,2,3], d^2=[0,69.444,0], mean=23.148, UI=4.811 */ + /* i=4: window [2,3,4], d^2=[69.444,0,59.172], mean=42.872, UI=6.548 */ + /* i=5: window [3,4,5], d^2=[0,59.172,0], mean=19.724, UI=4.441 */ + /* i=6: window [4,5,6], d^2=[59.172,0,459.184], mean=172.785, UI=13.145 */ + /* i=7: window [5,6,7], d^2=[0,459.184,51.020], mean=170.069, UI=13.041 */ + /* i=8: window [6,7,8], d^2=[459.184,51.020,204.082], mean=238.095, UI=15.430 */ + /* i=9: window [7,8,9], d^2=[51.020,204.082,0], mean=85.034, UI=9.221 */ + fp_t const e[] = { 4.811252, 4.811252, 6.547672, 4.441156, 13.144774, 13.041013, 15.430335, 9.221389 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_ulcer_index, ts_ulcer_index_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&k, &ts_ulcer_index_p); +} diff --git a/test/ultimate_oscillator.c b/test/ultimate_oscillator.c new file mode 100644 index 0000000..01bdb62 --- /dev/null +++ b/test/ultimate_oscillator.c @@ -0,0 +1,90 @@ +#include <stddef.h> +#include <stdlib.h> +#include <tgmath.h> +#include "ts.h" + +static fp_t _ts_min( fp_t const * const *x, uint_t start, uint_t count ) +{ + fp_t m = ts_l( x, start ); + for( uint_t i = 1; i < count; ++i ) + { + m = fmin( m, ts_l( x, start - i ) ); + } + return m; +} + +static fp_t _ts_max_h( fp_t const * const *x, uint_t start, uint_t count ) +{ + fp_t m = ts_h( x, start ); + for( uint_t i = 1; i < count; ++i ) + { + m = fmax( m, ts_h( x, start - i ) ); + } + return m; +} + +bool ts_test_ultimate_oscillator( void ) +{ + uint_t n = 60; + + fp_t o[60], h[60], l[60], c[60]; + for (uint_t i = 0; i < n; ++i) + { + o[i] = 10.0 + (fp_t)i; + h[i] = 12.0 + (fp_t)i; + l[i] = 8.0 + (fp_t)i; + c[i] = 11.0 + (fp_t)i; + } + + fp_t const * const x[] = { o, h, l, c }; + + uint_t offset = 54; + uint_t e_n = n - offset; + fp_t *e = calloc(e_n, sizeof(fp_t)); + if (!e) return false; + + for( uint_t i = offset; 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_min( x, idx, 7 ); + fp_t hh = _ts_max_h( x, idx, 7 ); + 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_min( x, idx, 14 ); + fp_t hh = _ts_max_h( x, idx, 14 ); + 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_min( x, idx, 28 ); + fp_t hh = _ts_max_h( x, idx, 28 ); + 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; + e[i - offset] = ( denom != 0 ) ? 100.0 * numer / denom : 50.0; + } + + fp_t const * const e_arr[1] = { e }; + + bool result = ts_test(ts_ultimate_oscillator, ts_ultimate_oscillator_offset, x, e_arr, n, (ts_constant_t *)NULL, &ts_ultimate_oscillator_p); + + free(e); + return result; +} diff --git a/test/valuation_lines.c b/test/valuation_lines.c new file mode 100644 index 0000000..10fde35 --- /dev/null +++ b/test/valuation_lines.c @@ -0,0 +1,23 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_valuation_lines( void ) +{ + fp_t const o[] = { 10, 12, 11, 14, 13, 15, 16, 14, 17, 18 }; + fp_t const h[] = { 12, 14, 13, 16, 15, 17, 18, 16, 19, 20 }; + fp_t const l[] = { 9, 11, 10, 13, 12, 14, 15, 13, 16, 17 }; + fp_t const cp[] = { 11, 13, 12, 15, 14, 16, 17, 15, 18, 19 }; + + fp_t const * const x[] = { o, h, l, cp }; + + /* k=3 */ + /* LL3: 9,10,10,12,12,13,13,13 */ + /* HH3: 14,16,16,17,18,18,19,20 */ + fp_t const es[] = { 9, 10, 10, 12, 12, 13, 13, 13 }; + fp_t const er[] = { 14, 16, 16, 17, 18, 18, 19, 20 }; + fp_t const * const exp[2] = { es, er }; + + uint_t k = 3; + return ts_test(ts_valuation_lines, ts_valuation_lines_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_valuation_lines_p); +} diff --git a/test/variable_index_dynamic_average.c b/test/variable_index_dynamic_average.c new file mode 100644 index 0000000..b7de9f8 --- /dev/null +++ b/test/variable_index_dynamic_average.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_variable_index_dynamic_average( void ) +{ + fp_t const x0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; + fp_t const e0[] = { 6, 6.375, 6.95052083333333, 7.655029296875, 8.44889958699544, 9.30590988198916, 10.2074478511673 }; + + fp_t const * const x[] = { x0 }; + fp_t const * const e[] = { e0 }; + + uint_t c = 5; + + return ts_test(ts_variable_index_dynamic_average, ts_variable_index_dynamic_average_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_variable_index_dynamic_average_p); +} diff --git a/test/variance.c b/test/variance.c new file mode 100644 index 0000000..5dedca5 --- /dev/null +++ b/test/variance.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_variance( void ) +{ + uint_t const c[] = { 3 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 0.666667, 0.666667, 0.666667 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_variance, ts_variance_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_variance_p); +} diff --git a/test/variance_exponential.c b/test/variance_exponential.c new file mode 100644 index 0000000..03e526f --- /dev/null +++ b/test/variance_exponential.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_variance_exponential( void ) +{ + fp_t const c[] = { 0.5 }; + + fp_t const x0[] = { 1, 2, 3, 4, 5 }; + fp_t const e0[] = { 0, 0.25, 0.6875, 1.109375, 1.433594 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_variance_exponential, ts_variance_exponential_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_variance_exponential_p); +} diff --git a/test/vertical_horizontal_filter.c b/test/vertical_horizontal_filter.c new file mode 100644 index 0000000..2f047ad --- /dev/null +++ b/test/vertical_horizontal_filter.c @@ -0,0 +1,26 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_vertical_horizontal_filter( void ) +{ + uint_t k = 3; + + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 14, 13, 15, 16, 14, 17, 18, 16, 19 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const c[] = { 11, 13, 12, 14, 15, 13, 16, 17, 15, 18 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* k=3, offset=3 + * i=3: hh=15,ll=10,num=5, den=|13-14|+|11-10|+|15-13|+|12-11|+|16-15|+|13-12|=1+1+2+1+1+1=7, VHF=5/7=0.71429 + * i=4: hh=16,ll=11,num=5, den=|15-13|+|12-11|+|16-15|+|13-12|+|14-16|+|14-13|=2+1+1+1+2+1=8, VHF=5/8=0.625 + * i=5: hh=16,ll=12,num=4, den=|14-15|+|14-13|+|17-16|+|15-14|+|14-14|+|14-14|=1+1+1+1+0+0=4, VHF=4/4=1.0 + * ... + */ + fp_t const e[] = { 0.625, 0.71429, 0.5, 0.44444, 0.44444, 0.33333, 0.33333 }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_vertical_horizontal_filter, ts_vertical_horizontal_filter_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_vertical_horizontal_filter_p); +} diff --git a/test/volatility_stop.c b/test/volatility_stop.c new file mode 100644 index 0000000..59db98f --- /dev/null +++ b/test/volatility_stop.c @@ -0,0 +1,27 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_volatility_stop( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; + fp_t const cp[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, cp }; + + /* k=3, mult=2.0 */ + /* HH3: 12,13,14,15,16,17,18,19,20,21 */ + /* LL3: 9,10,11,12,13,14,15,16,17,18 */ + /* ATR=3.0 */ + /* LongStop = HH - 2*ATR: 6,7,8,9,10,11,12,13,14 */ + /* ShortStop = LL + 2*ATR: 15,16,17,18,19,20,21,22,23 */ + fp_t const longs[] = { 9, 10, 11, 12, 13, 14, 15 }; + fp_t const shorts[] = { 15, 16, 17, 18, 19, 20, 21 }; + fp_t const * const exp[2] = { longs, shorts }; + + typedef struct { uint_t k; fp_t mult; } c_t; + c_t my_c = { .k = 3, .mult = 2.0 }; + return ts_test(ts_volatility_stop, ts_volatility_stop_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&my_c, &ts_volatility_stop_p); +} diff --git a/test/volatility_system.c b/test/volatility_system.c new file mode 100644 index 0000000..2d940d5 --- /dev/null +++ b/test/volatility_system.c @@ -0,0 +1,21 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_volatility_system( void ) +{ + uint_t k = 3; + + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* offset = 2k = 6, output starts at index 6 */ + fp_t const e[] = { 16.5, 17.25, 18.125, 19.0625, 20.03125, 21.015625 }; + fp_t const * const exp[1] = { e }; + + return ts_test(ts_volatility_system, ts_volatility_system_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_volatility_system_p); +} diff --git a/test/volume_delta.c b/test/volume_delta.c new file mode 100644 index 0000000..42a4c87 --- /dev/null +++ b/test/volume_delta.c @@ -0,0 +1,39 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_volume_delta( void ) +{ + fp_t const o[] = { 10, 11, 12, 13, 14 }; + fp_t const h[] = { 12, 13, 14, 15, 16 }; + fp_t const l[] = { 8, 9, 10, 11, 12 }; + fp_t const c[] = { 11, 12, 13, 14, 15 }; + fp_t const v[] = { 100, 200, 300, 400, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t e[5] = { 0 }; + for( uint_t i = 0; i < 5; ++i ) + { + fp_t hl = h[i] - l[i]; + if( hl == 0 ) + { + e[i] = 0; + } + else if( c[i] > o[i] ) + { + fp_t buy_vol = v[i] * ( c[i] - l[i] ) / hl; + fp_t sell_vol = v[i] - buy_vol; + e[i] = buy_vol - sell_vol; + } + else if( c[i] < o[i] ) + { + fp_t sell_vol = v[i] * ( h[i] - c[i] ) / hl; + fp_t buy_vol = v[i] - sell_vol; + e[i] = buy_vol - sell_vol; + } + } + + fp_t const * const e_arr[1] = { e }; + + return ts_test(ts_volume_delta, ts_volume_delta_offset, x, e_arr, 5, (ts_constant_t *)NULL, &ts_volume_delta_p); +} diff --git a/test/volume_moving_average.c b/test/volume_moving_average.c new file mode 100644 index 0000000..c6338dc --- /dev/null +++ b/test/volume_moving_average.c @@ -0,0 +1,33 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_volume_moving_average( void ) +{ + uint_t k = TS_TEST_K; + + fp_t const o[] = { 10, 11, 12, 11, 12, 10, 11, 13, 12, 14 }; + fp_t const h[] = { 12, 13, 14, 12, 14, 11, 12, 15, 14, 16 }; + fp_t const l[] = { 8, 9, 10, 9, 10, 9, 10, 11, 10, 12 }; + fp_t const c[] = { 11, 12, 10, 11, 11, 10, 12, 14, 13, 15 }; + fp_t const v[] = { 100, 200, 300, 400, 500, 300, 200, 400, 300, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t e[10] = { 0 }; + + fp_t sum = 0; + for( uint_t i = 0; i < k; ++i ) sum += v[i]; + e[0] = sum / (fp_t)k; + + for( uint_t i = k; i < 10; ++i ) + { + sum += v[i] - v[i - k]; + e[i - (k - 1)] = sum / (fp_t)k; + } + + fp_t const * const e_arr[1] = { e }; + + uint_t c_val = k; + + return ts_test(ts_volume_moving_average, ts_volume_moving_average_offset, x, e_arr, 10, (ts_constant_t *)&c_val, &ts_volume_moving_average_p); +} diff --git a/test/volume_oscillator.c b/test/volume_oscillator.c new file mode 100644 index 0000000..daa4bd0 --- /dev/null +++ b/test/volume_oscillator.c @@ -0,0 +1,34 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_volume_oscillator( void ) +{ + fp_t const v[] = { 100, 200, 300, 400, 500 }; + + fp_t const * const x[] = { v }; + + fp_t fast = 2; + fp_t slow = 4; + fp_t a_fast = 2.0 / (fast + 1); + fp_t a_slow = 2.0 / (slow + 1); + + fp_t ema_f = v[0]; + fp_t ema_s = v[0]; + fp_t e[2] = { 0 }; + + uint_t idx = 0; + for( uint_t i = 1; i < 5; ++i ) + { + ema_f = ema_f + a_fast * ( v[i] - ema_f ); + ema_s = ema_s + a_slow * ( v[i] - ema_s ); + if (i >= 3) { + e[idx++] = ema_s != 0 ? ( ema_f - ema_s ) / ema_s * 100 : 0; + } + } + + fp_t const * const e_arr[1] = { e }; + + fp_t constants[2] = { fast, slow }; + + return ts_test(ts_volume_oscillator, ts_volume_oscillator_offset, x, e_arr, 5, (ts_constant_t *)constants, &ts_volume_oscillator_p); +} diff --git a/test/volume_rate_of_change.c b/test/volume_rate_of_change.c new file mode 100644 index 0000000..f322c69 --- /dev/null +++ b/test/volume_rate_of_change.c @@ -0,0 +1,29 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_volume_rate_of_change( void ) +{ + uint_t k = TS_TEST_K; + + fp_t const o[] = { 10, 11, 12, 11, 12, 10, 11, 13, 12, 14 }; + fp_t const h[] = { 12, 13, 14, 12, 14, 11, 12, 15, 14, 16 }; + fp_t const l[] = { 8, 9, 10, 9, 10, 9, 10, 11, 10, 12 }; + fp_t const c[] = { 11, 12, 10, 11, 11, 10, 12, 14, 13, 15 }; + fp_t const v[] = { 100, 200, 300, 400, 500, 300, 200, 400, 300, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t e[5]; + + for( uint_t i = k; i < 10; ++i ) + { + fp_t v_prev = v[i - k]; + e[i - k] = v_prev != 0 ? ( v[i] - v_prev ) / v_prev * 100 : 0; + } + + fp_t const * const e_arr[1] = { e }; + + uint_t c_val = k; + + return ts_test(ts_volume_rate_of_change, ts_volume_rate_of_change_offset, x, e_arr, 10, (ts_constant_t *)&c_val, &ts_volume_rate_of_change_p); +} diff --git a/test/volume_underlay.c b/test/volume_underlay.c new file mode 100644 index 0000000..f02d0c0 --- /dev/null +++ b/test/volume_underlay.c @@ -0,0 +1,16 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_volume_underlay( void ) +{ + fp_t const v[] = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 }; + + fp_t const * const x[] = { v }; + + fp_t e[] = { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 }; + + fp_t const * const e_arr[1] = { e }; + uint_t c_val = 1; + + return ts_test(ts_volume_underlay, ts_volume_underlay_offset, x, e_arr, 10, (ts_constant_t *)&c_val, &ts_volume_underlay_p); +} diff --git a/test/volume_weighted_moving_average.c b/test/volume_weighted_moving_average.c new file mode 100644 index 0000000..092d937 --- /dev/null +++ b/test/volume_weighted_moving_average.c @@ -0,0 +1,39 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_volume_weighted_moving_average( void ) +{ + uint_t k = 3; + + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + fp_t const v[] = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t cv_sum = 0; + fp_t v_sum = 0; + + for( uint_t i = 0; i < k; ++i ) + { + cv_sum += c[i] * v[i]; + v_sum += v[i]; + } + + fp_t e[8] = { 0 }; + e[0] = ( v_sum != 0 ) ? cv_sum / v_sum : 0; + + for( uint_t i = k; i < 10; ++i ) + { + cv_sum += c[i] * v[i] - c[i - k] * v[i - k]; + v_sum += v[i] - v[i - k]; + e[i - (k - 1)] = ( v_sum != 0 ) ? cv_sum / v_sum : 0; + } + + fp_t const * const e_arr[1] = { e }; + uint_t c_val = k; + + return ts_test(ts_volume_weighted_moving_average, ts_volume_weighted_moving_average_offset, x, e_arr, 10, (ts_constant_t *)&c_val, &ts_volume_weighted_moving_average_p); +} diff --git a/test/vortex_indicator.c b/test/vortex_indicator.c new file mode 100644 index 0000000..c4e06ba --- /dev/null +++ b/test/vortex_indicator.c @@ -0,0 +1,27 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_vortex_indicator( void ) +{ + /* k=3 */ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15,16, 17, 18 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + fp_t const * const x[] = { o, h, l, c }; + + /* VM+(i): |H[i]-L[i-1]| = |13-9|=4, |14-10|=4, |15-11|=4 */ + /* VM-(i): |L[i]-H[i-1]| = |10-12|=2, |11-13|=2, |12-14|=2 */ + /* TR(i): max(3,|13-11|=2,|10-11|=1)=3, max(3,|14-12|=2,|11-12|=1)=3, max(3,|15-13|=2,|12-13|=1)=3 */ + /* SUM_VM+=(1..3) = 12, SUM_VM- = 6, SUM_TR = 9 */ + /* VI+ = 12/9 = 4/3, VI- = 6/9 = 2/3 */ + /* All bars same pattern: VI+=4/3, VI-=2/3 */ + fp_t const evp[] = { 4.0 / 3.0, 4.0 / 3.0, 4.0 / 3.0, 4.0 / 3.0, 4.0 / 3.0, 4.0 / 3.0, 4.0 / 3.0 }; + fp_t const evm[] = { 2.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0 }; + fp_t const * const exp[2] = { evp, evm }; + + uint_t k = 3; + return ts_test(ts_vortex_indicator, ts_vortex_indicator_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_vortex_indicator_p); +} diff --git a/test/vwap.c b/test/vwap.c new file mode 100644 index 0000000..c4ad2a3 --- /dev/null +++ b/test/vwap.c @@ -0,0 +1,28 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_vwap( void ) +{ + fp_t const o[] = { 10, 11, 12, 11, 12 }; + fp_t const h[] = { 12, 13, 14, 12, 14 }; + fp_t const l[] = { 8, 9, 10, 9, 10 }; + fp_t const c[] = { 11, 12, 10, 11, 11 }; + fp_t const v[] = { 100, 200, 300, 400, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t sum_cv = 0; + fp_t sum_v = 0; + fp_t e[5] = { 0 }; + + for( uint_t i = 0; i < 5; ++i ) + { + sum_cv += c[i] * v[i]; + sum_v += v[i]; + e[i] = sum_v != 0 ? sum_cv / sum_v : 0; + } + + fp_t const * const e_arr[1] = { e }; + + return ts_test(ts_vwap, ts_vwap_offset, x, e_arr, 5, (ts_constant_t *)NULL, &ts_vwap_p); +} diff --git a/test/vwap_period.c b/test/vwap_period.c new file mode 100644 index 0000000..d8a9d51 --- /dev/null +++ b/test/vwap_period.c @@ -0,0 +1,42 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_vwap_period( void ) +{ + uint_t k = TS_TEST_K; + + fp_t const o[] = { 10, 11, 12, 11, 12, 10, 11, 13, 12, 14 }; + fp_t const h[] = { 12, 13, 14, 12, 14, 11, 12, 15, 14, 16 }; + fp_t const l[] = { 8, 9, 10, 9, 10, 9, 10, 11, 10, 12 }; + fp_t const c[] = { 11, 12, 10, 11, 11, 10, 12, 14, 13, 15 }; + fp_t const v[] = { 100, 200, 300, 400, 500, 300, 200, 400, 300, 500 }; + + fp_t const * const x[] = { o, h, l, c, v }; + + fp_t sum_cv = 0; + fp_t sum_v = 0; + uint_t count = 0; + uint_t offset = k - 1; + fp_t e[10] = { 0 }; + + for( uint_t i = 0; i < 10; ++i ) + { + sum_cv += c[i] * v[i]; + sum_v += v[i]; + count++; + if (i >= offset) + e[i - offset] = sum_v != 0 ? sum_cv / sum_v : 0; + if( count >= k ) + { + sum_cv = 0; + sum_v = 0; + count = 0; + } + } + + fp_t const * const e_arr[1] = { e }; + + uint_t c_val = k; + + return ts_test(ts_vwap_period, ts_vwap_period_offset, x, e_arr, 10, (ts_constant_t *)&c_val, &ts_vwap_period_p); +} diff --git a/test/weibull_pdf.c b/test/weibull_pdf.c new file mode 100644 index 0000000..04ff453 --- /dev/null +++ b/test/weibull_pdf.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_weibull_pdf( void ) +{ + fp_t const c[] = { 2.000000 }; + + fp_t const x0[] = { 0.000000, 0.500000, 1.000000, 2.000000, 3.000000 }; + fp_t const e0[] = { 0.000000, 0.778801, 0.735759, 0.073263, 0.000740 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_weibull_pdf, ts_weibull_pdf_offset, x, e, sizeof( c ) / sizeof( *c ), (ts_constant_t *)&c, &ts_weibull_pdf_p); +} diff --git a/test/weighted_close.c b/test/weighted_close.c new file mode 100644 index 0000000..46084c8 --- /dev/null +++ b/test/weighted_close.c @@ -0,0 +1,17 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_weighted_close( void ) +{ + fp_t const x0[] = { 1, 1, 1, 1, 1 }; + fp_t const x1[] = { 4, 6, 8, 10, 12 }; + fp_t const x2[] = { 0, 2, 4, 6, 8 }; + fp_t const x3[] = { 3, 5, 7, 9, 11 }; + fp_t const x4[] = { 1, 1, 1, 1, 1 }; + fp_t const e0[] = { 2.5, 4.5, 6.5, 8.5, 10.5 }; + + fp_t const * const x[] = { x0, x1, x2, x3, x4 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_weighted_close, ts_weighted_close_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_weighted_close_p); +} diff --git a/test/wilders_smoothing.c b/test/wilders_smoothing.c new file mode 100644 index 0000000..4bb6037 --- /dev/null +++ b/test/wilders_smoothing.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_wilders_smoothing( void ) +{ + fp_t const x0[] = { -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10 }; + fp_t const e0[] = { -10, -8.75, -6.875, -4.6875, -2.34375, 0.078125, 2.5390625, 5.01953125, 7.509765625 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + fp_t c = 2; + + return ts_test(ts_wilders_smoothing, ts_wilders_smoothing_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_wilders_smoothing_p); +} diff --git a/test/williams_r.c b/test/williams_r.c new file mode 100644 index 0000000..5d9f32f --- /dev/null +++ b/test/williams_r.c @@ -0,0 +1,22 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_williams_r( void ) +{ + /* k=3, monotonic increase. C is always at the high end. */ + /* i=2: HH=14, LL=9, C=13 => -100*(14-13)/(14-9) = -20 */ + /* i=3: HH=15, LL=10, C=14 => -100*(15-14)/(15-10) = -20 */ + /* i=4: HH=16, LL=11, C=15 => -20 */ + fp_t const o[] = { 10, 11, 12, 13, 14, 15, 16, 17 }; + fp_t const h[] = { 12, 13, 14, 15, 16, 17, 18, 19 }; + fp_t const l[] = { 9, 10, 11, 12, 13, 14, 15, 16 }; + fp_t const c[] = { 11, 12, 13, 14, 15, 16, 17, 18 }; + + fp_t const * const x[] = { o, h, l, c }; + fp_t const e[] = { -20, -20, -20, -20, -20, -20 }; + fp_t const * const exp[1] = { e }; + + uint_t k = 3; + return ts_test(ts_williams_r, ts_williams_r_offset, x, exp, sizeof( o ) / sizeof( *o ), (ts_constant_t *)&k, &ts_williams_r_p); +} diff --git a/test/zero_lag_ema.c b/test/zero_lag_ema.c new file mode 100644 index 0000000..013c102 --- /dev/null +++ b/test/zero_lag_ema.c @@ -0,0 +1,21 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_zero_lag_ema( void ) +{ + fp_t const x0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + fp_t const e0[] = { + 6.59259259259259, + 7.39506172839506, + 8.26337448559671, + 9.17558299039781, + 10.11705532693187 + }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + uint_t c = 5; + + return ts_test(ts_zero_lag_ema, ts_zero_lag_ema_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)&c, &ts_zero_lag_ema_p); +} diff --git a/test/zeta.c b/test/zeta.c new file mode 100644 index 0000000..d7282df --- /dev/null +++ b/test/zeta.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include "ts.h" + +bool ts_test_zeta( void ) +{ + fp_t const x0[] = { 2.000000, 3.000000, 4.000000 }; + fp_t const e0[] = { 1.644934, 1.202057, 1.082323 }; + + fp_t const * const x[1] = { x0 }; + fp_t const * const e[1] = { e0 }; + + return ts_test(ts_zeta, ts_zeta_offset, x, e, sizeof( x0 ) / sizeof( *x0 ), (ts_constant_t *)NULL, &ts_zeta_p); +} diff --git a/test/zigzag.c b/test/zigzag.c new file mode 100644 index 0000000..890a1f0 --- /dev/null +++ b/test/zigzag.c @@ -0,0 +1,29 @@ +#include <math.h> +#include <stddef.h> +#include "ts.h" + +bool ts_test_zigzag( void ) +{ + /* threshold=5% */ + /* Prices: 100, 102, 104, 108, 110, 105, 95, 90, 94, 98 */ + fp_t const x[] = { 100, 102, 104, 108, 110, 105, 95, 90, 94, 98 }; + + fp_t const * const inp[1] = { x }; + + /* i=0: zz=100, dir=0 */ + /* i=1: change=(102-100)/100*100=2% < 5%, no change */ + /* i=2: change=4% < 5%, no change */ + /* i=3: change=8% >= 5%, zz=108, dir=1 */ + /* i=4: change=(110-108)/108*100=1.85% < 5%, no change */ + /* i=5: change=(105-108)/108*100=-2.78% > -5%, no change */ + /* i=6: change=(95-108)/108*100=-12.04% <= -5%, zz=95, dir=-1 */ + /* i=7: change=(90-95)/95*100=-5.26% <= -5%, zz=90, dir=-1 */ + /* i=8: change=(94-90)/90*100=4.44% < 5%, no change */ + /* i=9: change=(98-90)/90*100=8.89% >= 5%, zz=98, dir=1 */ + fp_t const ezz[] = { 100, 100, 100, 108, 108, 108, 95, 95, 95, 95 }; + fp_t const ed[] = { 0, 0, 0, 1, 1, 1, -1, -1, -1, -1 }; + fp_t const * const exp[2] = { ezz, ed }; + + fp_t threshold = 5; + return ts_test(ts_zigzag, ts_zigzag_offset, inp, exp, sizeof( x ) / sizeof( *x ), (ts_constant_t *)&threshold, &ts_zigzag_p); +} |