Files
wickra/bindings/c/src/lib.rs
T
kingchenc 12681e4b1b C ABI: full example suite + docs & About coverage (#224)
Stacked on #222 (base `feat/c-abi-hub`), so the diff is just the additions on top of the hub foundation — no merge of #222 required.

## What this adds

**Examples — full parity with rust/python/node (`examples/c/`)**
- `streaming.c` upgraded to the multi-indicator (SMA/EMA/RSI/MACD + signals) demo
- `backtest.c`, `multi_timeframe.c` (manual time-bucket resampling), `parallel_assets.c` (serial vs OpenMP fan-out, one handle per asset)
- three educational strategies: `strategy_rsi_mean_reversion.c`, `strategy_macd_adx.c`, `strategy_bollinger_squeeze.c`
- two network examples shelling out to `curl`: `fetch_btcusdt.c`, `live_binance.c` (REST poll)
- two header-only helpers (`wickra_csv.h`, `wickra_strategy.h`) since the C ABI ships no IO layer
- CMake builds all 11; the 9 offline ones run under `ctest` on 3 OS; the network two are built-only

**Docs & metadata — surface the C ABI everywhere it was missing**
- ARCHITECTURE diagram + crate table, SECURITY + THREAT_MODEL (the C ABI as the sole `unsafe` FFI surface), the three binding package READMEs, issue/PR templates, CHANGELOG, and the GitHub About template (live About + org description updated too)

**Cleanup**
- removed all references to the private generator tooling from public files (`bindings/c/src/lib.rs` header, `CONTRIBUTING.md`, `sync-about.yml`)

Verified locally: `cargo build -p wickra-c --release`, `cmake + ctest` (9/9 pass), and `-Wall -Wextra -Wpedantic` clean on gcc 13.
2026-06-09 02:14:28 +02:00

44291 lines
1.3 MiB
Plaintext

//! C ABI for Wickra — the hub every C-capable language (C, C++, Go, C#, Java, R)
//! links against. Each indicator is exposed as `extern "C"` functions over an
//! opaque handle:
//!
//! - `wickra_<ind>_new(...)` — construct; returns `NULL` on invalid parameters.
//! - `wickra_<ind>_update(h, ...)` — feed one point; returns the output, or `NaN`
//! while warming up / if `h` is `NULL` / if the inputs are invalid.
//! - `wickra_<ind>_batch(h, ..., out, n)` — write one output per input into the
//! caller-owned `out` buffer (length `n`), `NaN` at warmup positions.
//! - `wickra_<ind>_reset(h)` — clear all state.
//! - `wickra_<ind>_free(h)` — destroy the handle. Every `_new` must be paired
//! with exactly one `_free`; there is no RAII across the C boundary.
//!
//! GENERATED from the Wickra core. Do not edit by hand — regenerate from the
//! core and commit this file together with `include/wickra.h`.
use core::ptr;
use core::slice;
use wickra_core::{
AbandonedBaby, Abcd, AbsoluteBreadthIndex, AccelerationBands, AcceleratorOscillator,
AdOscillator, AdVolumeLine, AdaptiveCci, AdaptiveCycle, AdaptiveLaguerreFilter, AdaptiveRsi,
Adl, AdvanceBlock, AdvanceDecline, AdvanceDeclineRatio, Adx, Adxr, Alligator, Alma, Alpha,
AmihudIlliquidity, AnchoredRsi, AnchoredVwap, AndrewsPitchfork, Apo, Aroon, AroonOscillator,
Atr, AtrBands, AtrRatchet, AtrTrailingStop, AutoFib, Autocorrelation,
AutocorrelationPeriodogram, AverageDailyRange, AverageDrawdown, AvgPrice, AwesomeOscillator,
AwesomeOscillatorHistogram, BalanceOfPower, BandpassFilter, BarBuilder, Bat, BeltHold, Beta,
BetaNeutralSpread, BetterVolume, BipowerVariation, BodySizePct, BollingerBands,
BollingerBandwidth, BomarBands, BreadthThrust, Breakaway, BullishPercentIndex, BurkeRatio,
Butterfly, CalendarSpread, CalmarRatio, Camarilla, Candle, CandleVolume, Cci, CenterOfGravity,
CentralPivotRange, Cfo, ChaikinMoneyFlow, ChaikinOscillator, ChaikinVolatility,
ChandeKrollStop, ChandelierExit, ChoppinessIndex, ClassicPivots, CloseVsOpen, ClosingMarubozu,
Cmo, CoefficientOfVariation, Cointegration, CommonSenseRatio, CompositeProfile,
ConcealingBabySwallow, ConditionalValueAtRisk, ConnorsRsi, Coppock, CorrelationTrendIndicator,
Counterattack, Crab, CrossSection, CumulativeVolumeDelta, CumulativeVolumeIndex, CupAndHandle,
CyberneticCycle, Cypher, DayOfWeekProfile, Decycler, DecyclerOscillator, Dema, DemandIndex,
DemarkPivots, DepthSlope, DerivativeOscillator, DerivativesTick, DetrendedStdDev,
DisparityIndex, DistanceSsd, Doji, DojiStar, DollarBars, Donchian, DonchianStop,
DoubleBollinger, DoubleTopBottom, DownsideGapThreeMethods, Dpo, DragonflyDoji,
DrawdownDuration, DumplingTop, Dx, DynamicMomentumIndex, EaseOfMovement, EffectiveSpread,
EhlersStochastic, Ehma, ElderImpulse, ElderRay, ElderSafeZone, Ema, EmpiricalModeDecomposition,
Engulfing, Equivolume, EstimatedLeverageRatio, EvenBetterSinewave, EveningDojiStar, Evwma,
EwmaVolatility, Expectancy, FallingThreeMethods, Fama, FibArcs, FibChannel, FibConfluence,
FibExtension, FibFan, FibProjection, FibRetracement, FibTimeZones, FibonacciPivots, FisherRsi,
FisherTransform, FlagPennant, Footprint, ForceIndex, FractalChaosBands, Frama, FryPanBottom,
FundingBasis, FundingImpliedApr, FundingRate, FundingRateMean, FundingRateZScore,
GainLossRatio, GainToPainRatio, GapSideBySideWhite, Garch11, GarmanKlassVolatility, Gartley,
GatorOscillator, GeneralizedDema, GeometricMa, GoldenPocket, GrangerCausality, GravestoneDoji,
Hammer, HangingMan, Harami, HaramiCross, HasbrouckInformationShare, HeadAndShoulders,
HeikinAshi, HeikinAshiOscillator, HiLoActivator, HighLowIndex, HighLowRange,
HighLowVolumeNodes, HighWave, HighpassFilter, Hikkake, HikkakeModified, HilbertDominantCycle,
HistoricalVolatility, Hma, HoltWinters, HomingPigeon, HtDcPhase, HtPhasor, HtTrendMode,
HurstChannel, HurstExponent, Ichimoku, IdenticalThreeCrows, ImbalanceBars, InNeck, Indicator,
Inertia, InformationRatio, InitialBalance, InstantaneousTrendline, IntradayIntensity,
IntradayMomentumIndex, IntradayVolatilityProfile, InverseFisherTransform, InvertedHammer,
JarqueBera, Jma, JumpIndicator, KRatio, KagiBars, KalmanHedgeRatio, Kama, KaseDevStop,
KasePermissionStochastic, KellyCriterion, Keltner, KendallTau, Kicking, KickingByLength, Kst,
Kurtosis, Kvo, KylesLambda, LadderBottom, LaguerreRsi, LeadLagCrossCorrelation, Level,
LinRegAngle, LinRegChannel, LinRegIntercept, LinRegSlope, LinearRegression,
LiquidationFeatures, LogReturn, LongLeggedDoji, LongLine, LongShortRatio, M2Measure,
MaEnvelope, MaType, MacdExt, MacdFix, MacdHistogram, MacdIndicator, Mama,
MarketFacilitationIndex, MartinRatio, Marubozu, MassIndex, MatHold, MatchingLow, MaxDrawdown,
McClellanOscillator, McClellanSummationIndex, McGinleyDynamic, MedianAbsoluteDeviation,
MedianChannel, MedianMa, MedianPrice, Member, Mfi, Microprice, MidPoint, MidPrice, MinusDi,
MinusDm, ModifiedMaStop, Mom, MorningDojiStar, MorningEveningStar, MurreyMathLines, NakedPoc,
Natr, NewHighsNewLows, NewPriceLines, Nrtr, Nvi, OIPriceDivergence, OIWeighted, Obv,
OiToVolumeRatio, OmegaRatio, OnNeck, OpenInterestDelta, OpenInterestMomentum, OpeningMarubozu,
OpeningRange, OrderBook, OrderBookImbalanceFull, OrderBookImbalanceTop1,
OrderBookImbalanceTopN, OrderFlowImbalance, OuHalfLife, OvernightGap, OvernightIntradayReturn,
PainIndex, PairSpreadZScore, PairwiseBeta, ParkinsonVolatility, PearsonCorrelation,
PercentAboveMa, PercentB, PercentageTrailingStop, PerpetualPremiumIndex, Pgo,
PiercingDarkCloud, Pin, PivotReversal, PlusDi, PlusDm, Pmo, PointAndFigureBars,
PolarizedFractalEfficiency, Ppo, PpoHistogram, ProfileShape, ProfitFactor, ProjectionBands,
ProjectionOscillator, Psar, Pvi, Qqe, Qstick, QuartileBands, QuotedSpread, RSquared, RangeBars,
RealizedSpread, RealizedVolatility, RecoveryFactor, RectangleRange, Reflex, RegimeLabel,
RelativeStrengthAB, RenkoBars, RenkoTrailingStop, RickshawMan, RisingThreeMethods, Rmi, Roc,
Rocp, Rocr, Rocr100, RogersSatchellVolatility, RollMeasure, RollingCorrelation,
RollingCovariance, RollingIqr, RollingMinMaxScaler, RollingPercentileRank, RollingQuantile,
RollingVwap, RoofingFilter, Rsi, Rsx, RunBars, Rvi, RviVolatility, Rwi, SampleEntropy, SarExt,
SeasonalZScore, SeparatingLines, SessionHighLow, SessionRange, SessionVwap, ShannonEntropy,
Shark, SharpeRatio, ShootingStar, ShortLine, Side, SignedVolume, SineWave, SineWeightedMa,
SinglePrints, Skewness, Sma, Smi, Smma, SmoothedHeikinAshi, SortinoRatio, SpearmanCorrelation,
SpinningTop, SpreadAr1Coefficient, SpreadBollingerBands, SpreadHurst, StalledPattern,
StandardError, StandardErrorBands, StarcBands, Stc, StdDev, StepTrailingStop, SterlingRatio,
StickSandwich, StochRsi, Stochastic, StochasticCci, SuperSmoother, SuperTrend, TailRatio,
TakerBuySellRatio, Takuri, TasukiGap, TdCamouflage, TdClop, TdClopwin, TdCombo, TdCountdown,
TdDWave, TdDeMarker, TdDifferential, TdLines, TdMovingAverage, TdOpen, TdPressure,
TdPropulsion, TdRangeProjection, TdRei, TdRiskLevel, TdSequential, TdSetup, TdTrap, Tema,
TermStructureBasis, ThreeDrives, ThreeInside, ThreeLineBreak, ThreeLineBreakBars,
ThreeLineStrike, ThreeOutside, ThreeSoldiersOrCrows, ThreeStarsInSouth, Thrusting, TickBars,
TickIndex, Tii, TimeBasedStop, TimeOfDayReturnProfile, TowerTopBottom, TpoProfile, Trade,
TradeImbalance, TradeQuote, TradeSignAutocorrelation, TradeVolumeIndex, TrendLabel,
TrendStrengthIndex, Trendflex, TreynorRatio, Triangle, Trima, Trin, TripleTopBottom, Tristar,
Trix, TrueRange, Tsf, TsfOscillator, Tsi, Tsv, TtmSqueeze, TtmTrend, TurnOfMonth, Tweezer,
TwiggsMoneyFlow, TwoCrows, TypicalPrice, UlcerIndex, UltimateOscillator, UniqueThreeRiver,
UniversalOscillator, UpDownVolumeRatio, UpsideGapThreeMethods, UpsideGapTwoCrows,
UpsidePotentialRatio, ValueArea, ValueAtRisk, Variance, VarianceRatio,
VerticalHorizontalFilter, Vidya, VolatilityCone, VolatilityOfVolatility, VolatilityRatio,
VoltyStop, VolumeBars, VolumeByTimeProfile, VolumeOscillator, VolumePriceTrend, VolumeProfile,
VolumeRsi, VolumeWeightedMacd, VolumeWeightedSr, Vortex, Vpin, Vwap, VwapStdDevBands, Vwma,
Vzo, Wad, WavePm, WaveTrend, Wedge, WeightedClose, WickRatio, WilliamsFractals, WilliamsR,
WinRate, Wma, WoodiePivots, YangZhangVolatility, YoyoExit, ZScore, ZeroLagMacd, ZigZag, Zlema,
T3,
};
// ===== Scalar indicators (f64 -> f64) =====
/// Create a `AdaptiveCycle` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_adaptive_cycle_free`.
#[no_mangle]
pub extern "C" fn wickra_adaptive_cycle_new() -> *mut AdaptiveCycle {
Box::into_raw(Box::new(AdaptiveCycle::new()))
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_adaptive_cycle_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_cycle_update(
handle: *mut AdaptiveCycle,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_adaptive_cycle_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_cycle_batch(
handle: *mut AdaptiveCycle,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_adaptive_cycle_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_cycle_reset(handle: *mut AdaptiveCycle) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_adaptive_cycle_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_adaptive_cycle_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_cycle_free(handle: *mut AdaptiveCycle) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AdaptiveLaguerreFilter` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_adaptive_laguerre_filter_free`.
#[no_mangle]
pub extern "C" fn wickra_adaptive_laguerre_filter_new(
period: usize,
) -> *mut AdaptiveLaguerreFilter {
match AdaptiveLaguerreFilter::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_adaptive_laguerre_filter_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_laguerre_filter_update(
handle: *mut AdaptiveLaguerreFilter,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_adaptive_laguerre_filter_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_laguerre_filter_batch(
handle: *mut AdaptiveLaguerreFilter,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_adaptive_laguerre_filter_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_laguerre_filter_reset(
handle: *mut AdaptiveLaguerreFilter,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_adaptive_laguerre_filter_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_adaptive_laguerre_filter_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_laguerre_filter_free(handle: *mut AdaptiveLaguerreFilter) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AdaptiveRsi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_adaptive_rsi_free`.
#[no_mangle]
pub extern "C" fn wickra_adaptive_rsi_new(period: usize) -> *mut AdaptiveRsi {
match AdaptiveRsi::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_adaptive_rsi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_rsi_update(handle: *mut AdaptiveRsi, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_adaptive_rsi_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_rsi_batch(
handle: *mut AdaptiveRsi,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_adaptive_rsi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_rsi_reset(handle: *mut AdaptiveRsi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_adaptive_rsi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_adaptive_rsi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_rsi_free(handle: *mut AdaptiveRsi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Alma` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_alma_free`.
#[no_mangle]
pub extern "C" fn wickra_alma_new(period: usize, offset: f64, sigma: f64) -> *mut Alma {
match Alma::new(period, offset, sigma) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_alma_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_alma_update(handle: *mut Alma, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_alma_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_alma_batch(
handle: *mut Alma,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_alma_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_alma_reset(handle: *mut Alma) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_alma_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_alma_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_alma_free(handle: *mut Alma) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AnchoredRsi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_anchored_rsi_free`.
#[no_mangle]
pub extern "C" fn wickra_anchored_rsi_new() -> *mut AnchoredRsi {
Box::into_raw(Box::new(AnchoredRsi::new()))
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_anchored_rsi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_anchored_rsi_update(handle: *mut AnchoredRsi, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_anchored_rsi_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_anchored_rsi_batch(
handle: *mut AnchoredRsi,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_anchored_rsi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_anchored_rsi_reset(handle: *mut AnchoredRsi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_anchored_rsi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_anchored_rsi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_anchored_rsi_free(handle: *mut AnchoredRsi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Apo` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_apo_free`.
#[no_mangle]
pub extern "C" fn wickra_apo_new(fast: usize, slow: usize) -> *mut Apo {
match Apo::new(fast, slow) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_apo_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_apo_update(handle: *mut Apo, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_apo_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_apo_batch(
handle: *mut Apo,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_apo_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_apo_reset(handle: *mut Apo) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_apo_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_apo_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_apo_free(handle: *mut Apo) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Autocorrelation` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_autocorrelation_free`.
#[no_mangle]
pub extern "C" fn wickra_autocorrelation_new(period: usize, lag: usize) -> *mut Autocorrelation {
match Autocorrelation::new(period, lag) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_autocorrelation_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_autocorrelation_update(
handle: *mut Autocorrelation,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_autocorrelation_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_autocorrelation_batch(
handle: *mut Autocorrelation,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_autocorrelation_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_autocorrelation_reset(handle: *mut Autocorrelation) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_autocorrelation_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_autocorrelation_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_autocorrelation_free(handle: *mut Autocorrelation) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AutocorrelationPeriodogram` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_autocorrelation_periodogram_free`.
#[no_mangle]
pub extern "C" fn wickra_autocorrelation_periodogram_new(
min_period: usize,
max_period: usize,
) -> *mut AutocorrelationPeriodogram {
match AutocorrelationPeriodogram::new(min_period, max_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_autocorrelation_periodogram_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_autocorrelation_periodogram_update(
handle: *mut AutocorrelationPeriodogram,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_autocorrelation_periodogram_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_autocorrelation_periodogram_batch(
handle: *mut AutocorrelationPeriodogram,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_autocorrelation_periodogram_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_autocorrelation_periodogram_reset(
handle: *mut AutocorrelationPeriodogram,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_autocorrelation_periodogram_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_autocorrelation_periodogram_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_autocorrelation_periodogram_free(
handle: *mut AutocorrelationPeriodogram,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AverageDrawdown` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_average_drawdown_free`.
#[no_mangle]
pub extern "C" fn wickra_average_drawdown_new(period: usize) -> *mut AverageDrawdown {
match AverageDrawdown::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_average_drawdown_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_average_drawdown_update(
handle: *mut AverageDrawdown,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_average_drawdown_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_average_drawdown_batch(
handle: *mut AverageDrawdown,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_average_drawdown_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_average_drawdown_reset(handle: *mut AverageDrawdown) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_average_drawdown_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_average_drawdown_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_average_drawdown_free(handle: *mut AverageDrawdown) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `BandpassFilter` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_bandpass_filter_free`.
#[no_mangle]
pub extern "C" fn wickra_bandpass_filter_new(period: usize, bandwidth: f64) -> *mut BandpassFilter {
match BandpassFilter::new(period, bandwidth) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_bandpass_filter_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bandpass_filter_update(
handle: *mut BandpassFilter,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_bandpass_filter_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_bandpass_filter_batch(
handle: *mut BandpassFilter,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_bandpass_filter_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bandpass_filter_reset(handle: *mut BandpassFilter) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_bandpass_filter_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_bandpass_filter_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bandpass_filter_free(handle: *mut BandpassFilter) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `BipowerVariation` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_bipower_variation_free`.
#[no_mangle]
pub extern "C" fn wickra_bipower_variation_new(period: usize) -> *mut BipowerVariation {
match BipowerVariation::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_bipower_variation_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bipower_variation_update(
handle: *mut BipowerVariation,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_bipower_variation_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_bipower_variation_batch(
handle: *mut BipowerVariation,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_bipower_variation_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bipower_variation_reset(handle: *mut BipowerVariation) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_bipower_variation_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_bipower_variation_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bipower_variation_free(handle: *mut BipowerVariation) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `BollingerBandwidth` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_bollinger_bandwidth_free`.
#[no_mangle]
pub extern "C" fn wickra_bollinger_bandwidth_new(
period: usize,
multiplier: f64,
) -> *mut BollingerBandwidth {
match BollingerBandwidth::new(period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_bollinger_bandwidth_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bollinger_bandwidth_update(
handle: *mut BollingerBandwidth,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_bollinger_bandwidth_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_bollinger_bandwidth_batch(
handle: *mut BollingerBandwidth,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_bollinger_bandwidth_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bollinger_bandwidth_reset(handle: *mut BollingerBandwidth) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_bollinger_bandwidth_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_bollinger_bandwidth_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bollinger_bandwidth_free(handle: *mut BollingerBandwidth) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `BurkeRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_burke_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_burke_ratio_new(period: usize) -> *mut BurkeRatio {
match BurkeRatio::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_burke_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_burke_ratio_update(handle: *mut BurkeRatio, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_burke_ratio_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_burke_ratio_batch(
handle: *mut BurkeRatio,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_burke_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_burke_ratio_reset(handle: *mut BurkeRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_burke_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_burke_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_burke_ratio_free(handle: *mut BurkeRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `CalmarRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_calmar_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_calmar_ratio_new(period: usize) -> *mut CalmarRatio {
match CalmarRatio::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_calmar_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_calmar_ratio_update(handle: *mut CalmarRatio, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_calmar_ratio_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_calmar_ratio_batch(
handle: *mut CalmarRatio,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_calmar_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_calmar_ratio_reset(handle: *mut CalmarRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_calmar_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_calmar_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_calmar_ratio_free(handle: *mut CalmarRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `CenterOfGravity` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_center_of_gravity_free`.
#[no_mangle]
pub extern "C" fn wickra_center_of_gravity_new(period: usize) -> *mut CenterOfGravity {
match CenterOfGravity::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_center_of_gravity_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_center_of_gravity_update(
handle: *mut CenterOfGravity,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_center_of_gravity_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_center_of_gravity_batch(
handle: *mut CenterOfGravity,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_center_of_gravity_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_center_of_gravity_reset(handle: *mut CenterOfGravity) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_center_of_gravity_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_center_of_gravity_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_center_of_gravity_free(handle: *mut CenterOfGravity) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Cfo` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_cfo_free`.
#[no_mangle]
pub extern "C" fn wickra_cfo_new(period: usize) -> *mut Cfo {
match Cfo::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_cfo_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cfo_update(handle: *mut Cfo, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_cfo_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_cfo_batch(
handle: *mut Cfo,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_cfo_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cfo_reset(handle: *mut Cfo) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_cfo_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_cfo_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cfo_free(handle: *mut Cfo) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Cmo` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_cmo_free`.
#[no_mangle]
pub extern "C" fn wickra_cmo_new(period: usize) -> *mut Cmo {
match Cmo::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_cmo_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cmo_update(handle: *mut Cmo, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_cmo_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_cmo_batch(
handle: *mut Cmo,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_cmo_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cmo_reset(handle: *mut Cmo) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_cmo_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_cmo_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cmo_free(handle: *mut Cmo) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `CoefficientOfVariation` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_coefficient_of_variation_free`.
#[no_mangle]
pub extern "C" fn wickra_coefficient_of_variation_new(
period: usize,
) -> *mut CoefficientOfVariation {
match CoefficientOfVariation::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_coefficient_of_variation_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_coefficient_of_variation_update(
handle: *mut CoefficientOfVariation,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_coefficient_of_variation_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_coefficient_of_variation_batch(
handle: *mut CoefficientOfVariation,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_coefficient_of_variation_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_coefficient_of_variation_reset(
handle: *mut CoefficientOfVariation,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_coefficient_of_variation_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_coefficient_of_variation_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_coefficient_of_variation_free(handle: *mut CoefficientOfVariation) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `CommonSenseRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_common_sense_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_common_sense_ratio_new(period: usize) -> *mut CommonSenseRatio {
match CommonSenseRatio::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_common_sense_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_common_sense_ratio_update(
handle: *mut CommonSenseRatio,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_common_sense_ratio_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_common_sense_ratio_batch(
handle: *mut CommonSenseRatio,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_common_sense_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_common_sense_ratio_reset(handle: *mut CommonSenseRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_common_sense_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_common_sense_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_common_sense_ratio_free(handle: *mut CommonSenseRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ConditionalValueAtRisk` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_conditional_value_at_risk_free`.
#[no_mangle]
pub extern "C" fn wickra_conditional_value_at_risk_new(
period: usize,
confidence: f64,
) -> *mut ConditionalValueAtRisk {
match ConditionalValueAtRisk::new(period, confidence) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_conditional_value_at_risk_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_conditional_value_at_risk_update(
handle: *mut ConditionalValueAtRisk,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_conditional_value_at_risk_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_conditional_value_at_risk_batch(
handle: *mut ConditionalValueAtRisk,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_conditional_value_at_risk_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_conditional_value_at_risk_reset(
handle: *mut ConditionalValueAtRisk,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_conditional_value_at_risk_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_conditional_value_at_risk_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_conditional_value_at_risk_free(
handle: *mut ConditionalValueAtRisk,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ConnorsRsi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_connors_rsi_free`.
#[no_mangle]
pub extern "C" fn wickra_connors_rsi_new(
period_rsi: usize,
period_streak: usize,
period_rank: usize,
) -> *mut ConnorsRsi {
match ConnorsRsi::new(period_rsi, period_streak, period_rank) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_connors_rsi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_connors_rsi_update(handle: *mut ConnorsRsi, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_connors_rsi_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_connors_rsi_batch(
handle: *mut ConnorsRsi,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_connors_rsi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_connors_rsi_reset(handle: *mut ConnorsRsi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_connors_rsi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_connors_rsi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_connors_rsi_free(handle: *mut ConnorsRsi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Coppock` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_coppock_free`.
#[no_mangle]
pub extern "C" fn wickra_coppock_new(
roc_long_period: usize,
roc_short_period: usize,
wma_period: usize,
) -> *mut Coppock {
match Coppock::new(roc_long_period, roc_short_period, wma_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_coppock_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_coppock_update(handle: *mut Coppock, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_coppock_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_coppock_batch(
handle: *mut Coppock,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_coppock_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_coppock_reset(handle: *mut Coppock) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_coppock_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_coppock_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_coppock_free(handle: *mut Coppock) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `CorrelationTrendIndicator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_correlation_trend_indicator_free`.
#[no_mangle]
pub extern "C" fn wickra_correlation_trend_indicator_new(
period: usize,
) -> *mut CorrelationTrendIndicator {
match CorrelationTrendIndicator::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_correlation_trend_indicator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_correlation_trend_indicator_update(
handle: *mut CorrelationTrendIndicator,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_correlation_trend_indicator_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_correlation_trend_indicator_batch(
handle: *mut CorrelationTrendIndicator,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_correlation_trend_indicator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_correlation_trend_indicator_reset(
handle: *mut CorrelationTrendIndicator,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_correlation_trend_indicator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_correlation_trend_indicator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_correlation_trend_indicator_free(
handle: *mut CorrelationTrendIndicator,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `CyberneticCycle` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_cybernetic_cycle_free`.
#[no_mangle]
pub extern "C" fn wickra_cybernetic_cycle_new(period: usize) -> *mut CyberneticCycle {
match CyberneticCycle::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_cybernetic_cycle_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cybernetic_cycle_update(
handle: *mut CyberneticCycle,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_cybernetic_cycle_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_cybernetic_cycle_batch(
handle: *mut CyberneticCycle,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_cybernetic_cycle_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cybernetic_cycle_reset(handle: *mut CyberneticCycle) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_cybernetic_cycle_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_cybernetic_cycle_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cybernetic_cycle_free(handle: *mut CyberneticCycle) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Decycler` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_decycler_free`.
#[no_mangle]
pub extern "C" fn wickra_decycler_new(period: usize) -> *mut Decycler {
match Decycler::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_decycler_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_decycler_update(handle: *mut Decycler, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_decycler_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_decycler_batch(
handle: *mut Decycler,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_decycler_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_decycler_reset(handle: *mut Decycler) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_decycler_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_decycler_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_decycler_free(handle: *mut Decycler) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DecyclerOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_decycler_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_decycler_oscillator_new(
fast: usize,
slow: usize,
) -> *mut DecyclerOscillator {
match DecyclerOscillator::new(fast, slow) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_decycler_oscillator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_decycler_oscillator_update(
handle: *mut DecyclerOscillator,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_decycler_oscillator_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_decycler_oscillator_batch(
handle: *mut DecyclerOscillator,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_decycler_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_decycler_oscillator_reset(handle: *mut DecyclerOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_decycler_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_decycler_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_decycler_oscillator_free(handle: *mut DecyclerOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Dema` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_dema_free`.
#[no_mangle]
pub extern "C" fn wickra_dema_new(period: usize) -> *mut Dema {
match Dema::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_dema_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dema_update(handle: *mut Dema, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_dema_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_dema_batch(
handle: *mut Dema,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_dema_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dema_reset(handle: *mut Dema) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_dema_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_dema_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dema_free(handle: *mut Dema) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DerivativeOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_derivative_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_derivative_oscillator_new(
rsi_period: usize,
smooth1: usize,
smooth2: usize,
signal_period: usize,
) -> *mut DerivativeOscillator {
match DerivativeOscillator::new(rsi_period, smooth1, smooth2, signal_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_derivative_oscillator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_derivative_oscillator_update(
handle: *mut DerivativeOscillator,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_derivative_oscillator_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_derivative_oscillator_batch(
handle: *mut DerivativeOscillator,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_derivative_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_derivative_oscillator_reset(handle: *mut DerivativeOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_derivative_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_derivative_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_derivative_oscillator_free(handle: *mut DerivativeOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DetrendedStdDev` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_detrended_std_dev_free`.
#[no_mangle]
pub extern "C" fn wickra_detrended_std_dev_new(period: usize) -> *mut DetrendedStdDev {
match DetrendedStdDev::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_detrended_std_dev_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_detrended_std_dev_update(
handle: *mut DetrendedStdDev,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_detrended_std_dev_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_detrended_std_dev_batch(
handle: *mut DetrendedStdDev,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_detrended_std_dev_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_detrended_std_dev_reset(handle: *mut DetrendedStdDev) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_detrended_std_dev_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_detrended_std_dev_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_detrended_std_dev_free(handle: *mut DetrendedStdDev) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DisparityIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_disparity_index_free`.
#[no_mangle]
pub extern "C" fn wickra_disparity_index_new(period: usize) -> *mut DisparityIndex {
match DisparityIndex::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_disparity_index_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_disparity_index_update(
handle: *mut DisparityIndex,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_disparity_index_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_disparity_index_batch(
handle: *mut DisparityIndex,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_disparity_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_disparity_index_reset(handle: *mut DisparityIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_disparity_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_disparity_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_disparity_index_free(handle: *mut DisparityIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Dpo` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_dpo_free`.
#[no_mangle]
pub extern "C" fn wickra_dpo_new(period: usize) -> *mut Dpo {
match Dpo::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_dpo_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dpo_update(handle: *mut Dpo, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_dpo_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_dpo_batch(
handle: *mut Dpo,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_dpo_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dpo_reset(handle: *mut Dpo) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_dpo_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_dpo_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dpo_free(handle: *mut Dpo) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DrawdownDuration` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_drawdown_duration_free`.
#[no_mangle]
pub extern "C" fn wickra_drawdown_duration_new() -> *mut DrawdownDuration {
Box::into_raw(Box::new(DrawdownDuration::new()))
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_drawdown_duration_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_drawdown_duration_update(
handle: *mut DrawdownDuration,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).map_or(f64::NAN, f64::from),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_drawdown_duration_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_drawdown_duration_batch(
handle: *mut DrawdownDuration,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).map_or(f64::NAN, f64::from);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_drawdown_duration_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_drawdown_duration_reset(handle: *mut DrawdownDuration) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_drawdown_duration_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_drawdown_duration_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_drawdown_duration_free(handle: *mut DrawdownDuration) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DynamicMomentumIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_dynamic_momentum_index_free`.
#[no_mangle]
pub extern "C" fn wickra_dynamic_momentum_index_new(period: usize) -> *mut DynamicMomentumIndex {
match DynamicMomentumIndex::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_dynamic_momentum_index_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dynamic_momentum_index_update(
handle: *mut DynamicMomentumIndex,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_dynamic_momentum_index_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_dynamic_momentum_index_batch(
handle: *mut DynamicMomentumIndex,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_dynamic_momentum_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dynamic_momentum_index_reset(handle: *mut DynamicMomentumIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_dynamic_momentum_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_dynamic_momentum_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dynamic_momentum_index_free(handle: *mut DynamicMomentumIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `EhlersStochastic` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ehlers_stochastic_free`.
#[no_mangle]
pub extern "C" fn wickra_ehlers_stochastic_new(period: usize) -> *mut EhlersStochastic {
match EhlersStochastic::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ehlers_stochastic_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ehlers_stochastic_update(
handle: *mut EhlersStochastic,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_ehlers_stochastic_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_ehlers_stochastic_batch(
handle: *mut EhlersStochastic,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ehlers_stochastic_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ehlers_stochastic_reset(handle: *mut EhlersStochastic) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ehlers_stochastic_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ehlers_stochastic_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ehlers_stochastic_free(handle: *mut EhlersStochastic) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Ehma` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ehma_free`.
#[no_mangle]
pub extern "C" fn wickra_ehma_new(period: usize) -> *mut Ehma {
match Ehma::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ehma_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ehma_update(handle: *mut Ehma, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_ehma_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_ehma_batch(
handle: *mut Ehma,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ehma_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ehma_reset(handle: *mut Ehma) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ehma_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ehma_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ehma_free(handle: *mut Ehma) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ElderImpulse` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_elder_impulse_free`.
#[no_mangle]
pub extern "C" fn wickra_elder_impulse_new(
ema_period: usize,
macd_fast: usize,
macd_slow: usize,
macd_signal: usize,
) -> *mut ElderImpulse {
match ElderImpulse::new(ema_period, macd_fast, macd_slow, macd_signal) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_elder_impulse_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_elder_impulse_update(handle: *mut ElderImpulse, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_elder_impulse_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_elder_impulse_batch(
handle: *mut ElderImpulse,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_elder_impulse_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_elder_impulse_reset(handle: *mut ElderImpulse) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_elder_impulse_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_elder_impulse_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_elder_impulse_free(handle: *mut ElderImpulse) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Ema` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ema_free`.
#[no_mangle]
pub extern "C" fn wickra_ema_new(period: usize) -> *mut Ema {
match Ema::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ema_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ema_update(handle: *mut Ema, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_ema_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_ema_batch(
handle: *mut Ema,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ema_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ema_reset(handle: *mut Ema) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ema_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ema_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ema_free(handle: *mut Ema) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `EmpiricalModeDecomposition` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_empirical_mode_decomposition_free`.
#[no_mangle]
pub extern "C" fn wickra_empirical_mode_decomposition_new(
period: usize,
fraction: f64,
) -> *mut EmpiricalModeDecomposition {
match EmpiricalModeDecomposition::new(period, fraction) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_empirical_mode_decomposition_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_empirical_mode_decomposition_update(
handle: *mut EmpiricalModeDecomposition,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_empirical_mode_decomposition_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_empirical_mode_decomposition_batch(
handle: *mut EmpiricalModeDecomposition,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_empirical_mode_decomposition_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_empirical_mode_decomposition_reset(
handle: *mut EmpiricalModeDecomposition,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_empirical_mode_decomposition_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_empirical_mode_decomposition_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_empirical_mode_decomposition_free(
handle: *mut EmpiricalModeDecomposition,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `EvenBetterSinewave` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_even_better_sinewave_free`.
#[no_mangle]
pub extern "C" fn wickra_even_better_sinewave_new(
hp_period: usize,
ssf_length: usize,
) -> *mut EvenBetterSinewave {
match EvenBetterSinewave::new(hp_period, ssf_length) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_even_better_sinewave_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_even_better_sinewave_update(
handle: *mut EvenBetterSinewave,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_even_better_sinewave_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_even_better_sinewave_batch(
handle: *mut EvenBetterSinewave,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_even_better_sinewave_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_even_better_sinewave_reset(handle: *mut EvenBetterSinewave) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_even_better_sinewave_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_even_better_sinewave_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_even_better_sinewave_free(handle: *mut EvenBetterSinewave) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `EwmaVolatility` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ewma_volatility_free`.
#[no_mangle]
pub extern "C" fn wickra_ewma_volatility_new(lambda: f64) -> *mut EwmaVolatility {
match EwmaVolatility::new(lambda) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ewma_volatility_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ewma_volatility_update(
handle: *mut EwmaVolatility,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_ewma_volatility_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_ewma_volatility_batch(
handle: *mut EwmaVolatility,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ewma_volatility_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ewma_volatility_reset(handle: *mut EwmaVolatility) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ewma_volatility_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ewma_volatility_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ewma_volatility_free(handle: *mut EwmaVolatility) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Expectancy` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_expectancy_free`.
#[no_mangle]
pub extern "C" fn wickra_expectancy_new(period: usize) -> *mut Expectancy {
match Expectancy::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_expectancy_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_expectancy_update(handle: *mut Expectancy, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_expectancy_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_expectancy_batch(
handle: *mut Expectancy,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_expectancy_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_expectancy_reset(handle: *mut Expectancy) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_expectancy_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_expectancy_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_expectancy_free(handle: *mut Expectancy) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Fama` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_fama_free`.
#[no_mangle]
pub extern "C" fn wickra_fama_new(fast_limit: f64, slow_limit: f64) -> *mut Fama {
match Fama::new(fast_limit, slow_limit) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_fama_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fama_update(handle: *mut Fama, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_fama_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_fama_batch(
handle: *mut Fama,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_fama_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fama_reset(handle: *mut Fama) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_fama_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_fama_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fama_free(handle: *mut Fama) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FisherRsi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_fisher_rsi_free`.
#[no_mangle]
pub extern "C" fn wickra_fisher_rsi_new(period: usize) -> *mut FisherRsi {
match FisherRsi::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_fisher_rsi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fisher_rsi_update(handle: *mut FisherRsi, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_fisher_rsi_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_fisher_rsi_batch(
handle: *mut FisherRsi,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_fisher_rsi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fisher_rsi_reset(handle: *mut FisherRsi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_fisher_rsi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_fisher_rsi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fisher_rsi_free(handle: *mut FisherRsi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FisherTransform` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_fisher_transform_free`.
#[no_mangle]
pub extern "C" fn wickra_fisher_transform_new(period: usize) -> *mut FisherTransform {
match FisherTransform::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_fisher_transform_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fisher_transform_update(
handle: *mut FisherTransform,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_fisher_transform_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_fisher_transform_batch(
handle: *mut FisherTransform,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_fisher_transform_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fisher_transform_reset(handle: *mut FisherTransform) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_fisher_transform_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_fisher_transform_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fisher_transform_free(handle: *mut FisherTransform) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Frama` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_frama_free`.
#[no_mangle]
pub extern "C" fn wickra_frama_new(period: usize) -> *mut Frama {
match Frama::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_frama_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_frama_update(handle: *mut Frama, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_frama_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_frama_batch(
handle: *mut Frama,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_frama_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_frama_reset(handle: *mut Frama) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_frama_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_frama_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_frama_free(handle: *mut Frama) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `GainLossRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_gain_loss_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_gain_loss_ratio_new(period: usize) -> *mut GainLossRatio {
match GainLossRatio::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_gain_loss_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gain_loss_ratio_update(
handle: *mut GainLossRatio,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_gain_loss_ratio_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_gain_loss_ratio_batch(
handle: *mut GainLossRatio,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_gain_loss_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gain_loss_ratio_reset(handle: *mut GainLossRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_gain_loss_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_gain_loss_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gain_loss_ratio_free(handle: *mut GainLossRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `GainToPainRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_gain_to_pain_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_gain_to_pain_ratio_new(period: usize) -> *mut GainToPainRatio {
match GainToPainRatio::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_gain_to_pain_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gain_to_pain_ratio_update(
handle: *mut GainToPainRatio,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_gain_to_pain_ratio_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_gain_to_pain_ratio_batch(
handle: *mut GainToPainRatio,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_gain_to_pain_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gain_to_pain_ratio_reset(handle: *mut GainToPainRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_gain_to_pain_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_gain_to_pain_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gain_to_pain_ratio_free(handle: *mut GainToPainRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Garch11` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_garch11_free`.
#[no_mangle]
pub extern "C" fn wickra_garch11_new(omega: f64, alpha: f64, beta: f64) -> *mut Garch11 {
match Garch11::new(omega, alpha, beta) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_garch11_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_garch11_update(handle: *mut Garch11, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_garch11_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_garch11_batch(
handle: *mut Garch11,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_garch11_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_garch11_reset(handle: *mut Garch11) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_garch11_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_garch11_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_garch11_free(handle: *mut Garch11) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `GeneralizedDema` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_generalized_dema_free`.
#[no_mangle]
pub extern "C" fn wickra_generalized_dema_new(period: usize, v: f64) -> *mut GeneralizedDema {
match GeneralizedDema::new(period, v) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_generalized_dema_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_generalized_dema_update(
handle: *mut GeneralizedDema,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_generalized_dema_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_generalized_dema_batch(
handle: *mut GeneralizedDema,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_generalized_dema_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_generalized_dema_reset(handle: *mut GeneralizedDema) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_generalized_dema_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_generalized_dema_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_generalized_dema_free(handle: *mut GeneralizedDema) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `GeometricMa` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_geometric_ma_free`.
#[no_mangle]
pub extern "C" fn wickra_geometric_ma_new(period: usize) -> *mut GeometricMa {
match GeometricMa::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_geometric_ma_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_geometric_ma_update(handle: *mut GeometricMa, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_geometric_ma_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_geometric_ma_batch(
handle: *mut GeometricMa,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_geometric_ma_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_geometric_ma_reset(handle: *mut GeometricMa) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_geometric_ma_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_geometric_ma_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_geometric_ma_free(handle: *mut GeometricMa) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HighpassFilter` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_highpass_filter_free`.
#[no_mangle]
pub extern "C" fn wickra_highpass_filter_new(period: usize) -> *mut HighpassFilter {
match HighpassFilter::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_highpass_filter_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_highpass_filter_update(
handle: *mut HighpassFilter,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_highpass_filter_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_highpass_filter_batch(
handle: *mut HighpassFilter,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_highpass_filter_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_highpass_filter_reset(handle: *mut HighpassFilter) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_highpass_filter_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_highpass_filter_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_highpass_filter_free(handle: *mut HighpassFilter) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HilbertDominantCycle` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_hilbert_dominant_cycle_free`.
#[no_mangle]
pub extern "C" fn wickra_hilbert_dominant_cycle_new() -> *mut HilbertDominantCycle {
Box::into_raw(Box::new(HilbertDominantCycle::new()))
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_hilbert_dominant_cycle_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hilbert_dominant_cycle_update(
handle: *mut HilbertDominantCycle,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_hilbert_dominant_cycle_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_hilbert_dominant_cycle_batch(
handle: *mut HilbertDominantCycle,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_hilbert_dominant_cycle_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hilbert_dominant_cycle_reset(handle: *mut HilbertDominantCycle) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_hilbert_dominant_cycle_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_hilbert_dominant_cycle_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hilbert_dominant_cycle_free(handle: *mut HilbertDominantCycle) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HistoricalVolatility` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_historical_volatility_free`.
#[no_mangle]
pub extern "C" fn wickra_historical_volatility_new(
period: usize,
trading_periods: usize,
) -> *mut HistoricalVolatility {
match HistoricalVolatility::new(period, trading_periods) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_historical_volatility_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_historical_volatility_update(
handle: *mut HistoricalVolatility,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_historical_volatility_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_historical_volatility_batch(
handle: *mut HistoricalVolatility,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_historical_volatility_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_historical_volatility_reset(handle: *mut HistoricalVolatility) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_historical_volatility_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_historical_volatility_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_historical_volatility_free(handle: *mut HistoricalVolatility) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Hma` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_hma_free`.
#[no_mangle]
pub extern "C" fn wickra_hma_new(period: usize) -> *mut Hma {
match Hma::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_hma_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hma_update(handle: *mut Hma, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_hma_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_hma_batch(
handle: *mut Hma,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_hma_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hma_reset(handle: *mut Hma) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_hma_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_hma_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hma_free(handle: *mut Hma) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HoltWinters` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_holt_winters_free`.
#[no_mangle]
pub extern "C" fn wickra_holt_winters_new(alpha: f64, beta: f64) -> *mut HoltWinters {
match HoltWinters::new(alpha, beta) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_holt_winters_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_holt_winters_update(handle: *mut HoltWinters, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_holt_winters_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_holt_winters_batch(
handle: *mut HoltWinters,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_holt_winters_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_holt_winters_reset(handle: *mut HoltWinters) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_holt_winters_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_holt_winters_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_holt_winters_free(handle: *mut HoltWinters) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HtDcPhase` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ht_dc_phase_free`.
#[no_mangle]
pub extern "C" fn wickra_ht_dc_phase_new() -> *mut HtDcPhase {
Box::into_raw(Box::new(HtDcPhase::new()))
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ht_dc_phase_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ht_dc_phase_update(handle: *mut HtDcPhase, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_ht_dc_phase_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_ht_dc_phase_batch(
handle: *mut HtDcPhase,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ht_dc_phase_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ht_dc_phase_reset(handle: *mut HtDcPhase) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ht_dc_phase_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ht_dc_phase_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ht_dc_phase_free(handle: *mut HtDcPhase) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HtTrendMode` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ht_trend_mode_free`.
#[no_mangle]
pub extern "C" fn wickra_ht_trend_mode_new() -> *mut HtTrendMode {
Box::into_raw(Box::new(HtTrendMode::new()))
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ht_trend_mode_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ht_trend_mode_update(handle: *mut HtTrendMode, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_ht_trend_mode_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_ht_trend_mode_batch(
handle: *mut HtTrendMode,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ht_trend_mode_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ht_trend_mode_reset(handle: *mut HtTrendMode) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ht_trend_mode_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ht_trend_mode_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ht_trend_mode_free(handle: *mut HtTrendMode) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HurstExponent` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_hurst_exponent_free`.
#[no_mangle]
pub extern "C" fn wickra_hurst_exponent_new(period: usize, chunks: usize) -> *mut HurstExponent {
match HurstExponent::new(period, chunks) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_hurst_exponent_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hurst_exponent_update(
handle: *mut HurstExponent,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_hurst_exponent_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_hurst_exponent_batch(
handle: *mut HurstExponent,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_hurst_exponent_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hurst_exponent_reset(handle: *mut HurstExponent) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_hurst_exponent_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_hurst_exponent_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hurst_exponent_free(handle: *mut HurstExponent) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `InstantaneousTrendline` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_instantaneous_trendline_free`.
#[no_mangle]
pub extern "C" fn wickra_instantaneous_trendline_new(period: usize) -> *mut InstantaneousTrendline {
match InstantaneousTrendline::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_instantaneous_trendline_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_instantaneous_trendline_update(
handle: *mut InstantaneousTrendline,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_instantaneous_trendline_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_instantaneous_trendline_batch(
handle: *mut InstantaneousTrendline,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_instantaneous_trendline_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_instantaneous_trendline_reset(handle: *mut InstantaneousTrendline) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_instantaneous_trendline_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_instantaneous_trendline_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_instantaneous_trendline_free(handle: *mut InstantaneousTrendline) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `InverseFisherTransform` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_inverse_fisher_transform_free`.
#[no_mangle]
pub extern "C" fn wickra_inverse_fisher_transform_new(scale: f64) -> *mut InverseFisherTransform {
match InverseFisherTransform::new(scale) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_inverse_fisher_transform_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_inverse_fisher_transform_update(
handle: *mut InverseFisherTransform,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_inverse_fisher_transform_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_inverse_fisher_transform_batch(
handle: *mut InverseFisherTransform,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_inverse_fisher_transform_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_inverse_fisher_transform_reset(
handle: *mut InverseFisherTransform,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_inverse_fisher_transform_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_inverse_fisher_transform_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_inverse_fisher_transform_free(handle: *mut InverseFisherTransform) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `JarqueBera` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_jarque_bera_free`.
#[no_mangle]
pub extern "C" fn wickra_jarque_bera_new(period: usize) -> *mut JarqueBera {
match JarqueBera::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_jarque_bera_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_jarque_bera_update(handle: *mut JarqueBera, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_jarque_bera_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_jarque_bera_batch(
handle: *mut JarqueBera,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_jarque_bera_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_jarque_bera_reset(handle: *mut JarqueBera) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_jarque_bera_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_jarque_bera_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_jarque_bera_free(handle: *mut JarqueBera) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Jma` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_jma_free`.
#[no_mangle]
pub extern "C" fn wickra_jma_new(period: usize, phase: f64, power: u32) -> *mut Jma {
match Jma::new(period, phase, power) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_jma_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_jma_update(handle: *mut Jma, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_jma_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_jma_batch(
handle: *mut Jma,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_jma_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_jma_reset(handle: *mut Jma) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_jma_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_jma_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_jma_free(handle: *mut Jma) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `JumpIndicator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_jump_indicator_free`.
#[no_mangle]
pub extern "C" fn wickra_jump_indicator_new(period: usize, threshold: f64) -> *mut JumpIndicator {
match JumpIndicator::new(period, threshold) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_jump_indicator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_jump_indicator_update(
handle: *mut JumpIndicator,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_jump_indicator_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_jump_indicator_batch(
handle: *mut JumpIndicator,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_jump_indicator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_jump_indicator_reset(handle: *mut JumpIndicator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_jump_indicator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_jump_indicator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_jump_indicator_free(handle: *mut JumpIndicator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `KRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_k_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_k_ratio_new(period: usize) -> *mut KRatio {
match KRatio::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_k_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_k_ratio_update(handle: *mut KRatio, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_k_ratio_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_k_ratio_batch(
handle: *mut KRatio,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_k_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_k_ratio_reset(handle: *mut KRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_k_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_k_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_k_ratio_free(handle: *mut KRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Kama` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_kama_free`.
#[no_mangle]
pub extern "C" fn wickra_kama_new(er_period: usize, fast: usize, slow: usize) -> *mut Kama {
match Kama::new(er_period, fast, slow) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_kama_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kama_update(handle: *mut Kama, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_kama_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_kama_batch(
handle: *mut Kama,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_kama_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kama_reset(handle: *mut Kama) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_kama_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_kama_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kama_free(handle: *mut Kama) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `KellyCriterion` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_kelly_criterion_free`.
#[no_mangle]
pub extern "C" fn wickra_kelly_criterion_new(period: usize) -> *mut KellyCriterion {
match KellyCriterion::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_kelly_criterion_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kelly_criterion_update(
handle: *mut KellyCriterion,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_kelly_criterion_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_kelly_criterion_batch(
handle: *mut KellyCriterion,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_kelly_criterion_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kelly_criterion_reset(handle: *mut KellyCriterion) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_kelly_criterion_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_kelly_criterion_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kelly_criterion_free(handle: *mut KellyCriterion) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Kurtosis` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_kurtosis_free`.
#[no_mangle]
pub extern "C" fn wickra_kurtosis_new(period: usize) -> *mut Kurtosis {
match Kurtosis::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_kurtosis_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kurtosis_update(handle: *mut Kurtosis, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_kurtosis_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_kurtosis_batch(
handle: *mut Kurtosis,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_kurtosis_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kurtosis_reset(handle: *mut Kurtosis) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_kurtosis_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_kurtosis_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kurtosis_free(handle: *mut Kurtosis) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `LaguerreRsi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_laguerre_rsi_free`.
#[no_mangle]
pub extern "C" fn wickra_laguerre_rsi_new(gamma: f64) -> *mut LaguerreRsi {
match LaguerreRsi::new(gamma) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_laguerre_rsi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_laguerre_rsi_update(handle: *mut LaguerreRsi, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_laguerre_rsi_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_laguerre_rsi_batch(
handle: *mut LaguerreRsi,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_laguerre_rsi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_laguerre_rsi_reset(handle: *mut LaguerreRsi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_laguerre_rsi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_laguerre_rsi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_laguerre_rsi_free(handle: *mut LaguerreRsi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `LinearRegression` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_linear_regression_free`.
#[no_mangle]
pub extern "C" fn wickra_linear_regression_new(period: usize) -> *mut LinearRegression {
match LinearRegression::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_linear_regression_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_linear_regression_update(
handle: *mut LinearRegression,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_linear_regression_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_linear_regression_batch(
handle: *mut LinearRegression,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_linear_regression_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_linear_regression_reset(handle: *mut LinearRegression) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_linear_regression_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_linear_regression_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_linear_regression_free(handle: *mut LinearRegression) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `LinRegAngle` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_lin_reg_angle_free`.
#[no_mangle]
pub extern "C" fn wickra_lin_reg_angle_new(period: usize) -> *mut LinRegAngle {
match LinRegAngle::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_lin_reg_angle_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_angle_update(handle: *mut LinRegAngle, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_lin_reg_angle_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_angle_batch(
handle: *mut LinRegAngle,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_lin_reg_angle_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_angle_reset(handle: *mut LinRegAngle) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_lin_reg_angle_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_lin_reg_angle_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_angle_free(handle: *mut LinRegAngle) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `LinRegIntercept` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_lin_reg_intercept_free`.
#[no_mangle]
pub extern "C" fn wickra_lin_reg_intercept_new(period: usize) -> *mut LinRegIntercept {
match LinRegIntercept::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_lin_reg_intercept_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_intercept_update(
handle: *mut LinRegIntercept,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_lin_reg_intercept_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_intercept_batch(
handle: *mut LinRegIntercept,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_lin_reg_intercept_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_intercept_reset(handle: *mut LinRegIntercept) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_lin_reg_intercept_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_lin_reg_intercept_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_intercept_free(handle: *mut LinRegIntercept) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `LinRegSlope` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_lin_reg_slope_free`.
#[no_mangle]
pub extern "C" fn wickra_lin_reg_slope_new(period: usize) -> *mut LinRegSlope {
match LinRegSlope::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_lin_reg_slope_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_slope_update(handle: *mut LinRegSlope, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_lin_reg_slope_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_slope_batch(
handle: *mut LinRegSlope,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_lin_reg_slope_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_slope_reset(handle: *mut LinRegSlope) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_lin_reg_slope_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_lin_reg_slope_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_slope_free(handle: *mut LinRegSlope) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `LogReturn` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_log_return_free`.
#[no_mangle]
pub extern "C" fn wickra_log_return_new(period: usize) -> *mut LogReturn {
match LogReturn::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_log_return_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_log_return_update(handle: *mut LogReturn, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_log_return_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_log_return_batch(
handle: *mut LogReturn,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_log_return_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_log_return_reset(handle: *mut LogReturn) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_log_return_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_log_return_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_log_return_free(handle: *mut LogReturn) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `M2Measure` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_m2_measure_free`.
#[no_mangle]
pub extern "C" fn wickra_m2_measure_new(
period: usize,
risk_free: f64,
benchmark_stddev: f64,
) -> *mut M2Measure {
match M2Measure::new(period, risk_free, benchmark_stddev) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_m2_measure_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_m2_measure_update(handle: *mut M2Measure, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_m2_measure_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_m2_measure_batch(
handle: *mut M2Measure,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_m2_measure_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_m2_measure_reset(handle: *mut M2Measure) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_m2_measure_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_m2_measure_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_m2_measure_free(handle: *mut M2Measure) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MacdHistogram` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_macd_histogram_free`.
#[no_mangle]
pub extern "C" fn wickra_macd_histogram_new(
fast: usize,
slow: usize,
signal: usize,
) -> *mut MacdHistogram {
match MacdHistogram::new(fast, slow, signal) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_macd_histogram_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_macd_histogram_update(
handle: *mut MacdHistogram,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_macd_histogram_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_macd_histogram_batch(
handle: *mut MacdHistogram,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_macd_histogram_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_macd_histogram_reset(handle: *mut MacdHistogram) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_macd_histogram_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_macd_histogram_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_macd_histogram_free(handle: *mut MacdHistogram) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MartinRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_martin_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_martin_ratio_new(period: usize) -> *mut MartinRatio {
match MartinRatio::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_martin_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_martin_ratio_update(handle: *mut MartinRatio, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_martin_ratio_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_martin_ratio_batch(
handle: *mut MartinRatio,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_martin_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_martin_ratio_reset(handle: *mut MartinRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_martin_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_martin_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_martin_ratio_free(handle: *mut MartinRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MaxDrawdown` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_max_drawdown_free`.
#[no_mangle]
pub extern "C" fn wickra_max_drawdown_new(period: usize) -> *mut MaxDrawdown {
match MaxDrawdown::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_max_drawdown_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_max_drawdown_update(handle: *mut MaxDrawdown, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_max_drawdown_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_max_drawdown_batch(
handle: *mut MaxDrawdown,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_max_drawdown_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_max_drawdown_reset(handle: *mut MaxDrawdown) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_max_drawdown_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_max_drawdown_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_max_drawdown_free(handle: *mut MaxDrawdown) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `McGinleyDynamic` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_mc_ginley_dynamic_free`.
#[no_mangle]
pub extern "C" fn wickra_mc_ginley_dynamic_new(period: usize) -> *mut McGinleyDynamic {
match McGinleyDynamic::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_mc_ginley_dynamic_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mc_ginley_dynamic_update(
handle: *mut McGinleyDynamic,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_mc_ginley_dynamic_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_mc_ginley_dynamic_batch(
handle: *mut McGinleyDynamic,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_mc_ginley_dynamic_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mc_ginley_dynamic_reset(handle: *mut McGinleyDynamic) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_mc_ginley_dynamic_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_mc_ginley_dynamic_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mc_ginley_dynamic_free(handle: *mut McGinleyDynamic) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MedianAbsoluteDeviation` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_median_absolute_deviation_free`.
#[no_mangle]
pub extern "C" fn wickra_median_absolute_deviation_new(
period: usize,
) -> *mut MedianAbsoluteDeviation {
match MedianAbsoluteDeviation::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_median_absolute_deviation_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_absolute_deviation_update(
handle: *mut MedianAbsoluteDeviation,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_median_absolute_deviation_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_absolute_deviation_batch(
handle: *mut MedianAbsoluteDeviation,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_median_absolute_deviation_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_absolute_deviation_reset(
handle: *mut MedianAbsoluteDeviation,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_median_absolute_deviation_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_median_absolute_deviation_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_absolute_deviation_free(
handle: *mut MedianAbsoluteDeviation,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MedianMa` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_median_ma_free`.
#[no_mangle]
pub extern "C" fn wickra_median_ma_new(period: usize) -> *mut MedianMa {
match MedianMa::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_median_ma_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_ma_update(handle: *mut MedianMa, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_median_ma_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_ma_batch(
handle: *mut MedianMa,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_median_ma_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_ma_reset(handle: *mut MedianMa) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_median_ma_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_median_ma_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_ma_free(handle: *mut MedianMa) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MidPoint` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_mid_point_free`.
#[no_mangle]
pub extern "C" fn wickra_mid_point_new(period: usize) -> *mut MidPoint {
match MidPoint::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_mid_point_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mid_point_update(handle: *mut MidPoint, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_mid_point_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_mid_point_batch(
handle: *mut MidPoint,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_mid_point_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mid_point_reset(handle: *mut MidPoint) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_mid_point_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_mid_point_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mid_point_free(handle: *mut MidPoint) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Mom` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_mom_free`.
#[no_mangle]
pub extern "C" fn wickra_mom_new(period: usize) -> *mut Mom {
match Mom::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_mom_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mom_update(handle: *mut Mom, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_mom_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_mom_batch(
handle: *mut Mom,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_mom_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mom_reset(handle: *mut Mom) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_mom_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_mom_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mom_free(handle: *mut Mom) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OmegaRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_omega_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_omega_ratio_new(period: usize, threshold: f64) -> *mut OmegaRatio {
match OmegaRatio::new(period, threshold) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_omega_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_omega_ratio_update(handle: *mut OmegaRatio, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_omega_ratio_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_omega_ratio_batch(
handle: *mut OmegaRatio,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_omega_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_omega_ratio_reset(handle: *mut OmegaRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_omega_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_omega_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_omega_ratio_free(handle: *mut OmegaRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PainIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_pain_index_free`.
#[no_mangle]
pub extern "C" fn wickra_pain_index_new(period: usize) -> *mut PainIndex {
match PainIndex::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_pain_index_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pain_index_update(handle: *mut PainIndex, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_pain_index_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_pain_index_batch(
handle: *mut PainIndex,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_pain_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pain_index_reset(handle: *mut PainIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_pain_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_pain_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pain_index_free(handle: *mut PainIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PercentB` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_percent_b_free`.
#[no_mangle]
pub extern "C" fn wickra_percent_b_new(period: usize, multiplier: f64) -> *mut PercentB {
match PercentB::new(period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_percent_b_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_percent_b_update(handle: *mut PercentB, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_percent_b_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_percent_b_batch(
handle: *mut PercentB,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_percent_b_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_percent_b_reset(handle: *mut PercentB) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_percent_b_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_percent_b_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_percent_b_free(handle: *mut PercentB) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PercentageTrailingStop` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_percentage_trailing_stop_free`.
#[no_mangle]
pub extern "C" fn wickra_percentage_trailing_stop_new(percent: f64) -> *mut PercentageTrailingStop {
match PercentageTrailingStop::new(percent) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_percentage_trailing_stop_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_percentage_trailing_stop_update(
handle: *mut PercentageTrailingStop,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_percentage_trailing_stop_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_percentage_trailing_stop_batch(
handle: *mut PercentageTrailingStop,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_percentage_trailing_stop_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_percentage_trailing_stop_reset(
handle: *mut PercentageTrailingStop,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_percentage_trailing_stop_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_percentage_trailing_stop_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_percentage_trailing_stop_free(handle: *mut PercentageTrailingStop) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Pmo` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_pmo_free`.
#[no_mangle]
pub extern "C" fn wickra_pmo_new(smoothing1: usize, smoothing2: usize) -> *mut Pmo {
match Pmo::new(smoothing1, smoothing2) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_pmo_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pmo_update(handle: *mut Pmo, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_pmo_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_pmo_batch(
handle: *mut Pmo,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_pmo_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pmo_reset(handle: *mut Pmo) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_pmo_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_pmo_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pmo_free(handle: *mut Pmo) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PolarizedFractalEfficiency` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_polarized_fractal_efficiency_free`.
#[no_mangle]
pub extern "C" fn wickra_polarized_fractal_efficiency_new(
period: usize,
smoothing: usize,
) -> *mut PolarizedFractalEfficiency {
match PolarizedFractalEfficiency::new(period, smoothing) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_polarized_fractal_efficiency_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_polarized_fractal_efficiency_update(
handle: *mut PolarizedFractalEfficiency,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_polarized_fractal_efficiency_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_polarized_fractal_efficiency_batch(
handle: *mut PolarizedFractalEfficiency,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_polarized_fractal_efficiency_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_polarized_fractal_efficiency_reset(
handle: *mut PolarizedFractalEfficiency,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_polarized_fractal_efficiency_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_polarized_fractal_efficiency_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_polarized_fractal_efficiency_free(
handle: *mut PolarizedFractalEfficiency,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Ppo` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ppo_free`.
#[no_mangle]
pub extern "C" fn wickra_ppo_new(fast: usize, slow: usize) -> *mut Ppo {
match Ppo::new(fast, slow) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ppo_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ppo_update(handle: *mut Ppo, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_ppo_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_ppo_batch(
handle: *mut Ppo,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ppo_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ppo_reset(handle: *mut Ppo) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ppo_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ppo_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ppo_free(handle: *mut Ppo) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PpoHistogram` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ppo_histogram_free`.
#[no_mangle]
pub extern "C" fn wickra_ppo_histogram_new(
fast: usize,
slow: usize,
signal: usize,
) -> *mut PpoHistogram {
match PpoHistogram::new(fast, slow, signal) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ppo_histogram_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ppo_histogram_update(handle: *mut PpoHistogram, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_ppo_histogram_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_ppo_histogram_batch(
handle: *mut PpoHistogram,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ppo_histogram_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ppo_histogram_reset(handle: *mut PpoHistogram) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ppo_histogram_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ppo_histogram_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ppo_histogram_free(handle: *mut PpoHistogram) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ProfitFactor` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_profit_factor_free`.
#[no_mangle]
pub extern "C" fn wickra_profit_factor_new(period: usize) -> *mut ProfitFactor {
match ProfitFactor::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_profit_factor_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_profit_factor_update(handle: *mut ProfitFactor, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_profit_factor_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_profit_factor_batch(
handle: *mut ProfitFactor,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_profit_factor_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_profit_factor_reset(handle: *mut ProfitFactor) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_profit_factor_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_profit_factor_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_profit_factor_free(handle: *mut ProfitFactor) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RSquared` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_r_squared_free`.
#[no_mangle]
pub extern "C" fn wickra_r_squared_new(period: usize) -> *mut RSquared {
match RSquared::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_r_squared_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_r_squared_update(handle: *mut RSquared, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_r_squared_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_r_squared_batch(
handle: *mut RSquared,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_r_squared_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_r_squared_reset(handle: *mut RSquared) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_r_squared_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_r_squared_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_r_squared_free(handle: *mut RSquared) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RealizedVolatility` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_realized_volatility_free`.
#[no_mangle]
pub extern "C" fn wickra_realized_volatility_new(period: usize) -> *mut RealizedVolatility {
match RealizedVolatility::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_realized_volatility_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_realized_volatility_update(
handle: *mut RealizedVolatility,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_realized_volatility_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_realized_volatility_batch(
handle: *mut RealizedVolatility,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_realized_volatility_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_realized_volatility_reset(handle: *mut RealizedVolatility) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_realized_volatility_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_realized_volatility_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_realized_volatility_free(handle: *mut RealizedVolatility) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RecoveryFactor` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_recovery_factor_free`.
#[no_mangle]
pub extern "C" fn wickra_recovery_factor_new() -> *mut RecoveryFactor {
Box::into_raw(Box::new(RecoveryFactor::new()))
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_recovery_factor_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_recovery_factor_update(
handle: *mut RecoveryFactor,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_recovery_factor_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_recovery_factor_batch(
handle: *mut RecoveryFactor,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_recovery_factor_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_recovery_factor_reset(handle: *mut RecoveryFactor) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_recovery_factor_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_recovery_factor_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_recovery_factor_free(handle: *mut RecoveryFactor) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Reflex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_reflex_free`.
#[no_mangle]
pub extern "C" fn wickra_reflex_new(period: usize) -> *mut Reflex {
match Reflex::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_reflex_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_reflex_update(handle: *mut Reflex, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_reflex_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_reflex_batch(
handle: *mut Reflex,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_reflex_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_reflex_reset(handle: *mut Reflex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_reflex_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_reflex_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_reflex_free(handle: *mut Reflex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RegimeLabel` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_regime_label_free`.
#[no_mangle]
pub extern "C" fn wickra_regime_label_new(vol_period: usize, lookback: usize) -> *mut RegimeLabel {
match RegimeLabel::new(vol_period, lookback) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_regime_label_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_regime_label_update(handle: *mut RegimeLabel, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_regime_label_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_regime_label_batch(
handle: *mut RegimeLabel,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_regime_label_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_regime_label_reset(handle: *mut RegimeLabel) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_regime_label_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_regime_label_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_regime_label_free(handle: *mut RegimeLabel) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RenkoTrailingStop` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_renko_trailing_stop_free`.
#[no_mangle]
pub extern "C" fn wickra_renko_trailing_stop_new(block_size: f64) -> *mut RenkoTrailingStop {
match RenkoTrailingStop::new(block_size) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_renko_trailing_stop_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_renko_trailing_stop_update(
handle: *mut RenkoTrailingStop,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_renko_trailing_stop_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_renko_trailing_stop_batch(
handle: *mut RenkoTrailingStop,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_renko_trailing_stop_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_renko_trailing_stop_reset(handle: *mut RenkoTrailingStop) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_renko_trailing_stop_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_renko_trailing_stop_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_renko_trailing_stop_free(handle: *mut RenkoTrailingStop) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Rmi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rmi_free`.
#[no_mangle]
pub extern "C" fn wickra_rmi_new(period: usize, momentum: usize) -> *mut Rmi {
match Rmi::new(period, momentum) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rmi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rmi_update(handle: *mut Rmi, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_rmi_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_rmi_batch(
handle: *mut Rmi,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rmi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rmi_reset(handle: *mut Rmi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rmi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rmi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rmi_free(handle: *mut Rmi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Roc` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_roc_free`.
#[no_mangle]
pub extern "C" fn wickra_roc_new(period: usize) -> *mut Roc {
match Roc::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_roc_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_roc_update(handle: *mut Roc, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_roc_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_roc_batch(
handle: *mut Roc,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_roc_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_roc_reset(handle: *mut Roc) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_roc_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_roc_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_roc_free(handle: *mut Roc) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Rocp` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rocp_free`.
#[no_mangle]
pub extern "C" fn wickra_rocp_new(period: usize) -> *mut Rocp {
match Rocp::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rocp_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rocp_update(handle: *mut Rocp, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_rocp_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_rocp_batch(
handle: *mut Rocp,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rocp_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rocp_reset(handle: *mut Rocp) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rocp_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rocp_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rocp_free(handle: *mut Rocp) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Rocr` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rocr_free`.
#[no_mangle]
pub extern "C" fn wickra_rocr_new(period: usize) -> *mut Rocr {
match Rocr::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rocr_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rocr_update(handle: *mut Rocr, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_rocr_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_rocr_batch(
handle: *mut Rocr,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rocr_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rocr_reset(handle: *mut Rocr) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rocr_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rocr_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rocr_free(handle: *mut Rocr) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Rocr100` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rocr100_free`.
#[no_mangle]
pub extern "C" fn wickra_rocr100_new(period: usize) -> *mut Rocr100 {
match Rocr100::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rocr100_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rocr100_update(handle: *mut Rocr100, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_rocr100_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_rocr100_batch(
handle: *mut Rocr100,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rocr100_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rocr100_reset(handle: *mut Rocr100) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rocr100_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rocr100_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rocr100_free(handle: *mut Rocr100) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RollingIqr` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rolling_iqr_free`.
#[no_mangle]
pub extern "C" fn wickra_rolling_iqr_new(period: usize) -> *mut RollingIqr {
match RollingIqr::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rolling_iqr_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_iqr_update(handle: *mut RollingIqr, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_rolling_iqr_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_iqr_batch(
handle: *mut RollingIqr,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rolling_iqr_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_iqr_reset(handle: *mut RollingIqr) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rolling_iqr_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rolling_iqr_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_iqr_free(handle: *mut RollingIqr) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RollingMinMaxScaler` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rolling_min_max_scaler_free`.
#[no_mangle]
pub extern "C" fn wickra_rolling_min_max_scaler_new(period: usize) -> *mut RollingMinMaxScaler {
match RollingMinMaxScaler::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rolling_min_max_scaler_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_min_max_scaler_update(
handle: *mut RollingMinMaxScaler,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_rolling_min_max_scaler_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_min_max_scaler_batch(
handle: *mut RollingMinMaxScaler,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rolling_min_max_scaler_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_min_max_scaler_reset(handle: *mut RollingMinMaxScaler) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rolling_min_max_scaler_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rolling_min_max_scaler_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_min_max_scaler_free(handle: *mut RollingMinMaxScaler) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RollingPercentileRank` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rolling_percentile_rank_free`.
#[no_mangle]
pub extern "C" fn wickra_rolling_percentile_rank_new(period: usize) -> *mut RollingPercentileRank {
match RollingPercentileRank::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rolling_percentile_rank_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_percentile_rank_update(
handle: *mut RollingPercentileRank,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_rolling_percentile_rank_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_percentile_rank_batch(
handle: *mut RollingPercentileRank,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rolling_percentile_rank_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_percentile_rank_reset(handle: *mut RollingPercentileRank) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rolling_percentile_rank_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rolling_percentile_rank_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_percentile_rank_free(handle: *mut RollingPercentileRank) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RollingQuantile` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rolling_quantile_free`.
#[no_mangle]
pub extern "C" fn wickra_rolling_quantile_new(
period: usize,
quantile: f64,
) -> *mut RollingQuantile {
match RollingQuantile::new(period, quantile) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rolling_quantile_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_quantile_update(
handle: *mut RollingQuantile,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_rolling_quantile_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_quantile_batch(
handle: *mut RollingQuantile,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rolling_quantile_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_quantile_reset(handle: *mut RollingQuantile) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rolling_quantile_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rolling_quantile_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_quantile_free(handle: *mut RollingQuantile) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RoofingFilter` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_roofing_filter_free`.
#[no_mangle]
pub extern "C" fn wickra_roofing_filter_new(
lp_period: usize,
hp_period: usize,
) -> *mut RoofingFilter {
match RoofingFilter::new(lp_period, hp_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_roofing_filter_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_roofing_filter_update(
handle: *mut RoofingFilter,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_roofing_filter_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_roofing_filter_batch(
handle: *mut RoofingFilter,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_roofing_filter_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_roofing_filter_reset(handle: *mut RoofingFilter) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_roofing_filter_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_roofing_filter_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_roofing_filter_free(handle: *mut RoofingFilter) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Rsi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rsi_free`.
#[no_mangle]
pub extern "C" fn wickra_rsi_new(period: usize) -> *mut Rsi {
match Rsi::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rsi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rsi_update(handle: *mut Rsi, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_rsi_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_rsi_batch(
handle: *mut Rsi,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rsi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rsi_reset(handle: *mut Rsi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rsi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rsi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rsi_free(handle: *mut Rsi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Rsx` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rsx_free`.
#[no_mangle]
pub extern "C" fn wickra_rsx_new(length: usize) -> *mut Rsx {
match Rsx::new(length) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rsx_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rsx_update(handle: *mut Rsx, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_rsx_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_rsx_batch(
handle: *mut Rsx,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rsx_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rsx_reset(handle: *mut Rsx) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rsx_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rsx_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rsx_free(handle: *mut Rsx) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RviVolatility` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rvi_volatility_free`.
#[no_mangle]
pub extern "C" fn wickra_rvi_volatility_new(period: usize) -> *mut RviVolatility {
match RviVolatility::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rvi_volatility_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rvi_volatility_update(
handle: *mut RviVolatility,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_rvi_volatility_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_rvi_volatility_batch(
handle: *mut RviVolatility,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rvi_volatility_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rvi_volatility_reset(handle: *mut RviVolatility) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rvi_volatility_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rvi_volatility_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rvi_volatility_free(handle: *mut RviVolatility) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SampleEntropy` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_sample_entropy_free`.
#[no_mangle]
pub extern "C" fn wickra_sample_entropy_new(
period: usize,
m: usize,
r_factor: f64,
) -> *mut SampleEntropy {
match SampleEntropy::new(period, m, r_factor) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_sample_entropy_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sample_entropy_update(
handle: *mut SampleEntropy,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_sample_entropy_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_sample_entropy_batch(
handle: *mut SampleEntropy,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_sample_entropy_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sample_entropy_reset(handle: *mut SampleEntropy) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_sample_entropy_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_sample_entropy_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sample_entropy_free(handle: *mut SampleEntropy) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ShannonEntropy` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_shannon_entropy_free`.
#[no_mangle]
pub extern "C" fn wickra_shannon_entropy_new(period: usize, bins: usize) -> *mut ShannonEntropy {
match ShannonEntropy::new(period, bins) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_shannon_entropy_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_shannon_entropy_update(
handle: *mut ShannonEntropy,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_shannon_entropy_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_shannon_entropy_batch(
handle: *mut ShannonEntropy,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_shannon_entropy_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_shannon_entropy_reset(handle: *mut ShannonEntropy) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_shannon_entropy_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_shannon_entropy_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_shannon_entropy_free(handle: *mut ShannonEntropy) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SharpeRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_sharpe_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_sharpe_ratio_new(period: usize, risk_free: f64) -> *mut SharpeRatio {
match SharpeRatio::new(period, risk_free) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_sharpe_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sharpe_ratio_update(handle: *mut SharpeRatio, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_sharpe_ratio_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_sharpe_ratio_batch(
handle: *mut SharpeRatio,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_sharpe_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sharpe_ratio_reset(handle: *mut SharpeRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_sharpe_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_sharpe_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sharpe_ratio_free(handle: *mut SharpeRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SineWave` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_sine_wave_free`.
#[no_mangle]
pub extern "C" fn wickra_sine_wave_new() -> *mut SineWave {
Box::into_raw(Box::new(SineWave::new()))
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_sine_wave_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sine_wave_update(handle: *mut SineWave, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_sine_wave_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_sine_wave_batch(
handle: *mut SineWave,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_sine_wave_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sine_wave_reset(handle: *mut SineWave) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_sine_wave_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_sine_wave_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sine_wave_free(handle: *mut SineWave) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SineWeightedMa` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_sine_weighted_ma_free`.
#[no_mangle]
pub extern "C" fn wickra_sine_weighted_ma_new(period: usize) -> *mut SineWeightedMa {
match SineWeightedMa::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_sine_weighted_ma_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sine_weighted_ma_update(
handle: *mut SineWeightedMa,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_sine_weighted_ma_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_sine_weighted_ma_batch(
handle: *mut SineWeightedMa,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_sine_weighted_ma_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sine_weighted_ma_reset(handle: *mut SineWeightedMa) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_sine_weighted_ma_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_sine_weighted_ma_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sine_weighted_ma_free(handle: *mut SineWeightedMa) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Skewness` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_skewness_free`.
#[no_mangle]
pub extern "C" fn wickra_skewness_new(period: usize) -> *mut Skewness {
match Skewness::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_skewness_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_skewness_update(handle: *mut Skewness, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_skewness_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_skewness_batch(
handle: *mut Skewness,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_skewness_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_skewness_reset(handle: *mut Skewness) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_skewness_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_skewness_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_skewness_free(handle: *mut Skewness) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Sma` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_sma_free`.
#[no_mangle]
pub extern "C" fn wickra_sma_new(period: usize) -> *mut Sma {
match Sma::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_sma_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sma_update(handle: *mut Sma, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_sma_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_sma_batch(
handle: *mut Sma,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_sma_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sma_reset(handle: *mut Sma) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_sma_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_sma_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sma_free(handle: *mut Sma) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Smma` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_smma_free`.
#[no_mangle]
pub extern "C" fn wickra_smma_new(period: usize) -> *mut Smma {
match Smma::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_smma_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_smma_update(handle: *mut Smma, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_smma_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_smma_batch(
handle: *mut Smma,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_smma_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_smma_reset(handle: *mut Smma) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_smma_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_smma_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_smma_free(handle: *mut Smma) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SortinoRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_sortino_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_sortino_ratio_new(period: usize, mar: f64) -> *mut SortinoRatio {
match SortinoRatio::new(period, mar) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_sortino_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sortino_ratio_update(handle: *mut SortinoRatio, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_sortino_ratio_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_sortino_ratio_batch(
handle: *mut SortinoRatio,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_sortino_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sortino_ratio_reset(handle: *mut SortinoRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_sortino_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_sortino_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sortino_ratio_free(handle: *mut SortinoRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `StandardError` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_standard_error_free`.
#[no_mangle]
pub extern "C" fn wickra_standard_error_new(period: usize) -> *mut StandardError {
match StandardError::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_standard_error_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_standard_error_update(
handle: *mut StandardError,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_standard_error_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_standard_error_batch(
handle: *mut StandardError,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_standard_error_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_standard_error_reset(handle: *mut StandardError) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_standard_error_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_standard_error_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_standard_error_free(handle: *mut StandardError) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Stc` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_stc_free`.
#[no_mangle]
pub extern "C" fn wickra_stc_new(
fast: usize,
slow: usize,
schaff_period: usize,
factor: f64,
) -> *mut Stc {
match Stc::new(fast, slow, schaff_period, factor) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_stc_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stc_update(handle: *mut Stc, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_stc_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_stc_batch(
handle: *mut Stc,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_stc_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stc_reset(handle: *mut Stc) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_stc_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_stc_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stc_free(handle: *mut Stc) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `StdDev` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_std_dev_free`.
#[no_mangle]
pub extern "C" fn wickra_std_dev_new(period: usize) -> *mut StdDev {
match StdDev::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_std_dev_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_std_dev_update(handle: *mut StdDev, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_std_dev_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_std_dev_batch(
handle: *mut StdDev,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_std_dev_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_std_dev_reset(handle: *mut StdDev) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_std_dev_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_std_dev_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_std_dev_free(handle: *mut StdDev) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `StepTrailingStop` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_step_trailing_stop_free`.
#[no_mangle]
pub extern "C" fn wickra_step_trailing_stop_new(step_size: f64) -> *mut StepTrailingStop {
match StepTrailingStop::new(step_size) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_step_trailing_stop_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_step_trailing_stop_update(
handle: *mut StepTrailingStop,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_step_trailing_stop_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_step_trailing_stop_batch(
handle: *mut StepTrailingStop,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_step_trailing_stop_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_step_trailing_stop_reset(handle: *mut StepTrailingStop) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_step_trailing_stop_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_step_trailing_stop_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_step_trailing_stop_free(handle: *mut StepTrailingStop) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SterlingRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_sterling_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_sterling_ratio_new(period: usize) -> *mut SterlingRatio {
match SterlingRatio::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_sterling_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sterling_ratio_update(
handle: *mut SterlingRatio,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_sterling_ratio_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_sterling_ratio_batch(
handle: *mut SterlingRatio,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_sterling_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sterling_ratio_reset(handle: *mut SterlingRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_sterling_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_sterling_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sterling_ratio_free(handle: *mut SterlingRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `StochRsi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_stoch_rsi_free`.
#[no_mangle]
pub extern "C" fn wickra_stoch_rsi_new(rsi_period: usize, stoch_period: usize) -> *mut StochRsi {
match StochRsi::new(rsi_period, stoch_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_stoch_rsi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stoch_rsi_update(handle: *mut StochRsi, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_stoch_rsi_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_stoch_rsi_batch(
handle: *mut StochRsi,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_stoch_rsi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stoch_rsi_reset(handle: *mut StochRsi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_stoch_rsi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_stoch_rsi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stoch_rsi_free(handle: *mut StochRsi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SuperSmoother` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_super_smoother_free`.
#[no_mangle]
pub extern "C" fn wickra_super_smoother_new(period: usize) -> *mut SuperSmoother {
match SuperSmoother::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_super_smoother_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_super_smoother_update(
handle: *mut SuperSmoother,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_super_smoother_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_super_smoother_batch(
handle: *mut SuperSmoother,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_super_smoother_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_super_smoother_reset(handle: *mut SuperSmoother) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_super_smoother_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_super_smoother_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_super_smoother_free(handle: *mut SuperSmoother) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `T3` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_t3_free`.
#[no_mangle]
pub extern "C" fn wickra_t3_new(period: usize, v: f64) -> *mut T3 {
match T3::new(period, v) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_t3_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_t3_update(handle: *mut T3, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_t3_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_t3_batch(
handle: *mut T3,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_t3_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_t3_reset(handle: *mut T3) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_t3_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_t3_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_t3_free(handle: *mut T3) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TailRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_tail_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_tail_ratio_new(period: usize) -> *mut TailRatio {
match TailRatio::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_tail_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tail_ratio_update(handle: *mut TailRatio, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_tail_ratio_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_tail_ratio_batch(
handle: *mut TailRatio,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_tail_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tail_ratio_reset(handle: *mut TailRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_tail_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_tail_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tail_ratio_free(handle: *mut TailRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Tema` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_tema_free`.
#[no_mangle]
pub extern "C" fn wickra_tema_new(period: usize) -> *mut Tema {
match Tema::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_tema_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tema_update(handle: *mut Tema, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_tema_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_tema_batch(
handle: *mut Tema,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_tema_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tema_reset(handle: *mut Tema) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_tema_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_tema_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tema_free(handle: *mut Tema) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Tii` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_tii_free`.
#[no_mangle]
pub extern "C" fn wickra_tii_new(sma_period: usize, dev_period: usize) -> *mut Tii {
match Tii::new(sma_period, dev_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_tii_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tii_update(handle: *mut Tii, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_tii_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_tii_batch(
handle: *mut Tii,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_tii_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tii_reset(handle: *mut Tii) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_tii_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_tii_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tii_free(handle: *mut Tii) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TrendLabel` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_trend_label_free`.
#[no_mangle]
pub extern "C" fn wickra_trend_label_new(period: usize) -> *mut TrendLabel {
match TrendLabel::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_trend_label_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trend_label_update(handle: *mut TrendLabel, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_trend_label_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_trend_label_batch(
handle: *mut TrendLabel,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_trend_label_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trend_label_reset(handle: *mut TrendLabel) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_trend_label_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_trend_label_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trend_label_free(handle: *mut TrendLabel) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TrendStrengthIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_trend_strength_index_free`.
#[no_mangle]
pub extern "C" fn wickra_trend_strength_index_new(period: usize) -> *mut TrendStrengthIndex {
match TrendStrengthIndex::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_trend_strength_index_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trend_strength_index_update(
handle: *mut TrendStrengthIndex,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_trend_strength_index_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_trend_strength_index_batch(
handle: *mut TrendStrengthIndex,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_trend_strength_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trend_strength_index_reset(handle: *mut TrendStrengthIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_trend_strength_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_trend_strength_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trend_strength_index_free(handle: *mut TrendStrengthIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Trendflex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_trendflex_free`.
#[no_mangle]
pub extern "C" fn wickra_trendflex_new(period: usize) -> *mut Trendflex {
match Trendflex::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_trendflex_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trendflex_update(handle: *mut Trendflex, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_trendflex_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_trendflex_batch(
handle: *mut Trendflex,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_trendflex_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trendflex_reset(handle: *mut Trendflex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_trendflex_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_trendflex_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trendflex_free(handle: *mut Trendflex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Trima` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_trima_free`.
#[no_mangle]
pub extern "C" fn wickra_trima_new(period: usize) -> *mut Trima {
match Trima::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_trima_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trima_update(handle: *mut Trima, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_trima_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_trima_batch(
handle: *mut Trima,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_trima_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trima_reset(handle: *mut Trima) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_trima_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_trima_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trima_free(handle: *mut Trima) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Trix` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_trix_free`.
#[no_mangle]
pub extern "C" fn wickra_trix_new(period: usize) -> *mut Trix {
match Trix::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_trix_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trix_update(handle: *mut Trix, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_trix_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_trix_batch(
handle: *mut Trix,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_trix_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trix_reset(handle: *mut Trix) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_trix_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_trix_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trix_free(handle: *mut Trix) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Tsf` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_tsf_free`.
#[no_mangle]
pub extern "C" fn wickra_tsf_new(period: usize) -> *mut Tsf {
match Tsf::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_tsf_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsf_update(handle: *mut Tsf, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_tsf_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsf_batch(
handle: *mut Tsf,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_tsf_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsf_reset(handle: *mut Tsf) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_tsf_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_tsf_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsf_free(handle: *mut Tsf) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TsfOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_tsf_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_tsf_oscillator_new(period: usize) -> *mut TsfOscillator {
match TsfOscillator::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_tsf_oscillator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsf_oscillator_update(
handle: *mut TsfOscillator,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_tsf_oscillator_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsf_oscillator_batch(
handle: *mut TsfOscillator,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_tsf_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsf_oscillator_reset(handle: *mut TsfOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_tsf_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_tsf_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsf_oscillator_free(handle: *mut TsfOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Tsi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_tsi_free`.
#[no_mangle]
pub extern "C" fn wickra_tsi_new(long: usize, short: usize) -> *mut Tsi {
match Tsi::new(long, short) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_tsi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsi_update(handle: *mut Tsi, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_tsi_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsi_batch(
handle: *mut Tsi,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_tsi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsi_reset(handle: *mut Tsi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_tsi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_tsi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsi_free(handle: *mut Tsi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `UlcerIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ulcer_index_free`.
#[no_mangle]
pub extern "C" fn wickra_ulcer_index_new(period: usize) -> *mut UlcerIndex {
match UlcerIndex::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ulcer_index_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ulcer_index_update(handle: *mut UlcerIndex, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_ulcer_index_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_ulcer_index_batch(
handle: *mut UlcerIndex,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ulcer_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ulcer_index_reset(handle: *mut UlcerIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ulcer_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ulcer_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ulcer_index_free(handle: *mut UlcerIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `UniversalOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_universal_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_universal_oscillator_new(period: usize) -> *mut UniversalOscillator {
match UniversalOscillator::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_universal_oscillator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_universal_oscillator_update(
handle: *mut UniversalOscillator,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_universal_oscillator_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_universal_oscillator_batch(
handle: *mut UniversalOscillator,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_universal_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_universal_oscillator_reset(handle: *mut UniversalOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_universal_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_universal_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_universal_oscillator_free(handle: *mut UniversalOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `UpsidePotentialRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_upside_potential_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_upside_potential_ratio_new(
period: usize,
mar: f64,
) -> *mut UpsidePotentialRatio {
match UpsidePotentialRatio::new(period, mar) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_upside_potential_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_upside_potential_ratio_update(
handle: *mut UpsidePotentialRatio,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_upside_potential_ratio_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_upside_potential_ratio_batch(
handle: *mut UpsidePotentialRatio,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_upside_potential_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_upside_potential_ratio_reset(handle: *mut UpsidePotentialRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_upside_potential_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_upside_potential_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_upside_potential_ratio_free(handle: *mut UpsidePotentialRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ValueAtRisk` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_value_at_risk_free`.
#[no_mangle]
pub extern "C" fn wickra_value_at_risk_new(period: usize, confidence: f64) -> *mut ValueAtRisk {
match ValueAtRisk::new(period, confidence) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_value_at_risk_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_value_at_risk_update(handle: *mut ValueAtRisk, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_value_at_risk_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_value_at_risk_batch(
handle: *mut ValueAtRisk,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_value_at_risk_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_value_at_risk_reset(handle: *mut ValueAtRisk) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_value_at_risk_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_value_at_risk_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_value_at_risk_free(handle: *mut ValueAtRisk) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Variance` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_variance_free`.
#[no_mangle]
pub extern "C" fn wickra_variance_new(period: usize) -> *mut Variance {
match Variance::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_variance_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_variance_update(handle: *mut Variance, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_variance_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_variance_batch(
handle: *mut Variance,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_variance_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_variance_reset(handle: *mut Variance) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_variance_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_variance_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_variance_free(handle: *mut Variance) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VerticalHorizontalFilter` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_vertical_horizontal_filter_free`.
#[no_mangle]
pub extern "C" fn wickra_vertical_horizontal_filter_new(
period: usize,
) -> *mut VerticalHorizontalFilter {
match VerticalHorizontalFilter::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_vertical_horizontal_filter_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vertical_horizontal_filter_update(
handle: *mut VerticalHorizontalFilter,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_vertical_horizontal_filter_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_vertical_horizontal_filter_batch(
handle: *mut VerticalHorizontalFilter,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_vertical_horizontal_filter_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vertical_horizontal_filter_reset(
handle: *mut VerticalHorizontalFilter,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_vertical_horizontal_filter_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_vertical_horizontal_filter_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vertical_horizontal_filter_free(
handle: *mut VerticalHorizontalFilter,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Vidya` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_vidya_free`.
#[no_mangle]
pub extern "C" fn wickra_vidya_new(period: usize, cmo_period: usize) -> *mut Vidya {
match Vidya::new(period, cmo_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_vidya_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vidya_update(handle: *mut Vidya, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_vidya_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_vidya_batch(
handle: *mut Vidya,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_vidya_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vidya_reset(handle: *mut Vidya) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_vidya_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_vidya_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vidya_free(handle: *mut Vidya) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VolatilityOfVolatility` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_volatility_of_volatility_free`.
#[no_mangle]
pub extern "C" fn wickra_volatility_of_volatility_new(
vol_window: usize,
vov_window: usize,
) -> *mut VolatilityOfVolatility {
match VolatilityOfVolatility::new(vol_window, vov_window) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_volatility_of_volatility_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volatility_of_volatility_update(
handle: *mut VolatilityOfVolatility,
value: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_volatility_of_volatility_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_volatility_of_volatility_batch(
handle: *mut VolatilityOfVolatility,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_volatility_of_volatility_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volatility_of_volatility_reset(
handle: *mut VolatilityOfVolatility,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_volatility_of_volatility_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_volatility_of_volatility_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volatility_of_volatility_free(handle: *mut VolatilityOfVolatility) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `WavePm` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_wave_pm_free`.
#[no_mangle]
pub extern "C" fn wickra_wave_pm_new(length: usize, smoothing: usize) -> *mut WavePm {
match WavePm::new(length, smoothing) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_wave_pm_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wave_pm_update(handle: *mut WavePm, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_wave_pm_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_wave_pm_batch(
handle: *mut WavePm,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_wave_pm_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wave_pm_reset(handle: *mut WavePm) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_wave_pm_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_wave_pm_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wave_pm_free(handle: *mut WavePm) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `WinRate` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_win_rate_free`.
#[no_mangle]
pub extern "C" fn wickra_win_rate_new(period: usize) -> *mut WinRate {
match WinRate::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_win_rate_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_win_rate_update(handle: *mut WinRate, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_win_rate_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_win_rate_batch(
handle: *mut WinRate,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_win_rate_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_win_rate_reset(handle: *mut WinRate) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_win_rate_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_win_rate_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_win_rate_free(handle: *mut WinRate) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Wma` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_wma_free`.
#[no_mangle]
pub extern "C" fn wickra_wma_new(period: usize) -> *mut Wma {
match Wma::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_wma_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wma_update(handle: *mut Wma, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_wma_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_wma_batch(
handle: *mut Wma,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_wma_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wma_reset(handle: *mut Wma) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_wma_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_wma_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wma_free(handle: *mut Wma) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ZScore` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_z_score_free`.
#[no_mangle]
pub extern "C" fn wickra_z_score_new(period: usize) -> *mut ZScore {
match ZScore::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_z_score_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_z_score_update(handle: *mut ZScore, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_z_score_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_z_score_batch(
handle: *mut ZScore,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_z_score_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_z_score_reset(handle: *mut ZScore) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_z_score_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_z_score_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_z_score_free(handle: *mut ZScore) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Zlema` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_zlema_free`.
#[no_mangle]
pub extern "C" fn wickra_zlema_new(period: usize) -> *mut Zlema {
match Zlema::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_zlema_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_zlema_update(handle: *mut Zlema, value: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update(value).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over `input[0..n]`, writing one output per input into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_zlema_new`, not freed); `input`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_zlema_batch(
handle: *mut Zlema,
input: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || input.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let inputs = slice::from_raw_parts(input, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (slot, &value) in outputs.iter_mut().zip(inputs) {
*slot = ind.update(value).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_zlema_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_zlema_reset(handle: *mut Zlema) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_zlema_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_zlema_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_zlema_free(handle: *mut Zlema) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
// ===== Pairwise indicators ((f64, f64) -> f64) =====
/// Create a `Alpha` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_alpha_free`.
#[no_mangle]
pub extern "C" fn wickra_alpha_new(period: usize, risk_free: f64) -> *mut Alpha {
match Alpha::new(period, risk_free) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_alpha_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_alpha_update(handle: *mut Alpha, x: f64, y: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_alpha_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_alpha_batch(
handle: *mut Alpha,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_alpha_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_alpha_reset(handle: *mut Alpha) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_alpha_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_alpha_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_alpha_free(handle: *mut Alpha) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Beta` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_beta_free`.
#[no_mangle]
pub extern "C" fn wickra_beta_new(period: usize) -> *mut Beta {
match Beta::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_beta_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_beta_update(handle: *mut Beta, x: f64, y: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_beta_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_beta_batch(
handle: *mut Beta,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_beta_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_beta_reset(handle: *mut Beta) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_beta_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_beta_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_beta_free(handle: *mut Beta) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `BetaNeutralSpread` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_beta_neutral_spread_free`.
#[no_mangle]
pub extern "C" fn wickra_beta_neutral_spread_new(period: usize) -> *mut BetaNeutralSpread {
match BetaNeutralSpread::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_beta_neutral_spread_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_beta_neutral_spread_update(
handle: *mut BetaNeutralSpread,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_beta_neutral_spread_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_beta_neutral_spread_batch(
handle: *mut BetaNeutralSpread,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_beta_neutral_spread_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_beta_neutral_spread_reset(handle: *mut BetaNeutralSpread) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_beta_neutral_spread_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_beta_neutral_spread_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_beta_neutral_spread_free(handle: *mut BetaNeutralSpread) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DistanceSsd` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_distance_ssd_free`.
#[no_mangle]
pub extern "C" fn wickra_distance_ssd_new(period: usize) -> *mut DistanceSsd {
match DistanceSsd::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_distance_ssd_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_distance_ssd_update(
handle: *mut DistanceSsd,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_distance_ssd_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_distance_ssd_batch(
handle: *mut DistanceSsd,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_distance_ssd_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_distance_ssd_reset(handle: *mut DistanceSsd) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_distance_ssd_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_distance_ssd_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_distance_ssd_free(handle: *mut DistanceSsd) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `GrangerCausality` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_granger_causality_free`.
#[no_mangle]
pub extern "C" fn wickra_granger_causality_new(period: usize, lag: usize) -> *mut GrangerCausality {
match GrangerCausality::new(period, lag) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_granger_causality_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_granger_causality_update(
handle: *mut GrangerCausality,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_granger_causality_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_granger_causality_batch(
handle: *mut GrangerCausality,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_granger_causality_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_granger_causality_reset(handle: *mut GrangerCausality) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_granger_causality_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_granger_causality_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_granger_causality_free(handle: *mut GrangerCausality) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HasbrouckInformationShare` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_hasbrouck_information_share_free`.
#[no_mangle]
pub extern "C" fn wickra_hasbrouck_information_share_new(
period: usize,
) -> *mut HasbrouckInformationShare {
match HasbrouckInformationShare::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_hasbrouck_information_share_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hasbrouck_information_share_update(
handle: *mut HasbrouckInformationShare,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_hasbrouck_information_share_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_hasbrouck_information_share_batch(
handle: *mut HasbrouckInformationShare,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_hasbrouck_information_share_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hasbrouck_information_share_reset(
handle: *mut HasbrouckInformationShare,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_hasbrouck_information_share_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_hasbrouck_information_share_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hasbrouck_information_share_free(
handle: *mut HasbrouckInformationShare,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `InformationRatio` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_information_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_information_ratio_new(period: usize) -> *mut InformationRatio {
match InformationRatio::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_information_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_information_ratio_update(
handle: *mut InformationRatio,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_information_ratio_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_information_ratio_batch(
handle: *mut InformationRatio,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_information_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_information_ratio_reset(handle: *mut InformationRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_information_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_information_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_information_ratio_free(handle: *mut InformationRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `KendallTau` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_kendall_tau_free`.
#[no_mangle]
pub extern "C" fn wickra_kendall_tau_new(period: usize) -> *mut KendallTau {
match KendallTau::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_kendall_tau_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kendall_tau_update(handle: *mut KendallTau, x: f64, y: f64) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_kendall_tau_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_kendall_tau_batch(
handle: *mut KendallTau,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_kendall_tau_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kendall_tau_reset(handle: *mut KendallTau) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_kendall_tau_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_kendall_tau_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kendall_tau_free(handle: *mut KendallTau) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OuHalfLife` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ou_half_life_free`.
#[no_mangle]
pub extern "C" fn wickra_ou_half_life_new(period: usize) -> *mut OuHalfLife {
match OuHalfLife::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ou_half_life_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ou_half_life_update(
handle: *mut OuHalfLife,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_ou_half_life_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_ou_half_life_batch(
handle: *mut OuHalfLife,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ou_half_life_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ou_half_life_reset(handle: *mut OuHalfLife) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ou_half_life_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ou_half_life_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ou_half_life_free(handle: *mut OuHalfLife) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PairSpreadZScore` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_pair_spread_z_score_free`.
#[no_mangle]
pub extern "C" fn wickra_pair_spread_z_score_new(
beta_period: usize,
z_period: usize,
) -> *mut PairSpreadZScore {
match PairSpreadZScore::new(beta_period, z_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_pair_spread_z_score_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pair_spread_z_score_update(
handle: *mut PairSpreadZScore,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_pair_spread_z_score_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_pair_spread_z_score_batch(
handle: *mut PairSpreadZScore,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_pair_spread_z_score_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pair_spread_z_score_reset(handle: *mut PairSpreadZScore) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_pair_spread_z_score_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_pair_spread_z_score_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pair_spread_z_score_free(handle: *mut PairSpreadZScore) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PairwiseBeta` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_pairwise_beta_free`.
#[no_mangle]
pub extern "C" fn wickra_pairwise_beta_new(period: usize) -> *mut PairwiseBeta {
match PairwiseBeta::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_pairwise_beta_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pairwise_beta_update(
handle: *mut PairwiseBeta,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_pairwise_beta_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_pairwise_beta_batch(
handle: *mut PairwiseBeta,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_pairwise_beta_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pairwise_beta_reset(handle: *mut PairwiseBeta) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_pairwise_beta_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_pairwise_beta_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pairwise_beta_free(handle: *mut PairwiseBeta) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PearsonCorrelation` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_pearson_correlation_free`.
#[no_mangle]
pub extern "C" fn wickra_pearson_correlation_new(period: usize) -> *mut PearsonCorrelation {
match PearsonCorrelation::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_pearson_correlation_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pearson_correlation_update(
handle: *mut PearsonCorrelation,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_pearson_correlation_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_pearson_correlation_batch(
handle: *mut PearsonCorrelation,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_pearson_correlation_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pearson_correlation_reset(handle: *mut PearsonCorrelation) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_pearson_correlation_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_pearson_correlation_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pearson_correlation_free(handle: *mut PearsonCorrelation) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RollingCorrelation` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rolling_correlation_free`.
#[no_mangle]
pub extern "C" fn wickra_rolling_correlation_new(period: usize) -> *mut RollingCorrelation {
match RollingCorrelation::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rolling_correlation_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_correlation_update(
handle: *mut RollingCorrelation,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_rolling_correlation_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_correlation_batch(
handle: *mut RollingCorrelation,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rolling_correlation_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_correlation_reset(handle: *mut RollingCorrelation) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rolling_correlation_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rolling_correlation_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_correlation_free(handle: *mut RollingCorrelation) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RollingCovariance` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rolling_covariance_free`.
#[no_mangle]
pub extern "C" fn wickra_rolling_covariance_new(period: usize) -> *mut RollingCovariance {
match RollingCovariance::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rolling_covariance_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_covariance_update(
handle: *mut RollingCovariance,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_rolling_covariance_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_covariance_batch(
handle: *mut RollingCovariance,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rolling_covariance_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_covariance_reset(handle: *mut RollingCovariance) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rolling_covariance_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rolling_covariance_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_covariance_free(handle: *mut RollingCovariance) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SpearmanCorrelation` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_spearman_correlation_free`.
#[no_mangle]
pub extern "C" fn wickra_spearman_correlation_new(period: usize) -> *mut SpearmanCorrelation {
match SpearmanCorrelation::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_spearman_correlation_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spearman_correlation_update(
handle: *mut SpearmanCorrelation,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_spearman_correlation_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_spearman_correlation_batch(
handle: *mut SpearmanCorrelation,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_spearman_correlation_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spearman_correlation_reset(handle: *mut SpearmanCorrelation) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_spearman_correlation_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_spearman_correlation_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spearman_correlation_free(handle: *mut SpearmanCorrelation) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SpreadAr1Coefficient` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_spread_ar1_coefficient_free`.
#[no_mangle]
pub extern "C" fn wickra_spread_ar1_coefficient_new(period: usize) -> *mut SpreadAr1Coefficient {
match SpreadAr1Coefficient::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_spread_ar1_coefficient_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spread_ar1_coefficient_update(
handle: *mut SpreadAr1Coefficient,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_spread_ar1_coefficient_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_spread_ar1_coefficient_batch(
handle: *mut SpreadAr1Coefficient,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_spread_ar1_coefficient_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spread_ar1_coefficient_reset(handle: *mut SpreadAr1Coefficient) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_spread_ar1_coefficient_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_spread_ar1_coefficient_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spread_ar1_coefficient_free(handle: *mut SpreadAr1Coefficient) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SpreadHurst` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_spread_hurst_free`.
#[no_mangle]
pub extern "C" fn wickra_spread_hurst_new(period: usize) -> *mut SpreadHurst {
match SpreadHurst::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_spread_hurst_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spread_hurst_update(
handle: *mut SpreadHurst,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_spread_hurst_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_spread_hurst_batch(
handle: *mut SpreadHurst,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_spread_hurst_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spread_hurst_reset(handle: *mut SpreadHurst) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_spread_hurst_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_spread_hurst_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spread_hurst_free(handle: *mut SpreadHurst) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TreynorRatio` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_treynor_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_treynor_ratio_new(period: usize, risk_free: f64) -> *mut TreynorRatio {
match TreynorRatio::new(period, risk_free) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_treynor_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_treynor_ratio_update(
handle: *mut TreynorRatio,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_treynor_ratio_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_treynor_ratio_batch(
handle: *mut TreynorRatio,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_treynor_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_treynor_ratio_reset(handle: *mut TreynorRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_treynor_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_treynor_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_treynor_ratio_free(handle: *mut TreynorRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VarianceRatio` pairwise indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_variance_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_variance_ratio_new(period: usize, q: usize) -> *mut VarianceRatio {
match VarianceRatio::new(period, q) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one `(x, y)` pair; returns the output, or `NaN` during warmup / on a `NULL` handle.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_variance_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_variance_ratio_update(
handle: *mut VarianceRatio,
x: f64,
y: f64,
) -> f64 {
match handle.as_mut() {
Some(ind) => ind.update((x, y)).unwrap_or(f64::NAN),
None => f64::NAN,
}
}
/// Run over the paired series `x[0..n]` / `y[0..n]` into `out[0..n]` (`NaN` at warmup).
///
/// # Safety
/// `handle` valid (from `wickra_variance_ratio_new`, not freed); `x`/`y`/`out` cover `n` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_variance_ratio_batch(
handle: *mut VarianceRatio,
x: *const f64,
y: *const f64,
out: *mut f64,
n: usize,
) {
if handle.is_null() || x.is_null() || y.is_null() || out.is_null() {
return;
}
let ind = &mut *handle;
let xs = slice::from_raw_parts(x, n);
let ys = slice::from_raw_parts(y, n);
let outputs = slice::from_raw_parts_mut(out, n);
for ((slot, &xv), &yv) in outputs.iter_mut().zip(xs).zip(ys) {
*slot = ind.update((xv, yv)).unwrap_or(f64::NAN);
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_variance_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_variance_ratio_reset(handle: *mut VarianceRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_variance_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_variance_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_variance_ratio_free(handle: *mut VarianceRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
// ===== Candle indicators (OHLCV -> f64; includes candlestick patterns) =====
/// Create a `AbandonedBaby` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_abandoned_baby_free`.
#[no_mangle]
pub extern "C" fn wickra_abandoned_baby_new() -> *mut AbandonedBaby {
Box::into_raw(Box::new(AbandonedBaby::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_abandoned_baby_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_abandoned_baby_update(
handle: *mut AbandonedBaby,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_abandoned_baby_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_abandoned_baby_batch(
handle: *mut AbandonedBaby,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_abandoned_baby_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_abandoned_baby_reset(handle: *mut AbandonedBaby) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_abandoned_baby_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_abandoned_baby_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_abandoned_baby_free(handle: *mut AbandonedBaby) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Abcd` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_abcd_free`.
#[no_mangle]
pub extern "C" fn wickra_abcd_new() -> *mut Abcd {
Box::into_raw(Box::new(Abcd::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_abcd_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_abcd_update(
handle: *mut Abcd,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_abcd_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_abcd_batch(
handle: *mut Abcd,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_abcd_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_abcd_reset(handle: *mut Abcd) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_abcd_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_abcd_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_abcd_free(handle: *mut Abcd) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AcceleratorOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_accelerator_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_accelerator_oscillator_new(
ao_fast: usize,
ao_slow: usize,
signal_period: usize,
) -> *mut AcceleratorOscillator {
match AcceleratorOscillator::new(ao_fast, ao_slow, signal_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_accelerator_oscillator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_accelerator_oscillator_update(
handle: *mut AcceleratorOscillator,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_accelerator_oscillator_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_accelerator_oscillator_batch(
handle: *mut AcceleratorOscillator,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_accelerator_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_accelerator_oscillator_reset(handle: *mut AcceleratorOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_accelerator_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_accelerator_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_accelerator_oscillator_free(handle: *mut AcceleratorOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AdOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ad_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_ad_oscillator_new() -> *mut AdOscillator {
Box::into_raw(Box::new(AdOscillator::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ad_oscillator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ad_oscillator_update(
handle: *mut AdOscillator,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_ad_oscillator_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_ad_oscillator_batch(
handle: *mut AdOscillator,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ad_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ad_oscillator_reset(handle: *mut AdOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ad_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ad_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ad_oscillator_free(handle: *mut AdOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AdaptiveCci` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_adaptive_cci_free`.
#[no_mangle]
pub extern "C" fn wickra_adaptive_cci_new(period: usize) -> *mut AdaptiveCci {
match AdaptiveCci::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_adaptive_cci_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_cci_update(
handle: *mut AdaptiveCci,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_adaptive_cci_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_cci_batch(
handle: *mut AdaptiveCci,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_adaptive_cci_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_cci_reset(handle: *mut AdaptiveCci) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_adaptive_cci_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_adaptive_cci_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adaptive_cci_free(handle: *mut AdaptiveCci) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Adl` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_adl_free`.
#[no_mangle]
pub extern "C" fn wickra_adl_new() -> *mut Adl {
Box::into_raw(Box::new(Adl::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_adl_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adl_update(
handle: *mut Adl,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_adl_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_adl_batch(
handle: *mut Adl,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_adl_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adl_reset(handle: *mut Adl) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_adl_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_adl_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adl_free(handle: *mut Adl) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AdvanceBlock` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_advance_block_free`.
#[no_mangle]
pub extern "C" fn wickra_advance_block_new() -> *mut AdvanceBlock {
Box::into_raw(Box::new(AdvanceBlock::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_advance_block_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_advance_block_update(
handle: *mut AdvanceBlock,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_advance_block_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_advance_block_batch(
handle: *mut AdvanceBlock,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_advance_block_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_advance_block_reset(handle: *mut AdvanceBlock) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_advance_block_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_advance_block_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_advance_block_free(handle: *mut AdvanceBlock) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Adxr` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_adxr_free`.
#[no_mangle]
pub extern "C" fn wickra_adxr_new(period: usize) -> *mut Adxr {
match Adxr::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_adxr_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adxr_update(
handle: *mut Adxr,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_adxr_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_adxr_batch(
handle: *mut Adxr,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_adxr_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adxr_reset(handle: *mut Adxr) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_adxr_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_adxr_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adxr_free(handle: *mut Adxr) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AnchoredVwap` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_anchored_vwap_free`.
#[no_mangle]
pub extern "C" fn wickra_anchored_vwap_new() -> *mut AnchoredVwap {
Box::into_raw(Box::new(AnchoredVwap::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_anchored_vwap_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_anchored_vwap_update(
handle: *mut AnchoredVwap,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_anchored_vwap_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_anchored_vwap_batch(
handle: *mut AnchoredVwap,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_anchored_vwap_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_anchored_vwap_reset(handle: *mut AnchoredVwap) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_anchored_vwap_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_anchored_vwap_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_anchored_vwap_free(handle: *mut AnchoredVwap) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AroonOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_aroon_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_aroon_oscillator_new(period: usize) -> *mut AroonOscillator {
match AroonOscillator::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_aroon_oscillator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_aroon_oscillator_update(
handle: *mut AroonOscillator,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_aroon_oscillator_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_aroon_oscillator_batch(
handle: *mut AroonOscillator,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_aroon_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_aroon_oscillator_reset(handle: *mut AroonOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_aroon_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_aroon_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_aroon_oscillator_free(handle: *mut AroonOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Atr` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_atr_free`.
#[no_mangle]
pub extern "C" fn wickra_atr_new(period: usize) -> *mut Atr {
match Atr::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_atr_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_atr_update(
handle: *mut Atr,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_atr_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_atr_batch(
handle: *mut Atr,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_atr_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_atr_reset(handle: *mut Atr) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_atr_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_atr_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_atr_free(handle: *mut Atr) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AtrTrailingStop` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_atr_trailing_stop_free`.
#[no_mangle]
pub extern "C" fn wickra_atr_trailing_stop_new(
atr_period: usize,
multiplier: f64,
) -> *mut AtrTrailingStop {
match AtrTrailingStop::new(atr_period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_atr_trailing_stop_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_atr_trailing_stop_update(
handle: *mut AtrTrailingStop,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_atr_trailing_stop_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_atr_trailing_stop_batch(
handle: *mut AtrTrailingStop,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_atr_trailing_stop_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_atr_trailing_stop_reset(handle: *mut AtrTrailingStop) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_atr_trailing_stop_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_atr_trailing_stop_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_atr_trailing_stop_free(handle: *mut AtrTrailingStop) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AverageDailyRange` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_average_daily_range_free`.
#[no_mangle]
pub extern "C" fn wickra_average_daily_range_new(
period: usize,
utc_offset_minutes: i32,
) -> *mut AverageDailyRange {
match AverageDailyRange::new(period, utc_offset_minutes) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_average_daily_range_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_average_daily_range_update(
handle: *mut AverageDailyRange,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_average_daily_range_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_average_daily_range_batch(
handle: *mut AverageDailyRange,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_average_daily_range_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_average_daily_range_reset(handle: *mut AverageDailyRange) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_average_daily_range_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_average_daily_range_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_average_daily_range_free(handle: *mut AverageDailyRange) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AvgPrice` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_avg_price_free`.
#[no_mangle]
pub extern "C" fn wickra_avg_price_new() -> *mut AvgPrice {
Box::into_raw(Box::new(AvgPrice::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_avg_price_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_avg_price_update(
handle: *mut AvgPrice,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_avg_price_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_avg_price_batch(
handle: *mut AvgPrice,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_avg_price_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_avg_price_reset(handle: *mut AvgPrice) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_avg_price_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_avg_price_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_avg_price_free(handle: *mut AvgPrice) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AwesomeOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_awesome_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_awesome_oscillator_new(
fast: usize,
slow: usize,
) -> *mut AwesomeOscillator {
match AwesomeOscillator::new(fast, slow) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_awesome_oscillator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_awesome_oscillator_update(
handle: *mut AwesomeOscillator,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_awesome_oscillator_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_awesome_oscillator_batch(
handle: *mut AwesomeOscillator,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_awesome_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_awesome_oscillator_reset(handle: *mut AwesomeOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_awesome_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_awesome_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_awesome_oscillator_free(handle: *mut AwesomeOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AwesomeOscillatorHistogram` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_awesome_oscillator_histogram_free`.
#[no_mangle]
pub extern "C" fn wickra_awesome_oscillator_histogram_new(
fast: usize,
slow: usize,
sma_period: usize,
) -> *mut AwesomeOscillatorHistogram {
match AwesomeOscillatorHistogram::new(fast, slow, sma_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_awesome_oscillator_histogram_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_awesome_oscillator_histogram_update(
handle: *mut AwesomeOscillatorHistogram,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_awesome_oscillator_histogram_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_awesome_oscillator_histogram_batch(
handle: *mut AwesomeOscillatorHistogram,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_awesome_oscillator_histogram_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_awesome_oscillator_histogram_reset(
handle: *mut AwesomeOscillatorHistogram,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_awesome_oscillator_histogram_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_awesome_oscillator_histogram_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_awesome_oscillator_histogram_free(
handle: *mut AwesomeOscillatorHistogram,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `BalanceOfPower` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_balance_of_power_free`.
#[no_mangle]
pub extern "C" fn wickra_balance_of_power_new() -> *mut BalanceOfPower {
Box::into_raw(Box::new(BalanceOfPower::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_balance_of_power_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_balance_of_power_update(
handle: *mut BalanceOfPower,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_balance_of_power_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_balance_of_power_batch(
handle: *mut BalanceOfPower,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_balance_of_power_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_balance_of_power_reset(handle: *mut BalanceOfPower) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_balance_of_power_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_balance_of_power_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_balance_of_power_free(handle: *mut BalanceOfPower) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Bat` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_bat_free`.
#[no_mangle]
pub extern "C" fn wickra_bat_new() -> *mut Bat {
Box::into_raw(Box::new(Bat::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_bat_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bat_update(
handle: *mut Bat,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_bat_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_bat_batch(
handle: *mut Bat,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_bat_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bat_reset(handle: *mut Bat) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_bat_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_bat_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bat_free(handle: *mut Bat) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `BeltHold` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_belt_hold_free`.
#[no_mangle]
pub extern "C" fn wickra_belt_hold_new() -> *mut BeltHold {
Box::into_raw(Box::new(BeltHold::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_belt_hold_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_belt_hold_update(
handle: *mut BeltHold,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_belt_hold_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_belt_hold_batch(
handle: *mut BeltHold,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_belt_hold_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_belt_hold_reset(handle: *mut BeltHold) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_belt_hold_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_belt_hold_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_belt_hold_free(handle: *mut BeltHold) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `BetterVolume` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_better_volume_free`.
#[no_mangle]
pub extern "C" fn wickra_better_volume_new(period: usize) -> *mut BetterVolume {
match BetterVolume::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_better_volume_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_better_volume_update(
handle: *mut BetterVolume,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_better_volume_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_better_volume_batch(
handle: *mut BetterVolume,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_better_volume_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_better_volume_reset(handle: *mut BetterVolume) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_better_volume_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_better_volume_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_better_volume_free(handle: *mut BetterVolume) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `BodySizePct` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_body_size_pct_free`.
#[no_mangle]
pub extern "C" fn wickra_body_size_pct_new() -> *mut BodySizePct {
Box::into_raw(Box::new(BodySizePct::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_body_size_pct_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_body_size_pct_update(
handle: *mut BodySizePct,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_body_size_pct_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_body_size_pct_batch(
handle: *mut BodySizePct,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_body_size_pct_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_body_size_pct_reset(handle: *mut BodySizePct) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_body_size_pct_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_body_size_pct_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_body_size_pct_free(handle: *mut BodySizePct) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Breakaway` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_breakaway_free`.
#[no_mangle]
pub extern "C" fn wickra_breakaway_new() -> *mut Breakaway {
Box::into_raw(Box::new(Breakaway::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_breakaway_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_breakaway_update(
handle: *mut Breakaway,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_breakaway_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_breakaway_batch(
handle: *mut Breakaway,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_breakaway_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_breakaway_reset(handle: *mut Breakaway) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_breakaway_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_breakaway_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_breakaway_free(handle: *mut Breakaway) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Butterfly` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_butterfly_free`.
#[no_mangle]
pub extern "C" fn wickra_butterfly_new() -> *mut Butterfly {
Box::into_raw(Box::new(Butterfly::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_butterfly_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_butterfly_update(
handle: *mut Butterfly,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_butterfly_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_butterfly_batch(
handle: *mut Butterfly,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_butterfly_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_butterfly_reset(handle: *mut Butterfly) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_butterfly_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_butterfly_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_butterfly_free(handle: *mut Butterfly) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Cci` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_cci_free`.
#[no_mangle]
pub extern "C" fn wickra_cci_new(period: usize) -> *mut Cci {
match Cci::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_cci_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cci_update(
handle: *mut Cci,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_cci_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_cci_batch(
handle: *mut Cci,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_cci_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cci_reset(handle: *mut Cci) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_cci_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_cci_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cci_free(handle: *mut Cci) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ChaikinOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_chaikin_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_chaikin_oscillator_new(
fast: usize,
slow: usize,
) -> *mut ChaikinOscillator {
match ChaikinOscillator::new(fast, slow) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_chaikin_oscillator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chaikin_oscillator_update(
handle: *mut ChaikinOscillator,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_chaikin_oscillator_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_chaikin_oscillator_batch(
handle: *mut ChaikinOscillator,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_chaikin_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chaikin_oscillator_reset(handle: *mut ChaikinOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_chaikin_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_chaikin_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chaikin_oscillator_free(handle: *mut ChaikinOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ChaikinVolatility` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_chaikin_volatility_free`.
#[no_mangle]
pub extern "C" fn wickra_chaikin_volatility_new(
ema_period: usize,
roc_period: usize,
) -> *mut ChaikinVolatility {
match ChaikinVolatility::new(ema_period, roc_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_chaikin_volatility_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chaikin_volatility_update(
handle: *mut ChaikinVolatility,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_chaikin_volatility_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_chaikin_volatility_batch(
handle: *mut ChaikinVolatility,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_chaikin_volatility_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chaikin_volatility_reset(handle: *mut ChaikinVolatility) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_chaikin_volatility_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_chaikin_volatility_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chaikin_volatility_free(handle: *mut ChaikinVolatility) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ChoppinessIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_choppiness_index_free`.
#[no_mangle]
pub extern "C" fn wickra_choppiness_index_new(period: usize) -> *mut ChoppinessIndex {
match ChoppinessIndex::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_choppiness_index_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_choppiness_index_update(
handle: *mut ChoppinessIndex,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_choppiness_index_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_choppiness_index_batch(
handle: *mut ChoppinessIndex,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_choppiness_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_choppiness_index_reset(handle: *mut ChoppinessIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_choppiness_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_choppiness_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_choppiness_index_free(handle: *mut ChoppinessIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `CloseVsOpen` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_close_vs_open_free`.
#[no_mangle]
pub extern "C" fn wickra_close_vs_open_new() -> *mut CloseVsOpen {
Box::into_raw(Box::new(CloseVsOpen::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_close_vs_open_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_close_vs_open_update(
handle: *mut CloseVsOpen,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_close_vs_open_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_close_vs_open_batch(
handle: *mut CloseVsOpen,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_close_vs_open_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_close_vs_open_reset(handle: *mut CloseVsOpen) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_close_vs_open_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_close_vs_open_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_close_vs_open_free(handle: *mut CloseVsOpen) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ClosingMarubozu` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_closing_marubozu_free`.
#[no_mangle]
pub extern "C" fn wickra_closing_marubozu_new() -> *mut ClosingMarubozu {
Box::into_raw(Box::new(ClosingMarubozu::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_closing_marubozu_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_closing_marubozu_update(
handle: *mut ClosingMarubozu,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_closing_marubozu_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_closing_marubozu_batch(
handle: *mut ClosingMarubozu,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_closing_marubozu_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_closing_marubozu_reset(handle: *mut ClosingMarubozu) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_closing_marubozu_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_closing_marubozu_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_closing_marubozu_free(handle: *mut ClosingMarubozu) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ChaikinMoneyFlow` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_chaikin_money_flow_free`.
#[no_mangle]
pub extern "C" fn wickra_chaikin_money_flow_new(period: usize) -> *mut ChaikinMoneyFlow {
match ChaikinMoneyFlow::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_chaikin_money_flow_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chaikin_money_flow_update(
handle: *mut ChaikinMoneyFlow,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_chaikin_money_flow_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_chaikin_money_flow_batch(
handle: *mut ChaikinMoneyFlow,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_chaikin_money_flow_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chaikin_money_flow_reset(handle: *mut ChaikinMoneyFlow) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_chaikin_money_flow_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_chaikin_money_flow_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chaikin_money_flow_free(handle: *mut ChaikinMoneyFlow) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ConcealingBabySwallow` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_concealing_baby_swallow_free`.
#[no_mangle]
pub extern "C" fn wickra_concealing_baby_swallow_new() -> *mut ConcealingBabySwallow {
Box::into_raw(Box::new(ConcealingBabySwallow::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_concealing_baby_swallow_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_concealing_baby_swallow_update(
handle: *mut ConcealingBabySwallow,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_concealing_baby_swallow_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_concealing_baby_swallow_batch(
handle: *mut ConcealingBabySwallow,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_concealing_baby_swallow_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_concealing_baby_swallow_reset(handle: *mut ConcealingBabySwallow) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_concealing_baby_swallow_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_concealing_baby_swallow_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_concealing_baby_swallow_free(handle: *mut ConcealingBabySwallow) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Counterattack` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_counterattack_free`.
#[no_mangle]
pub extern "C" fn wickra_counterattack_new() -> *mut Counterattack {
Box::into_raw(Box::new(Counterattack::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_counterattack_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_counterattack_update(
handle: *mut Counterattack,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_counterattack_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_counterattack_batch(
handle: *mut Counterattack,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_counterattack_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_counterattack_reset(handle: *mut Counterattack) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_counterattack_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_counterattack_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_counterattack_free(handle: *mut Counterattack) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Crab` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_crab_free`.
#[no_mangle]
pub extern "C" fn wickra_crab_new() -> *mut Crab {
Box::into_raw(Box::new(Crab::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_crab_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_crab_update(
handle: *mut Crab,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_crab_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_crab_batch(
handle: *mut Crab,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_crab_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_crab_reset(handle: *mut Crab) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_crab_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_crab_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_crab_free(handle: *mut Crab) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `CupAndHandle` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_cup_and_handle_free`.
#[no_mangle]
pub extern "C" fn wickra_cup_and_handle_new() -> *mut CupAndHandle {
Box::into_raw(Box::new(CupAndHandle::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_cup_and_handle_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cup_and_handle_update(
handle: *mut CupAndHandle,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_cup_and_handle_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_cup_and_handle_batch(
handle: *mut CupAndHandle,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_cup_and_handle_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cup_and_handle_reset(handle: *mut CupAndHandle) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_cup_and_handle_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_cup_and_handle_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cup_and_handle_free(handle: *mut CupAndHandle) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Cypher` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_cypher_free`.
#[no_mangle]
pub extern "C" fn wickra_cypher_new() -> *mut Cypher {
Box::into_raw(Box::new(Cypher::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_cypher_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cypher_update(
handle: *mut Cypher,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_cypher_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_cypher_batch(
handle: *mut Cypher,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_cypher_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cypher_reset(handle: *mut Cypher) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_cypher_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_cypher_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cypher_free(handle: *mut Cypher) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DemandIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_demand_index_free`.
#[no_mangle]
pub extern "C" fn wickra_demand_index_new(period: usize) -> *mut DemandIndex {
match DemandIndex::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_demand_index_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_demand_index_update(
handle: *mut DemandIndex,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_demand_index_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_demand_index_batch(
handle: *mut DemandIndex,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_demand_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_demand_index_reset(handle: *mut DemandIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_demand_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_demand_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_demand_index_free(handle: *mut DemandIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Doji` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_doji_free`.
#[no_mangle]
pub extern "C" fn wickra_doji_new() -> *mut Doji {
Box::into_raw(Box::new(Doji::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_doji_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_doji_update(
handle: *mut Doji,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_doji_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_doji_batch(
handle: *mut Doji,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_doji_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_doji_reset(handle: *mut Doji) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_doji_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_doji_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_doji_free(handle: *mut Doji) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DojiStar` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_doji_star_free`.
#[no_mangle]
pub extern "C" fn wickra_doji_star_new() -> *mut DojiStar {
Box::into_raw(Box::new(DojiStar::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_doji_star_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_doji_star_update(
handle: *mut DojiStar,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_doji_star_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_doji_star_batch(
handle: *mut DojiStar,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_doji_star_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_doji_star_reset(handle: *mut DojiStar) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_doji_star_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_doji_star_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_doji_star_free(handle: *mut DojiStar) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DoubleTopBottom` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_double_top_bottom_free`.
#[no_mangle]
pub extern "C" fn wickra_double_top_bottom_new() -> *mut DoubleTopBottom {
Box::into_raw(Box::new(DoubleTopBottom::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_double_top_bottom_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_double_top_bottom_update(
handle: *mut DoubleTopBottom,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_double_top_bottom_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_double_top_bottom_batch(
handle: *mut DoubleTopBottom,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_double_top_bottom_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_double_top_bottom_reset(handle: *mut DoubleTopBottom) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_double_top_bottom_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_double_top_bottom_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_double_top_bottom_free(handle: *mut DoubleTopBottom) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DownsideGapThreeMethods` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_downside_gap_three_methods_free`.
#[no_mangle]
pub extern "C" fn wickra_downside_gap_three_methods_new() -> *mut DownsideGapThreeMethods {
Box::into_raw(Box::new(DownsideGapThreeMethods::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_downside_gap_three_methods_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_downside_gap_three_methods_update(
handle: *mut DownsideGapThreeMethods,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_downside_gap_three_methods_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_downside_gap_three_methods_batch(
handle: *mut DownsideGapThreeMethods,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_downside_gap_three_methods_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_downside_gap_three_methods_reset(
handle: *mut DownsideGapThreeMethods,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_downside_gap_three_methods_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_downside_gap_three_methods_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_downside_gap_three_methods_free(
handle: *mut DownsideGapThreeMethods,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DragonflyDoji` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_dragonfly_doji_free`.
#[no_mangle]
pub extern "C" fn wickra_dragonfly_doji_new() -> *mut DragonflyDoji {
Box::into_raw(Box::new(DragonflyDoji::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_dragonfly_doji_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dragonfly_doji_update(
handle: *mut DragonflyDoji,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_dragonfly_doji_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_dragonfly_doji_batch(
handle: *mut DragonflyDoji,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_dragonfly_doji_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dragonfly_doji_reset(handle: *mut DragonflyDoji) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_dragonfly_doji_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_dragonfly_doji_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dragonfly_doji_free(handle: *mut DragonflyDoji) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DumplingTop` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_dumpling_top_free`.
#[no_mangle]
pub extern "C" fn wickra_dumpling_top_new(period: usize) -> *mut DumplingTop {
match DumplingTop::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_dumpling_top_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dumpling_top_update(
handle: *mut DumplingTop,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_dumpling_top_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_dumpling_top_batch(
handle: *mut DumplingTop,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_dumpling_top_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dumpling_top_reset(handle: *mut DumplingTop) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_dumpling_top_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_dumpling_top_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dumpling_top_free(handle: *mut DumplingTop) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Dx` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_dx_free`.
#[no_mangle]
pub extern "C" fn wickra_dx_new(period: usize) -> *mut Dx {
match Dx::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_dx_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dx_update(
handle: *mut Dx,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_dx_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_dx_batch(
handle: *mut Dx,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_dx_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dx_reset(handle: *mut Dx) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_dx_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_dx_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dx_free(handle: *mut Dx) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `EaseOfMovement` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ease_of_movement_free`.
#[no_mangle]
pub extern "C" fn wickra_ease_of_movement_new(period: usize) -> *mut EaseOfMovement {
match EaseOfMovement::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ease_of_movement_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ease_of_movement_update(
handle: *mut EaseOfMovement,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_ease_of_movement_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_ease_of_movement_batch(
handle: *mut EaseOfMovement,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ease_of_movement_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ease_of_movement_reset(handle: *mut EaseOfMovement) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ease_of_movement_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ease_of_movement_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ease_of_movement_free(handle: *mut EaseOfMovement) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Engulfing` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_engulfing_free`.
#[no_mangle]
pub extern "C" fn wickra_engulfing_new() -> *mut Engulfing {
Box::into_raw(Box::new(Engulfing::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_engulfing_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_engulfing_update(
handle: *mut Engulfing,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_engulfing_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_engulfing_batch(
handle: *mut Engulfing,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_engulfing_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_engulfing_reset(handle: *mut Engulfing) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_engulfing_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_engulfing_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_engulfing_free(handle: *mut Engulfing) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `EveningDojiStar` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_evening_doji_star_free`.
#[no_mangle]
pub extern "C" fn wickra_evening_doji_star_new() -> *mut EveningDojiStar {
Box::into_raw(Box::new(EveningDojiStar::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_evening_doji_star_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_evening_doji_star_update(
handle: *mut EveningDojiStar,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_evening_doji_star_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_evening_doji_star_batch(
handle: *mut EveningDojiStar,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_evening_doji_star_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_evening_doji_star_reset(handle: *mut EveningDojiStar) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_evening_doji_star_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_evening_doji_star_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_evening_doji_star_free(handle: *mut EveningDojiStar) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Evwma` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_evwma_free`.
#[no_mangle]
pub extern "C" fn wickra_evwma_new(period: usize) -> *mut Evwma {
match Evwma::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_evwma_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_evwma_update(
handle: *mut Evwma,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_evwma_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_evwma_batch(
handle: *mut Evwma,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_evwma_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_evwma_reset(handle: *mut Evwma) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_evwma_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_evwma_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_evwma_free(handle: *mut Evwma) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FallingThreeMethods` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_falling_three_methods_free`.
#[no_mangle]
pub extern "C" fn wickra_falling_three_methods_new() -> *mut FallingThreeMethods {
Box::into_raw(Box::new(FallingThreeMethods::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_falling_three_methods_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_falling_three_methods_update(
handle: *mut FallingThreeMethods,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_falling_three_methods_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_falling_three_methods_batch(
handle: *mut FallingThreeMethods,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_falling_three_methods_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_falling_three_methods_reset(handle: *mut FallingThreeMethods) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_falling_three_methods_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_falling_three_methods_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_falling_three_methods_free(handle: *mut FallingThreeMethods) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FlagPennant` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_flag_pennant_free`.
#[no_mangle]
pub extern "C" fn wickra_flag_pennant_new() -> *mut FlagPennant {
Box::into_raw(Box::new(FlagPennant::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_flag_pennant_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_flag_pennant_update(
handle: *mut FlagPennant,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_flag_pennant_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_flag_pennant_batch(
handle: *mut FlagPennant,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_flag_pennant_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_flag_pennant_reset(handle: *mut FlagPennant) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_flag_pennant_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_flag_pennant_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_flag_pennant_free(handle: *mut FlagPennant) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ForceIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_force_index_free`.
#[no_mangle]
pub extern "C" fn wickra_force_index_new(period: usize) -> *mut ForceIndex {
match ForceIndex::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_force_index_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_force_index_update(
handle: *mut ForceIndex,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_force_index_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_force_index_batch(
handle: *mut ForceIndex,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_force_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_force_index_reset(handle: *mut ForceIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_force_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_force_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_force_index_free(handle: *mut ForceIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FryPanBottom` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_fry_pan_bottom_free`.
#[no_mangle]
pub extern "C" fn wickra_fry_pan_bottom_new(period: usize) -> *mut FryPanBottom {
match FryPanBottom::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_fry_pan_bottom_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fry_pan_bottom_update(
handle: *mut FryPanBottom,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_fry_pan_bottom_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_fry_pan_bottom_batch(
handle: *mut FryPanBottom,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_fry_pan_bottom_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fry_pan_bottom_reset(handle: *mut FryPanBottom) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_fry_pan_bottom_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_fry_pan_bottom_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fry_pan_bottom_free(handle: *mut FryPanBottom) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `GapSideBySideWhite` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_gap_side_by_side_white_free`.
#[no_mangle]
pub extern "C" fn wickra_gap_side_by_side_white_new() -> *mut GapSideBySideWhite {
Box::into_raw(Box::new(GapSideBySideWhite::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_gap_side_by_side_white_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gap_side_by_side_white_update(
handle: *mut GapSideBySideWhite,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_gap_side_by_side_white_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_gap_side_by_side_white_batch(
handle: *mut GapSideBySideWhite,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_gap_side_by_side_white_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gap_side_by_side_white_reset(handle: *mut GapSideBySideWhite) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_gap_side_by_side_white_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_gap_side_by_side_white_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gap_side_by_side_white_free(handle: *mut GapSideBySideWhite) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `GarmanKlassVolatility` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_garman_klass_volatility_free`.
#[no_mangle]
pub extern "C" fn wickra_garman_klass_volatility_new(
period: usize,
trading_periods: usize,
) -> *mut GarmanKlassVolatility {
match GarmanKlassVolatility::new(period, trading_periods) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_garman_klass_volatility_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_garman_klass_volatility_update(
handle: *mut GarmanKlassVolatility,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_garman_klass_volatility_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_garman_klass_volatility_batch(
handle: *mut GarmanKlassVolatility,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_garman_klass_volatility_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_garman_klass_volatility_reset(handle: *mut GarmanKlassVolatility) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_garman_klass_volatility_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_garman_klass_volatility_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_garman_klass_volatility_free(handle: *mut GarmanKlassVolatility) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Gartley` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_gartley_free`.
#[no_mangle]
pub extern "C" fn wickra_gartley_new() -> *mut Gartley {
Box::into_raw(Box::new(Gartley::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_gartley_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gartley_update(
handle: *mut Gartley,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_gartley_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_gartley_batch(
handle: *mut Gartley,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_gartley_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gartley_reset(handle: *mut Gartley) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_gartley_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_gartley_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gartley_free(handle: *mut Gartley) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `GravestoneDoji` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_gravestone_doji_free`.
#[no_mangle]
pub extern "C" fn wickra_gravestone_doji_new() -> *mut GravestoneDoji {
Box::into_raw(Box::new(GravestoneDoji::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_gravestone_doji_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gravestone_doji_update(
handle: *mut GravestoneDoji,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_gravestone_doji_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_gravestone_doji_batch(
handle: *mut GravestoneDoji,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_gravestone_doji_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gravestone_doji_reset(handle: *mut GravestoneDoji) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_gravestone_doji_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_gravestone_doji_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gravestone_doji_free(handle: *mut GravestoneDoji) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Hammer` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_hammer_free`.
#[no_mangle]
pub extern "C" fn wickra_hammer_new() -> *mut Hammer {
Box::into_raw(Box::new(Hammer::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_hammer_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hammer_update(
handle: *mut Hammer,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_hammer_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_hammer_batch(
handle: *mut Hammer,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_hammer_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hammer_reset(handle: *mut Hammer) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_hammer_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_hammer_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hammer_free(handle: *mut Hammer) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HangingMan` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_hanging_man_free`.
#[no_mangle]
pub extern "C" fn wickra_hanging_man_new() -> *mut HangingMan {
Box::into_raw(Box::new(HangingMan::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_hanging_man_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hanging_man_update(
handle: *mut HangingMan,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_hanging_man_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_hanging_man_batch(
handle: *mut HangingMan,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_hanging_man_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hanging_man_reset(handle: *mut HangingMan) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_hanging_man_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_hanging_man_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hanging_man_free(handle: *mut HangingMan) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Harami` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_harami_free`.
#[no_mangle]
pub extern "C" fn wickra_harami_new() -> *mut Harami {
Box::into_raw(Box::new(Harami::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_harami_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_harami_update(
handle: *mut Harami,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_harami_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_harami_batch(
handle: *mut Harami,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_harami_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_harami_reset(handle: *mut Harami) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_harami_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_harami_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_harami_free(handle: *mut Harami) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HaramiCross` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_harami_cross_free`.
#[no_mangle]
pub extern "C" fn wickra_harami_cross_new() -> *mut HaramiCross {
Box::into_raw(Box::new(HaramiCross::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_harami_cross_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_harami_cross_update(
handle: *mut HaramiCross,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_harami_cross_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_harami_cross_batch(
handle: *mut HaramiCross,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_harami_cross_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_harami_cross_reset(handle: *mut HaramiCross) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_harami_cross_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_harami_cross_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_harami_cross_free(handle: *mut HaramiCross) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HeadAndShoulders` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_head_and_shoulders_free`.
#[no_mangle]
pub extern "C" fn wickra_head_and_shoulders_new() -> *mut HeadAndShoulders {
Box::into_raw(Box::new(HeadAndShoulders::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_head_and_shoulders_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_head_and_shoulders_update(
handle: *mut HeadAndShoulders,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_head_and_shoulders_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_head_and_shoulders_batch(
handle: *mut HeadAndShoulders,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_head_and_shoulders_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_head_and_shoulders_reset(handle: *mut HeadAndShoulders) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_head_and_shoulders_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_head_and_shoulders_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_head_and_shoulders_free(handle: *mut HeadAndShoulders) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HeikinAshiOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_heikin_ashi_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_heikin_ashi_oscillator_new(period: usize) -> *mut HeikinAshiOscillator {
match HeikinAshiOscillator::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_heikin_ashi_oscillator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_heikin_ashi_oscillator_update(
handle: *mut HeikinAshiOscillator,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_heikin_ashi_oscillator_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_heikin_ashi_oscillator_batch(
handle: *mut HeikinAshiOscillator,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_heikin_ashi_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_heikin_ashi_oscillator_reset(handle: *mut HeikinAshiOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_heikin_ashi_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_heikin_ashi_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_heikin_ashi_oscillator_free(handle: *mut HeikinAshiOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HighLowRange` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_high_low_range_free`.
#[no_mangle]
pub extern "C" fn wickra_high_low_range_new() -> *mut HighLowRange {
Box::into_raw(Box::new(HighLowRange::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_high_low_range_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_high_low_range_update(
handle: *mut HighLowRange,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_high_low_range_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_high_low_range_batch(
handle: *mut HighLowRange,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_high_low_range_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_high_low_range_reset(handle: *mut HighLowRange) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_high_low_range_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_high_low_range_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_high_low_range_free(handle: *mut HighLowRange) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HighWave` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_high_wave_free`.
#[no_mangle]
pub extern "C" fn wickra_high_wave_new() -> *mut HighWave {
Box::into_raw(Box::new(HighWave::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_high_wave_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_high_wave_update(
handle: *mut HighWave,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_high_wave_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_high_wave_batch(
handle: *mut HighWave,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_high_wave_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_high_wave_reset(handle: *mut HighWave) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_high_wave_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_high_wave_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_high_wave_free(handle: *mut HighWave) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Hikkake` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_hikkake_free`.
#[no_mangle]
pub extern "C" fn wickra_hikkake_new() -> *mut Hikkake {
Box::into_raw(Box::new(Hikkake::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_hikkake_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hikkake_update(
handle: *mut Hikkake,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_hikkake_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_hikkake_batch(
handle: *mut Hikkake,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_hikkake_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hikkake_reset(handle: *mut Hikkake) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_hikkake_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_hikkake_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hikkake_free(handle: *mut Hikkake) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HikkakeModified` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_hikkake_modified_free`.
#[no_mangle]
pub extern "C" fn wickra_hikkake_modified_new() -> *mut HikkakeModified {
Box::into_raw(Box::new(HikkakeModified::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_hikkake_modified_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hikkake_modified_update(
handle: *mut HikkakeModified,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_hikkake_modified_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_hikkake_modified_batch(
handle: *mut HikkakeModified,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_hikkake_modified_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hikkake_modified_reset(handle: *mut HikkakeModified) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_hikkake_modified_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_hikkake_modified_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hikkake_modified_free(handle: *mut HikkakeModified) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HiLoActivator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_hi_lo_activator_free`.
#[no_mangle]
pub extern "C" fn wickra_hi_lo_activator_new(period: usize) -> *mut HiLoActivator {
match HiLoActivator::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_hi_lo_activator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hi_lo_activator_update(
handle: *mut HiLoActivator,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_hi_lo_activator_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_hi_lo_activator_batch(
handle: *mut HiLoActivator,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_hi_lo_activator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hi_lo_activator_reset(handle: *mut HiLoActivator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_hi_lo_activator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_hi_lo_activator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hi_lo_activator_free(handle: *mut HiLoActivator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HomingPigeon` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_homing_pigeon_free`.
#[no_mangle]
pub extern "C" fn wickra_homing_pigeon_new() -> *mut HomingPigeon {
Box::into_raw(Box::new(HomingPigeon::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_homing_pigeon_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_homing_pigeon_update(
handle: *mut HomingPigeon,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_homing_pigeon_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_homing_pigeon_batch(
handle: *mut HomingPigeon,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_homing_pigeon_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_homing_pigeon_reset(handle: *mut HomingPigeon) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_homing_pigeon_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_homing_pigeon_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_homing_pigeon_free(handle: *mut HomingPigeon) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `IdenticalThreeCrows` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_identical_three_crows_free`.
#[no_mangle]
pub extern "C" fn wickra_identical_three_crows_new() -> *mut IdenticalThreeCrows {
Box::into_raw(Box::new(IdenticalThreeCrows::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_identical_three_crows_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_identical_three_crows_update(
handle: *mut IdenticalThreeCrows,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_identical_three_crows_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_identical_three_crows_batch(
handle: *mut IdenticalThreeCrows,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_identical_three_crows_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_identical_three_crows_reset(handle: *mut IdenticalThreeCrows) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_identical_three_crows_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_identical_three_crows_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_identical_three_crows_free(handle: *mut IdenticalThreeCrows) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `InNeck` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_in_neck_free`.
#[no_mangle]
pub extern "C" fn wickra_in_neck_new() -> *mut InNeck {
Box::into_raw(Box::new(InNeck::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_in_neck_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_in_neck_update(
handle: *mut InNeck,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_in_neck_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_in_neck_batch(
handle: *mut InNeck,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_in_neck_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_in_neck_reset(handle: *mut InNeck) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_in_neck_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_in_neck_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_in_neck_free(handle: *mut InNeck) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Inertia` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_inertia_free`.
#[no_mangle]
pub extern "C" fn wickra_inertia_new(rvi_period: usize, linreg_period: usize) -> *mut Inertia {
match Inertia::new(rvi_period, linreg_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_inertia_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_inertia_update(
handle: *mut Inertia,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_inertia_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_inertia_batch(
handle: *mut Inertia,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_inertia_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_inertia_reset(handle: *mut Inertia) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_inertia_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_inertia_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_inertia_free(handle: *mut Inertia) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `IntradayIntensity` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_intraday_intensity_free`.
#[no_mangle]
pub extern "C" fn wickra_intraday_intensity_new() -> *mut IntradayIntensity {
Box::into_raw(Box::new(IntradayIntensity::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_intraday_intensity_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_intraday_intensity_update(
handle: *mut IntradayIntensity,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_intraday_intensity_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_intraday_intensity_batch(
handle: *mut IntradayIntensity,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_intraday_intensity_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_intraday_intensity_reset(handle: *mut IntradayIntensity) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_intraday_intensity_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_intraday_intensity_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_intraday_intensity_free(handle: *mut IntradayIntensity) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `IntradayMomentumIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_intraday_momentum_index_free`.
#[no_mangle]
pub extern "C" fn wickra_intraday_momentum_index_new(period: usize) -> *mut IntradayMomentumIndex {
match IntradayMomentumIndex::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_intraday_momentum_index_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_intraday_momentum_index_update(
handle: *mut IntradayMomentumIndex,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_intraday_momentum_index_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_intraday_momentum_index_batch(
handle: *mut IntradayMomentumIndex,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_intraday_momentum_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_intraday_momentum_index_reset(handle: *mut IntradayMomentumIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_intraday_momentum_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_intraday_momentum_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_intraday_momentum_index_free(handle: *mut IntradayMomentumIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `InvertedHammer` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_inverted_hammer_free`.
#[no_mangle]
pub extern "C" fn wickra_inverted_hammer_new() -> *mut InvertedHammer {
Box::into_raw(Box::new(InvertedHammer::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_inverted_hammer_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_inverted_hammer_update(
handle: *mut InvertedHammer,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_inverted_hammer_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_inverted_hammer_batch(
handle: *mut InvertedHammer,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_inverted_hammer_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_inverted_hammer_reset(handle: *mut InvertedHammer) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_inverted_hammer_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_inverted_hammer_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_inverted_hammer_free(handle: *mut InvertedHammer) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Kicking` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_kicking_free`.
#[no_mangle]
pub extern "C" fn wickra_kicking_new() -> *mut Kicking {
Box::into_raw(Box::new(Kicking::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_kicking_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kicking_update(
handle: *mut Kicking,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_kicking_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_kicking_batch(
handle: *mut Kicking,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_kicking_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kicking_reset(handle: *mut Kicking) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_kicking_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_kicking_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kicking_free(handle: *mut Kicking) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `KickingByLength` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_kicking_by_length_free`.
#[no_mangle]
pub extern "C" fn wickra_kicking_by_length_new() -> *mut KickingByLength {
Box::into_raw(Box::new(KickingByLength::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_kicking_by_length_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kicking_by_length_update(
handle: *mut KickingByLength,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_kicking_by_length_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_kicking_by_length_batch(
handle: *mut KickingByLength,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_kicking_by_length_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kicking_by_length_reset(handle: *mut KickingByLength) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_kicking_by_length_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_kicking_by_length_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kicking_by_length_free(handle: *mut KickingByLength) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Kvo` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_kvo_free`.
#[no_mangle]
pub extern "C" fn wickra_kvo_new(fast: usize, slow: usize) -> *mut Kvo {
match Kvo::new(fast, slow) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_kvo_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kvo_update(
handle: *mut Kvo,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_kvo_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_kvo_batch(
handle: *mut Kvo,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_kvo_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kvo_reset(handle: *mut Kvo) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_kvo_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_kvo_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kvo_free(handle: *mut Kvo) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `LadderBottom` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ladder_bottom_free`.
#[no_mangle]
pub extern "C" fn wickra_ladder_bottom_new() -> *mut LadderBottom {
Box::into_raw(Box::new(LadderBottom::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ladder_bottom_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ladder_bottom_update(
handle: *mut LadderBottom,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_ladder_bottom_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_ladder_bottom_batch(
handle: *mut LadderBottom,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ladder_bottom_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ladder_bottom_reset(handle: *mut LadderBottom) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ladder_bottom_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ladder_bottom_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ladder_bottom_free(handle: *mut LadderBottom) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `LongLeggedDoji` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_long_legged_doji_free`.
#[no_mangle]
pub extern "C" fn wickra_long_legged_doji_new() -> *mut LongLeggedDoji {
Box::into_raw(Box::new(LongLeggedDoji::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_long_legged_doji_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_long_legged_doji_update(
handle: *mut LongLeggedDoji,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_long_legged_doji_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_long_legged_doji_batch(
handle: *mut LongLeggedDoji,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_long_legged_doji_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_long_legged_doji_reset(handle: *mut LongLeggedDoji) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_long_legged_doji_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_long_legged_doji_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_long_legged_doji_free(handle: *mut LongLeggedDoji) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `LongLine` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_long_line_free`.
#[no_mangle]
pub extern "C" fn wickra_long_line_new() -> *mut LongLine {
Box::into_raw(Box::new(LongLine::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_long_line_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_long_line_update(
handle: *mut LongLine,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_long_line_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_long_line_batch(
handle: *mut LongLine,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_long_line_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_long_line_reset(handle: *mut LongLine) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_long_line_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_long_line_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_long_line_free(handle: *mut LongLine) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MarketFacilitationIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_market_facilitation_index_free`.
#[no_mangle]
pub extern "C" fn wickra_market_facilitation_index_new() -> *mut MarketFacilitationIndex {
Box::into_raw(Box::new(MarketFacilitationIndex::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_market_facilitation_index_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_market_facilitation_index_update(
handle: *mut MarketFacilitationIndex,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_market_facilitation_index_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_market_facilitation_index_batch(
handle: *mut MarketFacilitationIndex,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_market_facilitation_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_market_facilitation_index_reset(
handle: *mut MarketFacilitationIndex,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_market_facilitation_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_market_facilitation_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_market_facilitation_index_free(
handle: *mut MarketFacilitationIndex,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Marubozu` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_marubozu_free`.
#[no_mangle]
pub extern "C" fn wickra_marubozu_new() -> *mut Marubozu {
Box::into_raw(Box::new(Marubozu::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_marubozu_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_marubozu_update(
handle: *mut Marubozu,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_marubozu_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_marubozu_batch(
handle: *mut Marubozu,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_marubozu_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_marubozu_reset(handle: *mut Marubozu) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_marubozu_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_marubozu_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_marubozu_free(handle: *mut Marubozu) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MassIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_mass_index_free`.
#[no_mangle]
pub extern "C" fn wickra_mass_index_new(ema_period: usize, sum_period: usize) -> *mut MassIndex {
match MassIndex::new(ema_period, sum_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_mass_index_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mass_index_update(
handle: *mut MassIndex,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_mass_index_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_mass_index_batch(
handle: *mut MassIndex,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_mass_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mass_index_reset(handle: *mut MassIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_mass_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_mass_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mass_index_free(handle: *mut MassIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MatHold` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_mat_hold_free`.
#[no_mangle]
pub extern "C" fn wickra_mat_hold_new() -> *mut MatHold {
Box::into_raw(Box::new(MatHold::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_mat_hold_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mat_hold_update(
handle: *mut MatHold,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_mat_hold_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_mat_hold_batch(
handle: *mut MatHold,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_mat_hold_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mat_hold_reset(handle: *mut MatHold) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_mat_hold_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_mat_hold_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mat_hold_free(handle: *mut MatHold) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MatchingLow` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_matching_low_free`.
#[no_mangle]
pub extern "C" fn wickra_matching_low_new() -> *mut MatchingLow {
Box::into_raw(Box::new(MatchingLow::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_matching_low_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_matching_low_update(
handle: *mut MatchingLow,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_matching_low_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_matching_low_batch(
handle: *mut MatchingLow,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_matching_low_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_matching_low_reset(handle: *mut MatchingLow) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_matching_low_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_matching_low_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_matching_low_free(handle: *mut MatchingLow) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MedianPrice` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_median_price_free`.
#[no_mangle]
pub extern "C" fn wickra_median_price_new() -> *mut MedianPrice {
Box::into_raw(Box::new(MedianPrice::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_median_price_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_price_update(
handle: *mut MedianPrice,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_median_price_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_price_batch(
handle: *mut MedianPrice,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_median_price_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_price_reset(handle: *mut MedianPrice) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_median_price_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_median_price_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_price_free(handle: *mut MedianPrice) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Mfi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_mfi_free`.
#[no_mangle]
pub extern "C" fn wickra_mfi_new(period: usize) -> *mut Mfi {
match Mfi::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_mfi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mfi_update(
handle: *mut Mfi,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_mfi_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_mfi_batch(
handle: *mut Mfi,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_mfi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mfi_reset(handle: *mut Mfi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_mfi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_mfi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mfi_free(handle: *mut Mfi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MidPrice` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_mid_price_free`.
#[no_mangle]
pub extern "C" fn wickra_mid_price_new(period: usize) -> *mut MidPrice {
match MidPrice::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_mid_price_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mid_price_update(
handle: *mut MidPrice,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_mid_price_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_mid_price_batch(
handle: *mut MidPrice,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_mid_price_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mid_price_reset(handle: *mut MidPrice) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_mid_price_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_mid_price_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mid_price_free(handle: *mut MidPrice) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MinusDi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_minus_di_free`.
#[no_mangle]
pub extern "C" fn wickra_minus_di_new(period: usize) -> *mut MinusDi {
match MinusDi::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_minus_di_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_minus_di_update(
handle: *mut MinusDi,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_minus_di_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_minus_di_batch(
handle: *mut MinusDi,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_minus_di_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_minus_di_reset(handle: *mut MinusDi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_minus_di_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_minus_di_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_minus_di_free(handle: *mut MinusDi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MinusDm` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_minus_dm_free`.
#[no_mangle]
pub extern "C" fn wickra_minus_dm_new(period: usize) -> *mut MinusDm {
match MinusDm::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_minus_dm_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_minus_dm_update(
handle: *mut MinusDm,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_minus_dm_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_minus_dm_batch(
handle: *mut MinusDm,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_minus_dm_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_minus_dm_reset(handle: *mut MinusDm) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_minus_dm_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_minus_dm_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_minus_dm_free(handle: *mut MinusDm) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MorningDojiStar` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_morning_doji_star_free`.
#[no_mangle]
pub extern "C" fn wickra_morning_doji_star_new() -> *mut MorningDojiStar {
Box::into_raw(Box::new(MorningDojiStar::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_morning_doji_star_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_morning_doji_star_update(
handle: *mut MorningDojiStar,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_morning_doji_star_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_morning_doji_star_batch(
handle: *mut MorningDojiStar,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_morning_doji_star_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_morning_doji_star_reset(handle: *mut MorningDojiStar) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_morning_doji_star_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_morning_doji_star_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_morning_doji_star_free(handle: *mut MorningDojiStar) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MorningEveningStar` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_morning_evening_star_free`.
#[no_mangle]
pub extern "C" fn wickra_morning_evening_star_new() -> *mut MorningEveningStar {
Box::into_raw(Box::new(MorningEveningStar::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_morning_evening_star_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_morning_evening_star_update(
handle: *mut MorningEveningStar,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_morning_evening_star_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_morning_evening_star_batch(
handle: *mut MorningEveningStar,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_morning_evening_star_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_morning_evening_star_reset(handle: *mut MorningEveningStar) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_morning_evening_star_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_morning_evening_star_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_morning_evening_star_free(handle: *mut MorningEveningStar) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `NakedPoc` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_naked_poc_free`.
#[no_mangle]
pub extern "C" fn wickra_naked_poc_new(session_len: usize, bins: usize) -> *mut NakedPoc {
match NakedPoc::new(session_len, bins) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_naked_poc_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_naked_poc_update(
handle: *mut NakedPoc,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_naked_poc_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_naked_poc_batch(
handle: *mut NakedPoc,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_naked_poc_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_naked_poc_reset(handle: *mut NakedPoc) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_naked_poc_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_naked_poc_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_naked_poc_free(handle: *mut NakedPoc) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Natr` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_natr_free`.
#[no_mangle]
pub extern "C" fn wickra_natr_new(period: usize) -> *mut Natr {
match Natr::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_natr_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_natr_update(
handle: *mut Natr,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_natr_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_natr_batch(
handle: *mut Natr,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_natr_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_natr_reset(handle: *mut Natr) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_natr_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_natr_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_natr_free(handle: *mut Natr) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `NewPriceLines` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_new_price_lines_free`.
#[no_mangle]
pub extern "C" fn wickra_new_price_lines_new(count: usize) -> *mut NewPriceLines {
match NewPriceLines::new(count) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_new_price_lines_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_new_price_lines_update(
handle: *mut NewPriceLines,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_new_price_lines_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_new_price_lines_batch(
handle: *mut NewPriceLines,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_new_price_lines_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_new_price_lines_reset(handle: *mut NewPriceLines) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_new_price_lines_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_new_price_lines_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_new_price_lines_free(handle: *mut NewPriceLines) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Nvi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_nvi_free`.
#[no_mangle]
pub extern "C" fn wickra_nvi_new() -> *mut Nvi {
Box::into_raw(Box::new(Nvi::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_nvi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_nvi_update(
handle: *mut Nvi,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_nvi_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_nvi_batch(
handle: *mut Nvi,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_nvi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_nvi_reset(handle: *mut Nvi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_nvi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_nvi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_nvi_free(handle: *mut Nvi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Obv` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_obv_free`.
#[no_mangle]
pub extern "C" fn wickra_obv_new() -> *mut Obv {
Box::into_raw(Box::new(Obv::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_obv_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_obv_update(
handle: *mut Obv,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_obv_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_obv_batch(
handle: *mut Obv,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_obv_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_obv_reset(handle: *mut Obv) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_obv_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_obv_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_obv_free(handle: *mut Obv) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OnNeck` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_on_neck_free`.
#[no_mangle]
pub extern "C" fn wickra_on_neck_new() -> *mut OnNeck {
Box::into_raw(Box::new(OnNeck::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_on_neck_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_on_neck_update(
handle: *mut OnNeck,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_on_neck_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_on_neck_batch(
handle: *mut OnNeck,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_on_neck_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_on_neck_reset(handle: *mut OnNeck) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_on_neck_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_on_neck_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_on_neck_free(handle: *mut OnNeck) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OpeningMarubozu` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_opening_marubozu_free`.
#[no_mangle]
pub extern "C" fn wickra_opening_marubozu_new() -> *mut OpeningMarubozu {
Box::into_raw(Box::new(OpeningMarubozu::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_opening_marubozu_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_opening_marubozu_update(
handle: *mut OpeningMarubozu,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_opening_marubozu_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_opening_marubozu_batch(
handle: *mut OpeningMarubozu,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_opening_marubozu_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_opening_marubozu_reset(handle: *mut OpeningMarubozu) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_opening_marubozu_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_opening_marubozu_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_opening_marubozu_free(handle: *mut OpeningMarubozu) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OvernightGap` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_overnight_gap_free`.
#[no_mangle]
pub extern "C" fn wickra_overnight_gap_new(utc_offset_minutes: i32) -> *mut OvernightGap {
Box::into_raw(Box::new(OvernightGap::new(utc_offset_minutes)))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_overnight_gap_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_overnight_gap_update(
handle: *mut OvernightGap,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_overnight_gap_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_overnight_gap_batch(
handle: *mut OvernightGap,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_overnight_gap_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_overnight_gap_reset(handle: *mut OvernightGap) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_overnight_gap_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_overnight_gap_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_overnight_gap_free(handle: *mut OvernightGap) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ParkinsonVolatility` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_parkinson_volatility_free`.
#[no_mangle]
pub extern "C" fn wickra_parkinson_volatility_new(
period: usize,
trading_periods: usize,
) -> *mut ParkinsonVolatility {
match ParkinsonVolatility::new(period, trading_periods) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_parkinson_volatility_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_parkinson_volatility_update(
handle: *mut ParkinsonVolatility,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_parkinson_volatility_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_parkinson_volatility_batch(
handle: *mut ParkinsonVolatility,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_parkinson_volatility_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_parkinson_volatility_reset(handle: *mut ParkinsonVolatility) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_parkinson_volatility_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_parkinson_volatility_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_parkinson_volatility_free(handle: *mut ParkinsonVolatility) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Pgo` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_pgo_free`.
#[no_mangle]
pub extern "C" fn wickra_pgo_new(period: usize) -> *mut Pgo {
match Pgo::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_pgo_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pgo_update(
handle: *mut Pgo,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_pgo_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_pgo_batch(
handle: *mut Pgo,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_pgo_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pgo_reset(handle: *mut Pgo) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_pgo_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_pgo_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pgo_free(handle: *mut Pgo) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PiercingDarkCloud` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_piercing_dark_cloud_free`.
#[no_mangle]
pub extern "C" fn wickra_piercing_dark_cloud_new() -> *mut PiercingDarkCloud {
Box::into_raw(Box::new(PiercingDarkCloud::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_piercing_dark_cloud_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_piercing_dark_cloud_update(
handle: *mut PiercingDarkCloud,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_piercing_dark_cloud_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_piercing_dark_cloud_batch(
handle: *mut PiercingDarkCloud,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_piercing_dark_cloud_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_piercing_dark_cloud_reset(handle: *mut PiercingDarkCloud) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_piercing_dark_cloud_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_piercing_dark_cloud_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_piercing_dark_cloud_free(handle: *mut PiercingDarkCloud) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PivotReversal` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_pivot_reversal_free`.
#[no_mangle]
pub extern "C" fn wickra_pivot_reversal_new(left: usize, right: usize) -> *mut PivotReversal {
match PivotReversal::new(left, right) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_pivot_reversal_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pivot_reversal_update(
handle: *mut PivotReversal,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_pivot_reversal_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_pivot_reversal_batch(
handle: *mut PivotReversal,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_pivot_reversal_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pivot_reversal_reset(handle: *mut PivotReversal) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_pivot_reversal_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_pivot_reversal_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pivot_reversal_free(handle: *mut PivotReversal) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PlusDi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_plus_di_free`.
#[no_mangle]
pub extern "C" fn wickra_plus_di_new(period: usize) -> *mut PlusDi {
match PlusDi::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_plus_di_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_plus_di_update(
handle: *mut PlusDi,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_plus_di_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_plus_di_batch(
handle: *mut PlusDi,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_plus_di_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_plus_di_reset(handle: *mut PlusDi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_plus_di_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_plus_di_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_plus_di_free(handle: *mut PlusDi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PlusDm` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_plus_dm_free`.
#[no_mangle]
pub extern "C" fn wickra_plus_dm_new(period: usize) -> *mut PlusDm {
match PlusDm::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_plus_dm_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_plus_dm_update(
handle: *mut PlusDm,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_plus_dm_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_plus_dm_batch(
handle: *mut PlusDm,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_plus_dm_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_plus_dm_reset(handle: *mut PlusDm) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_plus_dm_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_plus_dm_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_plus_dm_free(handle: *mut PlusDm) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ProfileShape` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_profile_shape_free`.
#[no_mangle]
pub extern "C" fn wickra_profile_shape_new(period: usize, bins: usize) -> *mut ProfileShape {
match ProfileShape::new(period, bins) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_profile_shape_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_profile_shape_update(
handle: *mut ProfileShape,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_profile_shape_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_profile_shape_batch(
handle: *mut ProfileShape,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_profile_shape_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_profile_shape_reset(handle: *mut ProfileShape) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_profile_shape_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_profile_shape_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_profile_shape_free(handle: *mut ProfileShape) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ProjectionOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_projection_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_projection_oscillator_new(period: usize) -> *mut ProjectionOscillator {
match ProjectionOscillator::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_projection_oscillator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_projection_oscillator_update(
handle: *mut ProjectionOscillator,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_projection_oscillator_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_projection_oscillator_batch(
handle: *mut ProjectionOscillator,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_projection_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_projection_oscillator_reset(handle: *mut ProjectionOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_projection_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_projection_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_projection_oscillator_free(handle: *mut ProjectionOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Psar` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_psar_free`.
#[no_mangle]
pub extern "C" fn wickra_psar_new(af_start: f64, af_step: f64, af_max: f64) -> *mut Psar {
match Psar::new(af_start, af_step, af_max) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_psar_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_psar_update(
handle: *mut Psar,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_psar_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_psar_batch(
handle: *mut Psar,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_psar_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_psar_reset(handle: *mut Psar) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_psar_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_psar_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_psar_free(handle: *mut Psar) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Pvi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_pvi_free`.
#[no_mangle]
pub extern "C" fn wickra_pvi_new() -> *mut Pvi {
Box::into_raw(Box::new(Pvi::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_pvi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pvi_update(
handle: *mut Pvi,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_pvi_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_pvi_batch(
handle: *mut Pvi,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_pvi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pvi_reset(handle: *mut Pvi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_pvi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_pvi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pvi_free(handle: *mut Pvi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Qstick` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_qstick_free`.
#[no_mangle]
pub extern "C" fn wickra_qstick_new(period: usize) -> *mut Qstick {
match Qstick::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_qstick_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_qstick_update(
handle: *mut Qstick,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_qstick_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_qstick_batch(
handle: *mut Qstick,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_qstick_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_qstick_reset(handle: *mut Qstick) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_qstick_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_qstick_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_qstick_free(handle: *mut Qstick) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RectangleRange` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rectangle_range_free`.
#[no_mangle]
pub extern "C" fn wickra_rectangle_range_new() -> *mut RectangleRange {
Box::into_raw(Box::new(RectangleRange::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rectangle_range_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rectangle_range_update(
handle: *mut RectangleRange,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_rectangle_range_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_rectangle_range_batch(
handle: *mut RectangleRange,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rectangle_range_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rectangle_range_reset(handle: *mut RectangleRange) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rectangle_range_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rectangle_range_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rectangle_range_free(handle: *mut RectangleRange) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RickshawMan` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rickshaw_man_free`.
#[no_mangle]
pub extern "C" fn wickra_rickshaw_man_new() -> *mut RickshawMan {
Box::into_raw(Box::new(RickshawMan::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rickshaw_man_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rickshaw_man_update(
handle: *mut RickshawMan,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_rickshaw_man_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_rickshaw_man_batch(
handle: *mut RickshawMan,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rickshaw_man_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rickshaw_man_reset(handle: *mut RickshawMan) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rickshaw_man_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rickshaw_man_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rickshaw_man_free(handle: *mut RickshawMan) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RisingThreeMethods` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rising_three_methods_free`.
#[no_mangle]
pub extern "C" fn wickra_rising_three_methods_new() -> *mut RisingThreeMethods {
Box::into_raw(Box::new(RisingThreeMethods::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rising_three_methods_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rising_three_methods_update(
handle: *mut RisingThreeMethods,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_rising_three_methods_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_rising_three_methods_batch(
handle: *mut RisingThreeMethods,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rising_three_methods_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rising_three_methods_reset(handle: *mut RisingThreeMethods) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rising_three_methods_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rising_three_methods_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rising_three_methods_free(handle: *mut RisingThreeMethods) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RogersSatchellVolatility` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rogers_satchell_volatility_free`.
#[no_mangle]
pub extern "C" fn wickra_rogers_satchell_volatility_new(
period: usize,
trading_periods: usize,
) -> *mut RogersSatchellVolatility {
match RogersSatchellVolatility::new(period, trading_periods) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rogers_satchell_volatility_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rogers_satchell_volatility_update(
handle: *mut RogersSatchellVolatility,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_rogers_satchell_volatility_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_rogers_satchell_volatility_batch(
handle: *mut RogersSatchellVolatility,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rogers_satchell_volatility_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rogers_satchell_volatility_reset(
handle: *mut RogersSatchellVolatility,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rogers_satchell_volatility_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rogers_satchell_volatility_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rogers_satchell_volatility_free(
handle: *mut RogersSatchellVolatility,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Rvi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rvi_free`.
#[no_mangle]
pub extern "C" fn wickra_rvi_new(period: usize) -> *mut Rvi {
match Rvi::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rvi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rvi_update(
handle: *mut Rvi,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_rvi_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_rvi_batch(
handle: *mut Rvi,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rvi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rvi_reset(handle: *mut Rvi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rvi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rvi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rvi_free(handle: *mut Rvi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SarExt` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_sar_ext_free`.
#[no_mangle]
pub extern "C" fn wickra_sar_ext_new(
start_value: f64,
offset_on_reverse: f64,
accel_init_long: f64,
accel_long: f64,
accel_max_long: f64,
accel_init_short: f64,
accel_short: f64,
accel_max_short: f64,
) -> *mut SarExt {
match SarExt::new(
start_value,
offset_on_reverse,
accel_init_long,
accel_long,
accel_max_long,
accel_init_short,
accel_short,
accel_max_short,
) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_sar_ext_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sar_ext_update(
handle: *mut SarExt,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_sar_ext_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_sar_ext_batch(
handle: *mut SarExt,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_sar_ext_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sar_ext_reset(handle: *mut SarExt) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_sar_ext_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_sar_ext_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_sar_ext_free(handle: *mut SarExt) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SeasonalZScore` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_seasonal_z_score_free`.
#[no_mangle]
pub extern "C" fn wickra_seasonal_z_score_new(utc_offset_minutes: i32) -> *mut SeasonalZScore {
Box::into_raw(Box::new(SeasonalZScore::new(utc_offset_minutes)))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_seasonal_z_score_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_seasonal_z_score_update(
handle: *mut SeasonalZScore,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_seasonal_z_score_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_seasonal_z_score_batch(
handle: *mut SeasonalZScore,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_seasonal_z_score_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_seasonal_z_score_reset(handle: *mut SeasonalZScore) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_seasonal_z_score_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_seasonal_z_score_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_seasonal_z_score_free(handle: *mut SeasonalZScore) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SeparatingLines` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_separating_lines_free`.
#[no_mangle]
pub extern "C" fn wickra_separating_lines_new() -> *mut SeparatingLines {
Box::into_raw(Box::new(SeparatingLines::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_separating_lines_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_separating_lines_update(
handle: *mut SeparatingLines,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_separating_lines_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_separating_lines_batch(
handle: *mut SeparatingLines,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_separating_lines_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_separating_lines_reset(handle: *mut SeparatingLines) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_separating_lines_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_separating_lines_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_separating_lines_free(handle: *mut SeparatingLines) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SessionVwap` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_session_vwap_free`.
#[no_mangle]
pub extern "C" fn wickra_session_vwap_new(utc_offset_minutes: i32) -> *mut SessionVwap {
Box::into_raw(Box::new(SessionVwap::new(utc_offset_minutes)))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_session_vwap_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_session_vwap_update(
handle: *mut SessionVwap,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_session_vwap_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_session_vwap_batch(
handle: *mut SessionVwap,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_session_vwap_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_session_vwap_reset(handle: *mut SessionVwap) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_session_vwap_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_session_vwap_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_session_vwap_free(handle: *mut SessionVwap) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Shark` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_shark_free`.
#[no_mangle]
pub extern "C" fn wickra_shark_new() -> *mut Shark {
Box::into_raw(Box::new(Shark::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_shark_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_shark_update(
handle: *mut Shark,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_shark_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_shark_batch(
handle: *mut Shark,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_shark_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_shark_reset(handle: *mut Shark) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_shark_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_shark_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_shark_free(handle: *mut Shark) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ShootingStar` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_shooting_star_free`.
#[no_mangle]
pub extern "C" fn wickra_shooting_star_new() -> *mut ShootingStar {
Box::into_raw(Box::new(ShootingStar::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_shooting_star_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_shooting_star_update(
handle: *mut ShootingStar,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_shooting_star_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_shooting_star_batch(
handle: *mut ShootingStar,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_shooting_star_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_shooting_star_reset(handle: *mut ShootingStar) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_shooting_star_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_shooting_star_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_shooting_star_free(handle: *mut ShootingStar) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ShortLine` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_short_line_free`.
#[no_mangle]
pub extern "C" fn wickra_short_line_new() -> *mut ShortLine {
Box::into_raw(Box::new(ShortLine::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_short_line_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_short_line_update(
handle: *mut ShortLine,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_short_line_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_short_line_batch(
handle: *mut ShortLine,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_short_line_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_short_line_reset(handle: *mut ShortLine) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_short_line_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_short_line_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_short_line_free(handle: *mut ShortLine) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SinglePrints` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_single_prints_free`.
#[no_mangle]
pub extern "C" fn wickra_single_prints_new(period: usize, bins: usize) -> *mut SinglePrints {
match SinglePrints::new(period, bins) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_single_prints_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_single_prints_update(
handle: *mut SinglePrints,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_single_prints_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_single_prints_batch(
handle: *mut SinglePrints,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_single_prints_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_single_prints_reset(handle: *mut SinglePrints) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_single_prints_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_single_prints_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_single_prints_free(handle: *mut SinglePrints) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Smi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_smi_free`.
#[no_mangle]
pub extern "C" fn wickra_smi_new(period: usize, d_period: usize, d2_period: usize) -> *mut Smi {
match Smi::new(period, d_period, d2_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_smi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_smi_update(
handle: *mut Smi,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_smi_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_smi_batch(
handle: *mut Smi,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_smi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_smi_reset(handle: *mut Smi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_smi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_smi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_smi_free(handle: *mut Smi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SpinningTop` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_spinning_top_free`.
#[no_mangle]
pub extern "C" fn wickra_spinning_top_new() -> *mut SpinningTop {
Box::into_raw(Box::new(SpinningTop::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_spinning_top_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spinning_top_update(
handle: *mut SpinningTop,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_spinning_top_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_spinning_top_batch(
handle: *mut SpinningTop,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_spinning_top_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spinning_top_reset(handle: *mut SpinningTop) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_spinning_top_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_spinning_top_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spinning_top_free(handle: *mut SpinningTop) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `StalledPattern` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_stalled_pattern_free`.
#[no_mangle]
pub extern "C" fn wickra_stalled_pattern_new() -> *mut StalledPattern {
Box::into_raw(Box::new(StalledPattern::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_stalled_pattern_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stalled_pattern_update(
handle: *mut StalledPattern,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_stalled_pattern_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_stalled_pattern_batch(
handle: *mut StalledPattern,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_stalled_pattern_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stalled_pattern_reset(handle: *mut StalledPattern) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_stalled_pattern_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_stalled_pattern_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stalled_pattern_free(handle: *mut StalledPattern) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `StickSandwich` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_stick_sandwich_free`.
#[no_mangle]
pub extern "C" fn wickra_stick_sandwich_new() -> *mut StickSandwich {
Box::into_raw(Box::new(StickSandwich::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_stick_sandwich_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stick_sandwich_update(
handle: *mut StickSandwich,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_stick_sandwich_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_stick_sandwich_batch(
handle: *mut StickSandwich,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_stick_sandwich_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stick_sandwich_reset(handle: *mut StickSandwich) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_stick_sandwich_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_stick_sandwich_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stick_sandwich_free(handle: *mut StickSandwich) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `StochasticCci` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_stochastic_cci_free`.
#[no_mangle]
pub extern "C" fn wickra_stochastic_cci_new(period: usize) -> *mut StochasticCci {
match StochasticCci::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_stochastic_cci_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stochastic_cci_update(
handle: *mut StochasticCci,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_stochastic_cci_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_stochastic_cci_batch(
handle: *mut StochasticCci,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_stochastic_cci_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stochastic_cci_reset(handle: *mut StochasticCci) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_stochastic_cci_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_stochastic_cci_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stochastic_cci_free(handle: *mut StochasticCci) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Takuri` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_takuri_free`.
#[no_mangle]
pub extern "C" fn wickra_takuri_new() -> *mut Takuri {
Box::into_raw(Box::new(Takuri::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_takuri_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_takuri_update(
handle: *mut Takuri,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_takuri_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_takuri_batch(
handle: *mut Takuri,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_takuri_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_takuri_reset(handle: *mut Takuri) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_takuri_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_takuri_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_takuri_free(handle: *mut Takuri) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TasukiGap` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_tasuki_gap_free`.
#[no_mangle]
pub extern "C" fn wickra_tasuki_gap_new() -> *mut TasukiGap {
Box::into_raw(Box::new(TasukiGap::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_tasuki_gap_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tasuki_gap_update(
handle: *mut TasukiGap,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_tasuki_gap_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_tasuki_gap_batch(
handle: *mut TasukiGap,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_tasuki_gap_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tasuki_gap_reset(handle: *mut TasukiGap) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_tasuki_gap_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_tasuki_gap_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tasuki_gap_free(handle: *mut TasukiGap) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdCamouflage` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_camouflage_free`.
#[no_mangle]
pub extern "C" fn wickra_td_camouflage_new() -> *mut TdCamouflage {
Box::into_raw(Box::new(TdCamouflage::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_td_camouflage_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_camouflage_update(
handle: *mut TdCamouflage,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_td_camouflage_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_camouflage_batch(
handle: *mut TdCamouflage,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_camouflage_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_camouflage_reset(handle: *mut TdCamouflage) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_camouflage_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_camouflage_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_camouflage_free(handle: *mut TdCamouflage) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdClop` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_clop_free`.
#[no_mangle]
pub extern "C" fn wickra_td_clop_new() -> *mut TdClop {
Box::into_raw(Box::new(TdClop::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_td_clop_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_clop_update(
handle: *mut TdClop,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_td_clop_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_clop_batch(
handle: *mut TdClop,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_clop_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_clop_reset(handle: *mut TdClop) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_clop_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_clop_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_clop_free(handle: *mut TdClop) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdClopwin` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_clopwin_free`.
#[no_mangle]
pub extern "C" fn wickra_td_clopwin_new() -> *mut TdClopwin {
Box::into_raw(Box::new(TdClopwin::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_td_clopwin_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_clopwin_update(
handle: *mut TdClopwin,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_td_clopwin_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_clopwin_batch(
handle: *mut TdClopwin,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_clopwin_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_clopwin_reset(handle: *mut TdClopwin) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_clopwin_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_clopwin_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_clopwin_free(handle: *mut TdClopwin) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdCombo` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_combo_free`.
#[no_mangle]
pub extern "C" fn wickra_td_combo_new(
setup_lookback: usize,
setup_target: usize,
countdown_lookback: usize,
countdown_target: usize,
) -> *mut TdCombo {
match TdCombo::new(
setup_lookback,
setup_target,
countdown_lookback,
countdown_target,
) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_td_combo_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_combo_update(
handle: *mut TdCombo,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_td_combo_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_combo_batch(
handle: *mut TdCombo,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_combo_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_combo_reset(handle: *mut TdCombo) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_combo_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_combo_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_combo_free(handle: *mut TdCombo) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdCountdown` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_countdown_free`.
#[no_mangle]
pub extern "C" fn wickra_td_countdown_new(
setup_lookback: usize,
setup_target: usize,
countdown_lookback: usize,
countdown_target: usize,
) -> *mut TdCountdown {
match TdCountdown::new(
setup_lookback,
setup_target,
countdown_lookback,
countdown_target,
) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_td_countdown_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_countdown_update(
handle: *mut TdCountdown,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_td_countdown_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_countdown_batch(
handle: *mut TdCountdown,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_countdown_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_countdown_reset(handle: *mut TdCountdown) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_countdown_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_countdown_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_countdown_free(handle: *mut TdCountdown) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdDeMarker` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_de_marker_free`.
#[no_mangle]
pub extern "C" fn wickra_td_de_marker_new(period: usize) -> *mut TdDeMarker {
match TdDeMarker::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_td_de_marker_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_de_marker_update(
handle: *mut TdDeMarker,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_td_de_marker_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_de_marker_batch(
handle: *mut TdDeMarker,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_de_marker_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_de_marker_reset(handle: *mut TdDeMarker) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_de_marker_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_de_marker_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_de_marker_free(handle: *mut TdDeMarker) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdDifferential` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_differential_free`.
#[no_mangle]
pub extern "C" fn wickra_td_differential_new() -> *mut TdDifferential {
Box::into_raw(Box::new(TdDifferential::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_td_differential_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_differential_update(
handle: *mut TdDifferential,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_td_differential_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_differential_batch(
handle: *mut TdDifferential,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_differential_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_differential_reset(handle: *mut TdDifferential) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_differential_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_differential_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_differential_free(handle: *mut TdDifferential) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdDWave` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_d_wave_free`.
#[no_mangle]
pub extern "C" fn wickra_td_d_wave_new(strength: usize) -> *mut TdDWave {
match TdDWave::new(strength) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_td_d_wave_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_d_wave_update(
handle: *mut TdDWave,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_td_d_wave_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_d_wave_batch(
handle: *mut TdDWave,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_d_wave_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_d_wave_reset(handle: *mut TdDWave) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_d_wave_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_d_wave_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_d_wave_free(handle: *mut TdDWave) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdOpen` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_open_free`.
#[no_mangle]
pub extern "C" fn wickra_td_open_new() -> *mut TdOpen {
Box::into_raw(Box::new(TdOpen::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_td_open_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_open_update(
handle: *mut TdOpen,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_td_open_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_open_batch(
handle: *mut TdOpen,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_open_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_open_reset(handle: *mut TdOpen) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_open_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_open_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_open_free(handle: *mut TdOpen) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdPressure` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_pressure_free`.
#[no_mangle]
pub extern "C" fn wickra_td_pressure_new(period: usize) -> *mut TdPressure {
match TdPressure::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_td_pressure_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_pressure_update(
handle: *mut TdPressure,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_td_pressure_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_pressure_batch(
handle: *mut TdPressure,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_pressure_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_pressure_reset(handle: *mut TdPressure) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_pressure_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_pressure_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_pressure_free(handle: *mut TdPressure) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdPropulsion` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_propulsion_free`.
#[no_mangle]
pub extern "C" fn wickra_td_propulsion_new() -> *mut TdPropulsion {
Box::into_raw(Box::new(TdPropulsion::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_td_propulsion_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_propulsion_update(
handle: *mut TdPropulsion,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_td_propulsion_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_propulsion_batch(
handle: *mut TdPropulsion,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_propulsion_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_propulsion_reset(handle: *mut TdPropulsion) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_propulsion_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_propulsion_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_propulsion_free(handle: *mut TdPropulsion) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdRei` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_rei_free`.
#[no_mangle]
pub extern "C" fn wickra_td_rei_new(period: usize) -> *mut TdRei {
match TdRei::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_td_rei_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_rei_update(
handle: *mut TdRei,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_td_rei_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_rei_batch(
handle: *mut TdRei,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_rei_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_rei_reset(handle: *mut TdRei) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_rei_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_rei_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_rei_free(handle: *mut TdRei) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdSetup` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_setup_free`.
#[no_mangle]
pub extern "C" fn wickra_td_setup_new(lookback: usize, target: usize) -> *mut TdSetup {
match TdSetup::new(lookback, target) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_td_setup_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_setup_update(
handle: *mut TdSetup,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_td_setup_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_setup_batch(
handle: *mut TdSetup,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_setup_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_setup_reset(handle: *mut TdSetup) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_setup_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_setup_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_setup_free(handle: *mut TdSetup) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdTrap` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_trap_free`.
#[no_mangle]
pub extern "C" fn wickra_td_trap_new() -> *mut TdTrap {
Box::into_raw(Box::new(TdTrap::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_td_trap_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_trap_update(
handle: *mut TdTrap,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_td_trap_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_trap_batch(
handle: *mut TdTrap,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_trap_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_trap_reset(handle: *mut TdTrap) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_trap_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_trap_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_trap_free(handle: *mut TdTrap) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ThreeDrives` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_three_drives_free`.
#[no_mangle]
pub extern "C" fn wickra_three_drives_new() -> *mut ThreeDrives {
Box::into_raw(Box::new(ThreeDrives::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_three_drives_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_drives_update(
handle: *mut ThreeDrives,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_three_drives_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_drives_batch(
handle: *mut ThreeDrives,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_three_drives_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_drives_reset(handle: *mut ThreeDrives) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_three_drives_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_three_drives_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_drives_free(handle: *mut ThreeDrives) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ThreeInside` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_three_inside_free`.
#[no_mangle]
pub extern "C" fn wickra_three_inside_new() -> *mut ThreeInside {
Box::into_raw(Box::new(ThreeInside::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_three_inside_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_inside_update(
handle: *mut ThreeInside,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_three_inside_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_inside_batch(
handle: *mut ThreeInside,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_three_inside_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_inside_reset(handle: *mut ThreeInside) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_three_inside_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_three_inside_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_inside_free(handle: *mut ThreeInside) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ThreeLineBreak` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_three_line_break_free`.
#[no_mangle]
pub extern "C" fn wickra_three_line_break_new(lines: usize) -> *mut ThreeLineBreak {
match ThreeLineBreak::new(lines) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_three_line_break_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_line_break_update(
handle: *mut ThreeLineBreak,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_three_line_break_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_line_break_batch(
handle: *mut ThreeLineBreak,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_three_line_break_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_line_break_reset(handle: *mut ThreeLineBreak) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_three_line_break_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_three_line_break_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_line_break_free(handle: *mut ThreeLineBreak) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ThreeLineStrike` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_three_line_strike_free`.
#[no_mangle]
pub extern "C" fn wickra_three_line_strike_new() -> *mut ThreeLineStrike {
Box::into_raw(Box::new(ThreeLineStrike::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_three_line_strike_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_line_strike_update(
handle: *mut ThreeLineStrike,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_three_line_strike_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_line_strike_batch(
handle: *mut ThreeLineStrike,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_three_line_strike_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_line_strike_reset(handle: *mut ThreeLineStrike) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_three_line_strike_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_three_line_strike_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_line_strike_free(handle: *mut ThreeLineStrike) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ThreeOutside` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_three_outside_free`.
#[no_mangle]
pub extern "C" fn wickra_three_outside_new() -> *mut ThreeOutside {
Box::into_raw(Box::new(ThreeOutside::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_three_outside_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_outside_update(
handle: *mut ThreeOutside,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_three_outside_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_outside_batch(
handle: *mut ThreeOutside,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_three_outside_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_outside_reset(handle: *mut ThreeOutside) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_three_outside_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_three_outside_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_outside_free(handle: *mut ThreeOutside) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ThreeSoldiersOrCrows` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_three_soldiers_or_crows_free`.
#[no_mangle]
pub extern "C" fn wickra_three_soldiers_or_crows_new() -> *mut ThreeSoldiersOrCrows {
Box::into_raw(Box::new(ThreeSoldiersOrCrows::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_three_soldiers_or_crows_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_soldiers_or_crows_update(
handle: *mut ThreeSoldiersOrCrows,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_three_soldiers_or_crows_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_soldiers_or_crows_batch(
handle: *mut ThreeSoldiersOrCrows,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_three_soldiers_or_crows_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_soldiers_or_crows_reset(handle: *mut ThreeSoldiersOrCrows) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_three_soldiers_or_crows_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_three_soldiers_or_crows_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_soldiers_or_crows_free(handle: *mut ThreeSoldiersOrCrows) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ThreeStarsInSouth` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_three_stars_in_south_free`.
#[no_mangle]
pub extern "C" fn wickra_three_stars_in_south_new() -> *mut ThreeStarsInSouth {
Box::into_raw(Box::new(ThreeStarsInSouth::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_three_stars_in_south_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_stars_in_south_update(
handle: *mut ThreeStarsInSouth,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_three_stars_in_south_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_stars_in_south_batch(
handle: *mut ThreeStarsInSouth,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_three_stars_in_south_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_stars_in_south_reset(handle: *mut ThreeStarsInSouth) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_three_stars_in_south_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_three_stars_in_south_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_stars_in_south_free(handle: *mut ThreeStarsInSouth) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Thrusting` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_thrusting_free`.
#[no_mangle]
pub extern "C" fn wickra_thrusting_new() -> *mut Thrusting {
Box::into_raw(Box::new(Thrusting::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_thrusting_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_thrusting_update(
handle: *mut Thrusting,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_thrusting_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_thrusting_batch(
handle: *mut Thrusting,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_thrusting_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_thrusting_reset(handle: *mut Thrusting) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_thrusting_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_thrusting_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_thrusting_free(handle: *mut Thrusting) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TimeBasedStop` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_time_based_stop_free`.
#[no_mangle]
pub extern "C" fn wickra_time_based_stop_new(max_bars: usize) -> *mut TimeBasedStop {
match TimeBasedStop::new(max_bars) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_time_based_stop_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_time_based_stop_update(
handle: *mut TimeBasedStop,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_time_based_stop_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_time_based_stop_batch(
handle: *mut TimeBasedStop,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_time_based_stop_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_time_based_stop_reset(handle: *mut TimeBasedStop) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_time_based_stop_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_time_based_stop_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_time_based_stop_free(handle: *mut TimeBasedStop) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TowerTopBottom` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_tower_top_bottom_free`.
#[no_mangle]
pub extern "C" fn wickra_tower_top_bottom_new() -> *mut TowerTopBottom {
Box::into_raw(Box::new(TowerTopBottom::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_tower_top_bottom_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tower_top_bottom_update(
handle: *mut TowerTopBottom,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_tower_top_bottom_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_tower_top_bottom_batch(
handle: *mut TowerTopBottom,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_tower_top_bottom_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tower_top_bottom_reset(handle: *mut TowerTopBottom) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_tower_top_bottom_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_tower_top_bottom_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tower_top_bottom_free(handle: *mut TowerTopBottom) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TradeVolumeIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_trade_volume_index_free`.
#[no_mangle]
pub extern "C" fn wickra_trade_volume_index_new(min_tick: f64) -> *mut TradeVolumeIndex {
match TradeVolumeIndex::new(min_tick) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_trade_volume_index_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trade_volume_index_update(
handle: *mut TradeVolumeIndex,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_trade_volume_index_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_trade_volume_index_batch(
handle: *mut TradeVolumeIndex,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_trade_volume_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trade_volume_index_reset(handle: *mut TradeVolumeIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_trade_volume_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_trade_volume_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trade_volume_index_free(handle: *mut TradeVolumeIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Triangle` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_triangle_free`.
#[no_mangle]
pub extern "C" fn wickra_triangle_new() -> *mut Triangle {
Box::into_raw(Box::new(Triangle::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_triangle_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_triangle_update(
handle: *mut Triangle,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_triangle_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_triangle_batch(
handle: *mut Triangle,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_triangle_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_triangle_reset(handle: *mut Triangle) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_triangle_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_triangle_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_triangle_free(handle: *mut Triangle) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TripleTopBottom` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_triple_top_bottom_free`.
#[no_mangle]
pub extern "C" fn wickra_triple_top_bottom_new() -> *mut TripleTopBottom {
Box::into_raw(Box::new(TripleTopBottom::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_triple_top_bottom_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_triple_top_bottom_update(
handle: *mut TripleTopBottom,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_triple_top_bottom_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_triple_top_bottom_batch(
handle: *mut TripleTopBottom,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_triple_top_bottom_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_triple_top_bottom_reset(handle: *mut TripleTopBottom) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_triple_top_bottom_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_triple_top_bottom_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_triple_top_bottom_free(handle: *mut TripleTopBottom) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Tristar` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_tristar_free`.
#[no_mangle]
pub extern "C" fn wickra_tristar_new() -> *mut Tristar {
Box::into_raw(Box::new(Tristar::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_tristar_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tristar_update(
handle: *mut Tristar,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_tristar_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_tristar_batch(
handle: *mut Tristar,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_tristar_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tristar_reset(handle: *mut Tristar) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_tristar_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_tristar_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tristar_free(handle: *mut Tristar) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TrueRange` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_true_range_free`.
#[no_mangle]
pub extern "C" fn wickra_true_range_new() -> *mut TrueRange {
Box::into_raw(Box::new(TrueRange::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_true_range_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_true_range_update(
handle: *mut TrueRange,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_true_range_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_true_range_batch(
handle: *mut TrueRange,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_true_range_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_true_range_reset(handle: *mut TrueRange) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_true_range_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_true_range_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_true_range_free(handle: *mut TrueRange) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Tsv` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_tsv_free`.
#[no_mangle]
pub extern "C" fn wickra_tsv_new(period: usize) -> *mut Tsv {
match Tsv::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_tsv_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsv_update(
handle: *mut Tsv,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_tsv_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsv_batch(
handle: *mut Tsv,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_tsv_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsv_reset(handle: *mut Tsv) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_tsv_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_tsv_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tsv_free(handle: *mut Tsv) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TtmTrend` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ttm_trend_free`.
#[no_mangle]
pub extern "C" fn wickra_ttm_trend_new(period: usize) -> *mut TtmTrend {
match TtmTrend::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ttm_trend_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ttm_trend_update(
handle: *mut TtmTrend,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_ttm_trend_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_ttm_trend_batch(
handle: *mut TtmTrend,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ttm_trend_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ttm_trend_reset(handle: *mut TtmTrend) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ttm_trend_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ttm_trend_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ttm_trend_free(handle: *mut TtmTrend) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TurnOfMonth` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_turn_of_month_free`.
#[no_mangle]
pub extern "C" fn wickra_turn_of_month_new(
n_first: u32,
n_last: u32,
utc_offset_minutes: i32,
) -> *mut TurnOfMonth {
match TurnOfMonth::new(n_first, n_last, utc_offset_minutes) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_turn_of_month_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_turn_of_month_update(
handle: *mut TurnOfMonth,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_turn_of_month_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_turn_of_month_batch(
handle: *mut TurnOfMonth,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_turn_of_month_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_turn_of_month_reset(handle: *mut TurnOfMonth) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_turn_of_month_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_turn_of_month_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_turn_of_month_free(handle: *mut TurnOfMonth) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Tweezer` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_tweezer_free`.
#[no_mangle]
pub extern "C" fn wickra_tweezer_new() -> *mut Tweezer {
Box::into_raw(Box::new(Tweezer::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_tweezer_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tweezer_update(
handle: *mut Tweezer,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_tweezer_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_tweezer_batch(
handle: *mut Tweezer,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_tweezer_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tweezer_reset(handle: *mut Tweezer) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_tweezer_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_tweezer_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tweezer_free(handle: *mut Tweezer) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TwiggsMoneyFlow` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_twiggs_money_flow_free`.
#[no_mangle]
pub extern "C" fn wickra_twiggs_money_flow_new(period: usize) -> *mut TwiggsMoneyFlow {
match TwiggsMoneyFlow::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_twiggs_money_flow_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_twiggs_money_flow_update(
handle: *mut TwiggsMoneyFlow,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_twiggs_money_flow_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_twiggs_money_flow_batch(
handle: *mut TwiggsMoneyFlow,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_twiggs_money_flow_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_twiggs_money_flow_reset(handle: *mut TwiggsMoneyFlow) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_twiggs_money_flow_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_twiggs_money_flow_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_twiggs_money_flow_free(handle: *mut TwiggsMoneyFlow) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TwoCrows` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_two_crows_free`.
#[no_mangle]
pub extern "C" fn wickra_two_crows_new() -> *mut TwoCrows {
Box::into_raw(Box::new(TwoCrows::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_two_crows_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_two_crows_update(
handle: *mut TwoCrows,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_two_crows_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_two_crows_batch(
handle: *mut TwoCrows,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_two_crows_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_two_crows_reset(handle: *mut TwoCrows) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_two_crows_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_two_crows_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_two_crows_free(handle: *mut TwoCrows) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TypicalPrice` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_typical_price_free`.
#[no_mangle]
pub extern "C" fn wickra_typical_price_new() -> *mut TypicalPrice {
Box::into_raw(Box::new(TypicalPrice::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_typical_price_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_typical_price_update(
handle: *mut TypicalPrice,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_typical_price_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_typical_price_batch(
handle: *mut TypicalPrice,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_typical_price_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_typical_price_reset(handle: *mut TypicalPrice) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_typical_price_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_typical_price_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_typical_price_free(handle: *mut TypicalPrice) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `UltimateOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ultimate_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_ultimate_oscillator_new(
short: usize,
mid: usize,
long: usize,
) -> *mut UltimateOscillator {
match UltimateOscillator::new(short, mid, long) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_ultimate_oscillator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ultimate_oscillator_update(
handle: *mut UltimateOscillator,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_ultimate_oscillator_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_ultimate_oscillator_batch(
handle: *mut UltimateOscillator,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ultimate_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ultimate_oscillator_reset(handle: *mut UltimateOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ultimate_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ultimate_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ultimate_oscillator_free(handle: *mut UltimateOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `UniqueThreeRiver` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_unique_three_river_free`.
#[no_mangle]
pub extern "C" fn wickra_unique_three_river_new() -> *mut UniqueThreeRiver {
Box::into_raw(Box::new(UniqueThreeRiver::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_unique_three_river_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_unique_three_river_update(
handle: *mut UniqueThreeRiver,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_unique_three_river_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_unique_three_river_batch(
handle: *mut UniqueThreeRiver,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_unique_three_river_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_unique_three_river_reset(handle: *mut UniqueThreeRiver) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_unique_three_river_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_unique_three_river_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_unique_three_river_free(handle: *mut UniqueThreeRiver) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `UpsideGapThreeMethods` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_upside_gap_three_methods_free`.
#[no_mangle]
pub extern "C" fn wickra_upside_gap_three_methods_new() -> *mut UpsideGapThreeMethods {
Box::into_raw(Box::new(UpsideGapThreeMethods::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_upside_gap_three_methods_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_upside_gap_three_methods_update(
handle: *mut UpsideGapThreeMethods,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_upside_gap_three_methods_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_upside_gap_three_methods_batch(
handle: *mut UpsideGapThreeMethods,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_upside_gap_three_methods_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_upside_gap_three_methods_reset(handle: *mut UpsideGapThreeMethods) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_upside_gap_three_methods_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_upside_gap_three_methods_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_upside_gap_three_methods_free(handle: *mut UpsideGapThreeMethods) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `UpsideGapTwoCrows` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_upside_gap_two_crows_free`.
#[no_mangle]
pub extern "C" fn wickra_upside_gap_two_crows_new() -> *mut UpsideGapTwoCrows {
Box::into_raw(Box::new(UpsideGapTwoCrows::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_upside_gap_two_crows_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_upside_gap_two_crows_update(
handle: *mut UpsideGapTwoCrows,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_upside_gap_two_crows_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_upside_gap_two_crows_batch(
handle: *mut UpsideGapTwoCrows,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_upside_gap_two_crows_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_upside_gap_two_crows_reset(handle: *mut UpsideGapTwoCrows) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_upside_gap_two_crows_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_upside_gap_two_crows_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_upside_gap_two_crows_free(handle: *mut UpsideGapTwoCrows) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VolatilityRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_volatility_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_volatility_ratio_new(period: usize) -> *mut VolatilityRatio {
match VolatilityRatio::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_volatility_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volatility_ratio_update(
handle: *mut VolatilityRatio,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_volatility_ratio_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_volatility_ratio_batch(
handle: *mut VolatilityRatio,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_volatility_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volatility_ratio_reset(handle: *mut VolatilityRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_volatility_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_volatility_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volatility_ratio_free(handle: *mut VolatilityRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VoltyStop` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_volty_stop_free`.
#[no_mangle]
pub extern "C" fn wickra_volty_stop_new(atr_period: usize, multiplier: f64) -> *mut VoltyStop {
match VoltyStop::new(atr_period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_volty_stop_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volty_stop_update(
handle: *mut VoltyStop,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_volty_stop_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_volty_stop_batch(
handle: *mut VoltyStop,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_volty_stop_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volty_stop_reset(handle: *mut VoltyStop) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_volty_stop_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_volty_stop_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volty_stop_free(handle: *mut VoltyStop) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VolumeOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_volume_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_volume_oscillator_new(fast: usize, slow: usize) -> *mut VolumeOscillator {
match VolumeOscillator::new(fast, slow) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_volume_oscillator_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_oscillator_update(
handle: *mut VolumeOscillator,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_volume_oscillator_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_oscillator_batch(
handle: *mut VolumeOscillator,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_volume_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_oscillator_reset(handle: *mut VolumeOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_volume_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_volume_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_oscillator_free(handle: *mut VolumeOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VolumeRsi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_volume_rsi_free`.
#[no_mangle]
pub extern "C" fn wickra_volume_rsi_new(period: usize) -> *mut VolumeRsi {
match VolumeRsi::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_volume_rsi_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_rsi_update(
handle: *mut VolumeRsi,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_volume_rsi_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_rsi_batch(
handle: *mut VolumeRsi,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_volume_rsi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_rsi_reset(handle: *mut VolumeRsi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_volume_rsi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_volume_rsi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_rsi_free(handle: *mut VolumeRsi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VolumePriceTrend` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_volume_price_trend_free`.
#[no_mangle]
pub extern "C" fn wickra_volume_price_trend_new() -> *mut VolumePriceTrend {
Box::into_raw(Box::new(VolumePriceTrend::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_volume_price_trend_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_price_trend_update(
handle: *mut VolumePriceTrend,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_volume_price_trend_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_price_trend_batch(
handle: *mut VolumePriceTrend,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_volume_price_trend_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_price_trend_reset(handle: *mut VolumePriceTrend) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_volume_price_trend_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_volume_price_trend_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_price_trend_free(handle: *mut VolumePriceTrend) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Vwap` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_vwap_free`.
#[no_mangle]
pub extern "C" fn wickra_vwap_new() -> *mut Vwap {
Box::into_raw(Box::new(Vwap::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_vwap_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vwap_update(
handle: *mut Vwap,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_vwap_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_vwap_batch(
handle: *mut Vwap,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_vwap_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vwap_reset(handle: *mut Vwap) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_vwap_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_vwap_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vwap_free(handle: *mut Vwap) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RollingVwap` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rolling_vwap_free`.
#[no_mangle]
pub extern "C" fn wickra_rolling_vwap_new(period: usize) -> *mut RollingVwap {
match RollingVwap::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_rolling_vwap_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_vwap_update(
handle: *mut RollingVwap,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_rolling_vwap_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_vwap_batch(
handle: *mut RollingVwap,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rolling_vwap_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_vwap_reset(handle: *mut RollingVwap) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rolling_vwap_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rolling_vwap_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rolling_vwap_free(handle: *mut RollingVwap) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Vwma` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_vwma_free`.
#[no_mangle]
pub extern "C" fn wickra_vwma_new(period: usize) -> *mut Vwma {
match Vwma::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_vwma_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vwma_update(
handle: *mut Vwma,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_vwma_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_vwma_batch(
handle: *mut Vwma,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_vwma_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vwma_reset(handle: *mut Vwma) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_vwma_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_vwma_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vwma_free(handle: *mut Vwma) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Vzo` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_vzo_free`.
#[no_mangle]
pub extern "C" fn wickra_vzo_new(period: usize) -> *mut Vzo {
match Vzo::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_vzo_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vzo_update(
handle: *mut Vzo,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_vzo_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_vzo_batch(
handle: *mut Vzo,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_vzo_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vzo_reset(handle: *mut Vzo) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_vzo_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_vzo_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vzo_free(handle: *mut Vzo) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Wad` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_wad_free`.
#[no_mangle]
pub extern "C" fn wickra_wad_new() -> *mut Wad {
Box::into_raw(Box::new(Wad::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_wad_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wad_update(
handle: *mut Wad,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_wad_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_wad_batch(
handle: *mut Wad,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_wad_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wad_reset(handle: *mut Wad) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_wad_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_wad_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wad_free(handle: *mut Wad) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Wedge` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_wedge_free`.
#[no_mangle]
pub extern "C" fn wickra_wedge_new() -> *mut Wedge {
Box::into_raw(Box::new(Wedge::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_wedge_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wedge_update(
handle: *mut Wedge,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_wedge_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_wedge_batch(
handle: *mut Wedge,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_wedge_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wedge_reset(handle: *mut Wedge) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_wedge_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_wedge_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wedge_free(handle: *mut Wedge) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `WeightedClose` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_weighted_close_free`.
#[no_mangle]
pub extern "C" fn wickra_weighted_close_new() -> *mut WeightedClose {
Box::into_raw(Box::new(WeightedClose::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_weighted_close_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_weighted_close_update(
handle: *mut WeightedClose,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_weighted_close_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_weighted_close_batch(
handle: *mut WeightedClose,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_weighted_close_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_weighted_close_reset(handle: *mut WeightedClose) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_weighted_close_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_weighted_close_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_weighted_close_free(handle: *mut WeightedClose) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `WickRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_wick_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_wick_ratio_new() -> *mut WickRatio {
Box::into_raw(Box::new(WickRatio::new()))
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_wick_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wick_ratio_update(
handle: *mut WickRatio,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_wick_ratio_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_wick_ratio_batch(
handle: *mut WickRatio,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_wick_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wick_ratio_reset(handle: *mut WickRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_wick_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_wick_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wick_ratio_free(handle: *mut WickRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `WilliamsR` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_williams_r_free`.
#[no_mangle]
pub extern "C" fn wickra_williams_r_new(period: usize) -> *mut WilliamsR {
match WilliamsR::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_williams_r_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_williams_r_update(
handle: *mut WilliamsR,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_williams_r_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_williams_r_batch(
handle: *mut WilliamsR,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_williams_r_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_williams_r_reset(handle: *mut WilliamsR) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_williams_r_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_williams_r_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_williams_r_free(handle: *mut WilliamsR) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `YangZhangVolatility` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_yang_zhang_volatility_free`.
#[no_mangle]
pub extern "C" fn wickra_yang_zhang_volatility_new(
period: usize,
trading_periods: usize,
) -> *mut YangZhangVolatility {
match YangZhangVolatility::new(period, trading_periods) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_yang_zhang_volatility_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_yang_zhang_volatility_update(
handle: *mut YangZhangVolatility,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_yang_zhang_volatility_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_yang_zhang_volatility_batch(
handle: *mut YangZhangVolatility,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_yang_zhang_volatility_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_yang_zhang_volatility_reset(handle: *mut YangZhangVolatility) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_yang_zhang_volatility_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_yang_zhang_volatility_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_yang_zhang_volatility_free(handle: *mut YangZhangVolatility) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `YoyoExit` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_yoyo_exit_free`.
#[no_mangle]
pub extern "C" fn wickra_yoyo_exit_new(atr_period: usize, multiplier: f64) -> *mut YoyoExit {
match YoyoExit::new(atr_period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; returns the output, or `NaN` during warmup / on a `NULL`
/// handle / if the candle is invalid (e.g. `high < low`).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_yoyo_exit_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_yoyo_exit_update(
handle: *mut YoyoExit,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match Candle::new(open, high, low, close, volume, timestamp) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Run over the OHLCV series (`open/high/low/close/volume/timestamp[0..n]`) into
/// `out[0..n]` (`NaN` at warmup or on an invalid candle).
///
/// # Safety
/// `handle` valid (from `wickra_yoyo_exit_new`, not freed); every input pointer and `out`
/// cover `n` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_yoyo_exit_batch(
handle: *mut YoyoExit,
open: *const f64,
high: *const f64,
low: *const f64,
close: *const f64,
volume: *const f64,
timestamp: *const i64,
out: *mut f64,
n: usize,
) {
if handle.is_null()
|| open.is_null()
|| high.is_null()
|| low.is_null()
|| close.is_null()
|| volume.is_null()
|| timestamp.is_null()
|| out.is_null()
{
return;
}
let ind = &mut *handle;
let opens = slice::from_raw_parts(open, n);
let highs = slice::from_raw_parts(high, n);
let lows = slice::from_raw_parts(low, n);
let closes = slice::from_raw_parts(close, n);
let volumes = slice::from_raw_parts(volume, n);
let timestamps = slice::from_raw_parts(timestamp, n);
let outputs = slice::from_raw_parts_mut(out, n);
for (idx, slot) in outputs.iter_mut().enumerate() {
*slot = match Candle::new(
opens[idx],
highs[idx],
lows[idx],
closes[idx],
volumes[idx],
timestamps[idx],
) {
Ok(candle) => ind.update(candle).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
};
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_yoyo_exit_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_yoyo_exit_reset(handle: *mut YoyoExit) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_yoyo_exit_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_yoyo_exit_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_yoyo_exit_free(handle: *mut YoyoExit) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
// ===== Trade-input indicators (microstructure) =====
/// Create a `AmihudIlliquidity` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_amihud_illiquidity_free`.
#[no_mangle]
pub extern "C" fn wickra_amihud_illiquidity_new(period: usize) -> *mut AmihudIlliquidity {
match AmihudIlliquidity::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one trade; returns the output, or `NaN` during warmup / on a `NULL` handle /
/// if the trade is invalid (non-positive price, negative size).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_amihud_illiquidity_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_amihud_illiquidity_update(
handle: *mut AmihudIlliquidity,
price: f64,
size: f64,
is_buy: bool,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
let side = if is_buy { Side::Buy } else { Side::Sell };
match Trade::new(price, size, side, timestamp) {
Ok(trade) => ind.update(trade).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_amihud_illiquidity_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_amihud_illiquidity_reset(handle: *mut AmihudIlliquidity) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_amihud_illiquidity_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_amihud_illiquidity_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_amihud_illiquidity_free(handle: *mut AmihudIlliquidity) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `CumulativeVolumeDelta` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_cumulative_volume_delta_free`.
#[no_mangle]
pub extern "C" fn wickra_cumulative_volume_delta_new() -> *mut CumulativeVolumeDelta {
Box::into_raw(Box::new(CumulativeVolumeDelta::new()))
}
/// Feed one trade; returns the output, or `NaN` during warmup / on a `NULL` handle /
/// if the trade is invalid (non-positive price, negative size).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_cumulative_volume_delta_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cumulative_volume_delta_update(
handle: *mut CumulativeVolumeDelta,
price: f64,
size: f64,
is_buy: bool,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
let side = if is_buy { Side::Buy } else { Side::Sell };
match Trade::new(price, size, side, timestamp) {
Ok(trade) => ind.update(trade).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_cumulative_volume_delta_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cumulative_volume_delta_reset(handle: *mut CumulativeVolumeDelta) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_cumulative_volume_delta_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_cumulative_volume_delta_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cumulative_volume_delta_free(handle: *mut CumulativeVolumeDelta) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Pin` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_pin_free`.
#[no_mangle]
pub extern "C" fn wickra_pin_new(window: usize) -> *mut Pin {
match Pin::new(window) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one trade; returns the output, or `NaN` during warmup / on a `NULL` handle /
/// if the trade is invalid (non-positive price, negative size).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_pin_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pin_update(
handle: *mut Pin,
price: f64,
size: f64,
is_buy: bool,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
let side = if is_buy { Side::Buy } else { Side::Sell };
match Trade::new(price, size, side, timestamp) {
Ok(trade) => ind.update(trade).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_pin_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pin_reset(handle: *mut Pin) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_pin_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_pin_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_pin_free(handle: *mut Pin) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RollMeasure` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_roll_measure_free`.
#[no_mangle]
pub extern "C" fn wickra_roll_measure_new(period: usize) -> *mut RollMeasure {
match RollMeasure::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one trade; returns the output, or `NaN` during warmup / on a `NULL` handle /
/// if the trade is invalid (non-positive price, negative size).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_roll_measure_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_roll_measure_update(
handle: *mut RollMeasure,
price: f64,
size: f64,
is_buy: bool,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
let side = if is_buy { Side::Buy } else { Side::Sell };
match Trade::new(price, size, side, timestamp) {
Ok(trade) => ind.update(trade).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_roll_measure_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_roll_measure_reset(handle: *mut RollMeasure) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_roll_measure_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_roll_measure_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_roll_measure_free(handle: *mut RollMeasure) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SignedVolume` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_signed_volume_free`.
#[no_mangle]
pub extern "C" fn wickra_signed_volume_new() -> *mut SignedVolume {
Box::into_raw(Box::new(SignedVolume::new()))
}
/// Feed one trade; returns the output, or `NaN` during warmup / on a `NULL` handle /
/// if the trade is invalid (non-positive price, negative size).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_signed_volume_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_signed_volume_update(
handle: *mut SignedVolume,
price: f64,
size: f64,
is_buy: bool,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
let side = if is_buy { Side::Buy } else { Side::Sell };
match Trade::new(price, size, side, timestamp) {
Ok(trade) => ind.update(trade).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_signed_volume_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_signed_volume_reset(handle: *mut SignedVolume) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_signed_volume_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_signed_volume_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_signed_volume_free(handle: *mut SignedVolume) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TradeImbalance` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_trade_imbalance_free`.
#[no_mangle]
pub extern "C" fn wickra_trade_imbalance_new(window: usize) -> *mut TradeImbalance {
match TradeImbalance::new(window) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one trade; returns the output, or `NaN` during warmup / on a `NULL` handle /
/// if the trade is invalid (non-positive price, negative size).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_trade_imbalance_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trade_imbalance_update(
handle: *mut TradeImbalance,
price: f64,
size: f64,
is_buy: bool,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
let side = if is_buy { Side::Buy } else { Side::Sell };
match Trade::new(price, size, side, timestamp) {
Ok(trade) => ind.update(trade).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_trade_imbalance_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trade_imbalance_reset(handle: *mut TradeImbalance) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_trade_imbalance_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_trade_imbalance_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trade_imbalance_free(handle: *mut TradeImbalance) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TradeSignAutocorrelation` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_trade_sign_autocorrelation_free`.
#[no_mangle]
pub extern "C" fn wickra_trade_sign_autocorrelation_new(
period: usize,
) -> *mut TradeSignAutocorrelation {
match TradeSignAutocorrelation::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one trade; returns the output, or `NaN` during warmup / on a `NULL` handle /
/// if the trade is invalid (non-positive price, negative size).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_trade_sign_autocorrelation_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trade_sign_autocorrelation_update(
handle: *mut TradeSignAutocorrelation,
price: f64,
size: f64,
is_buy: bool,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
let side = if is_buy { Side::Buy } else { Side::Sell };
match Trade::new(price, size, side, timestamp) {
Ok(trade) => ind.update(trade).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_trade_sign_autocorrelation_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trade_sign_autocorrelation_reset(
handle: *mut TradeSignAutocorrelation,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_trade_sign_autocorrelation_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_trade_sign_autocorrelation_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trade_sign_autocorrelation_free(
handle: *mut TradeSignAutocorrelation,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Vpin` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_vpin_free`.
#[no_mangle]
pub extern "C" fn wickra_vpin_new(bucket_volume: f64, num_buckets: usize) -> *mut Vpin {
match Vpin::new(bucket_volume, num_buckets) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one trade; returns the output, or `NaN` during warmup / on a `NULL` handle /
/// if the trade is invalid (non-positive price, negative size).
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_vpin_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vpin_update(
handle: *mut Vpin,
price: f64,
size: f64,
is_buy: bool,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
let side = if is_buy { Side::Buy } else { Side::Sell };
match Trade::new(price, size, side, timestamp) {
Ok(trade) => ind.update(trade).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_vpin_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vpin_reset(handle: *mut Vpin) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_vpin_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_vpin_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vpin_free(handle: *mut Vpin) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
// ===== Trade+quote-input indicators (microstructure) =====
/// Create a `EffectiveSpread` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_effective_spread_free`.
#[no_mangle]
pub extern "C" fn wickra_effective_spread_new() -> *mut EffectiveSpread {
Box::into_raw(Box::new(EffectiveSpread::new()))
}
/// Feed one trade with the prevailing mid price; returns the output, or `NaN` during
/// warmup / on a `NULL` handle / if the trade or mid is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_effective_spread_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_effective_spread_update(
handle: *mut EffectiveSpread,
price: f64,
size: f64,
is_buy: bool,
timestamp: i64,
mid: f64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
let side = if is_buy { Side::Buy } else { Side::Sell };
let Ok(trade) = Trade::new(price, size, side, timestamp) else {
return f64::NAN;
};
match TradeQuote::new(trade, mid) {
Ok(quote) => ind.update(quote).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_effective_spread_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_effective_spread_reset(handle: *mut EffectiveSpread) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_effective_spread_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_effective_spread_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_effective_spread_free(handle: *mut EffectiveSpread) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `KylesLambda` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_kyles_lambda_free`.
#[no_mangle]
pub extern "C" fn wickra_kyles_lambda_new(window: usize) -> *mut KylesLambda {
match KylesLambda::new(window) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one trade with the prevailing mid price; returns the output, or `NaN` during
/// warmup / on a `NULL` handle / if the trade or mid is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_kyles_lambda_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kyles_lambda_update(
handle: *mut KylesLambda,
price: f64,
size: f64,
is_buy: bool,
timestamp: i64,
mid: f64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
let side = if is_buy { Side::Buy } else { Side::Sell };
let Ok(trade) = Trade::new(price, size, side, timestamp) else {
return f64::NAN;
};
match TradeQuote::new(trade, mid) {
Ok(quote) => ind.update(quote).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_kyles_lambda_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kyles_lambda_reset(handle: *mut KylesLambda) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_kyles_lambda_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_kyles_lambda_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kyles_lambda_free(handle: *mut KylesLambda) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RealizedSpread` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_realized_spread_free`.
#[no_mangle]
pub extern "C" fn wickra_realized_spread_new(horizon: usize) -> *mut RealizedSpread {
match RealizedSpread::new(horizon) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one trade with the prevailing mid price; returns the output, or `NaN` during
/// warmup / on a `NULL` handle / if the trade or mid is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_realized_spread_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_realized_spread_update(
handle: *mut RealizedSpread,
price: f64,
size: f64,
is_buy: bool,
timestamp: i64,
mid: f64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
let side = if is_buy { Side::Buy } else { Side::Sell };
let Ok(trade) = Trade::new(price, size, side, timestamp) else {
return f64::NAN;
};
match TradeQuote::new(trade, mid) {
Ok(quote) => ind.update(quote).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_realized_spread_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_realized_spread_reset(handle: *mut RealizedSpread) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_realized_spread_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_realized_spread_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_realized_spread_free(handle: *mut RealizedSpread) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
// ===== Derivatives-tick-input indicators =====
/// Create a `CalendarSpread` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_calendar_spread_free`.
#[no_mangle]
pub extern "C" fn wickra_calendar_spread_new() -> *mut CalendarSpread {
Box::into_raw(Box::new(CalendarSpread::new()))
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_calendar_spread_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_calendar_spread_update(
handle: *mut CalendarSpread,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_calendar_spread_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_calendar_spread_reset(handle: *mut CalendarSpread) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_calendar_spread_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_calendar_spread_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_calendar_spread_free(handle: *mut CalendarSpread) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `EstimatedLeverageRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_estimated_leverage_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_estimated_leverage_ratio_new() -> *mut EstimatedLeverageRatio {
Box::into_raw(Box::new(EstimatedLeverageRatio::new()))
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_estimated_leverage_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_estimated_leverage_ratio_update(
handle: *mut EstimatedLeverageRatio,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_estimated_leverage_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_estimated_leverage_ratio_reset(
handle: *mut EstimatedLeverageRatio,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_estimated_leverage_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_estimated_leverage_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_estimated_leverage_ratio_free(handle: *mut EstimatedLeverageRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FundingBasis` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_funding_basis_free`.
#[no_mangle]
pub extern "C" fn wickra_funding_basis_new() -> *mut FundingBasis {
Box::into_raw(Box::new(FundingBasis::new()))
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_funding_basis_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_basis_update(
handle: *mut FundingBasis,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_funding_basis_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_basis_reset(handle: *mut FundingBasis) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_funding_basis_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_funding_basis_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_basis_free(handle: *mut FundingBasis) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FundingImpliedApr` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_funding_implied_apr_free`.
#[no_mangle]
pub extern "C" fn wickra_funding_implied_apr_new(
intervals_per_year: f64,
) -> *mut FundingImpliedApr {
match FundingImpliedApr::new(intervals_per_year) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_funding_implied_apr_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_implied_apr_update(
handle: *mut FundingImpliedApr,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_funding_implied_apr_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_implied_apr_reset(handle: *mut FundingImpliedApr) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_funding_implied_apr_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_funding_implied_apr_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_implied_apr_free(handle: *mut FundingImpliedApr) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FundingRate` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_funding_rate_free`.
#[no_mangle]
pub extern "C" fn wickra_funding_rate_new() -> *mut FundingRate {
Box::into_raw(Box::new(FundingRate::new()))
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_funding_rate_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_rate_update(
handle: *mut FundingRate,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_funding_rate_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_rate_reset(handle: *mut FundingRate) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_funding_rate_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_funding_rate_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_rate_free(handle: *mut FundingRate) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FundingRateMean` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_funding_rate_mean_free`.
#[no_mangle]
pub extern "C" fn wickra_funding_rate_mean_new(window: usize) -> *mut FundingRateMean {
match FundingRateMean::new(window) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_funding_rate_mean_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_rate_mean_update(
handle: *mut FundingRateMean,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_funding_rate_mean_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_rate_mean_reset(handle: *mut FundingRateMean) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_funding_rate_mean_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_funding_rate_mean_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_rate_mean_free(handle: *mut FundingRateMean) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FundingRateZScore` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_funding_rate_z_score_free`.
#[no_mangle]
pub extern "C" fn wickra_funding_rate_z_score_new(window: usize) -> *mut FundingRateZScore {
match FundingRateZScore::new(window) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_funding_rate_z_score_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_rate_z_score_update(
handle: *mut FundingRateZScore,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_funding_rate_z_score_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_rate_z_score_reset(handle: *mut FundingRateZScore) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_funding_rate_z_score_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_funding_rate_z_score_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_funding_rate_z_score_free(handle: *mut FundingRateZScore) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `LongShortRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_long_short_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_long_short_ratio_new() -> *mut LongShortRatio {
Box::into_raw(Box::new(LongShortRatio::new()))
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_long_short_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_long_short_ratio_update(
handle: *mut LongShortRatio,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_long_short_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_long_short_ratio_reset(handle: *mut LongShortRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_long_short_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_long_short_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_long_short_ratio_free(handle: *mut LongShortRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OpenInterestDelta` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_open_interest_delta_free`.
#[no_mangle]
pub extern "C" fn wickra_open_interest_delta_new() -> *mut OpenInterestDelta {
Box::into_raw(Box::new(OpenInterestDelta::new()))
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_open_interest_delta_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_open_interest_delta_update(
handle: *mut OpenInterestDelta,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_open_interest_delta_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_open_interest_delta_reset(handle: *mut OpenInterestDelta) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_open_interest_delta_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_open_interest_delta_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_open_interest_delta_free(handle: *mut OpenInterestDelta) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OIPriceDivergence` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_oi_price_divergence_free`.
#[no_mangle]
pub extern "C" fn wickra_oi_price_divergence_new(window: usize) -> *mut OIPriceDivergence {
match OIPriceDivergence::new(window) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_oi_price_divergence_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_oi_price_divergence_update(
handle: *mut OIPriceDivergence,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_oi_price_divergence_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_oi_price_divergence_reset(handle: *mut OIPriceDivergence) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_oi_price_divergence_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_oi_price_divergence_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_oi_price_divergence_free(handle: *mut OIPriceDivergence) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OiToVolumeRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_oi_to_volume_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_oi_to_volume_ratio_new() -> *mut OiToVolumeRatio {
Box::into_raw(Box::new(OiToVolumeRatio::new()))
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_oi_to_volume_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_oi_to_volume_ratio_update(
handle: *mut OiToVolumeRatio,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_oi_to_volume_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_oi_to_volume_ratio_reset(handle: *mut OiToVolumeRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_oi_to_volume_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_oi_to_volume_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_oi_to_volume_ratio_free(handle: *mut OiToVolumeRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OIWeighted` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_oi_weighted_free`.
#[no_mangle]
pub extern "C" fn wickra_oi_weighted_new() -> *mut OIWeighted {
Box::into_raw(Box::new(OIWeighted::new()))
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_oi_weighted_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_oi_weighted_update(
handle: *mut OIWeighted,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_oi_weighted_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_oi_weighted_reset(handle: *mut OIWeighted) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_oi_weighted_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_oi_weighted_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_oi_weighted_free(handle: *mut OIWeighted) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OpenInterestMomentum` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_open_interest_momentum_free`.
#[no_mangle]
pub extern "C" fn wickra_open_interest_momentum_new(period: usize) -> *mut OpenInterestMomentum {
match OpenInterestMomentum::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_open_interest_momentum_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_open_interest_momentum_update(
handle: *mut OpenInterestMomentum,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_open_interest_momentum_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_open_interest_momentum_reset(handle: *mut OpenInterestMomentum) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_open_interest_momentum_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_open_interest_momentum_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_open_interest_momentum_free(handle: *mut OpenInterestMomentum) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PerpetualPremiumIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_perpetual_premium_index_free`.
#[no_mangle]
pub extern "C" fn wickra_perpetual_premium_index_new() -> *mut PerpetualPremiumIndex {
Box::into_raw(Box::new(PerpetualPremiumIndex::new()))
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_perpetual_premium_index_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_perpetual_premium_index_update(
handle: *mut PerpetualPremiumIndex,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_perpetual_premium_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_perpetual_premium_index_reset(handle: *mut PerpetualPremiumIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_perpetual_premium_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_perpetual_premium_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_perpetual_premium_index_free(handle: *mut PerpetualPremiumIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TakerBuySellRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_taker_buy_sell_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_taker_buy_sell_ratio_new() -> *mut TakerBuySellRatio {
Box::into_raw(Box::new(TakerBuySellRatio::new()))
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_taker_buy_sell_ratio_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_taker_buy_sell_ratio_update(
handle: *mut TakerBuySellRatio,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_taker_buy_sell_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_taker_buy_sell_ratio_reset(handle: *mut TakerBuySellRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_taker_buy_sell_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_taker_buy_sell_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_taker_buy_sell_ratio_free(handle: *mut TakerBuySellRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TermStructureBasis` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_term_structure_basis_free`.
#[no_mangle]
pub extern "C" fn wickra_term_structure_basis_new() -> *mut TermStructureBasis {
Box::into_raw(Box::new(TermStructureBasis::new()))
}
/// Feed one derivatives tick; returns the output, or `NaN` during warmup / on a
/// `NULL` handle / if the tick is invalid.
///
/// # Safety
/// `handle` must be a valid pointer from `wickra_term_structure_basis_new` (not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_term_structure_basis_update(
handle: *mut TermStructureBasis,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
match DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) {
Ok(tick) => ind.update(tick).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_term_structure_basis_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_term_structure_basis_reset(handle: *mut TermStructureBasis) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_term_structure_basis_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_term_structure_basis_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_term_structure_basis_free(handle: *mut TermStructureBasis) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
// ===== Order-book-input indicators (microstructure) =====
/// Create a `DepthSlope` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_depth_slope_free`.
#[no_mangle]
pub extern "C" fn wickra_depth_slope_new() -> *mut DepthSlope {
Box::into_raw(Box::new(DepthSlope::new()))
}
/// Feed one order-book snapshot as parallel bid/ask price+size arrays; returns the
/// output, or `NaN` during warmup / on a `NULL` handle / if a level or the book is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_depth_slope_new`, not freed) or `NULL`. `bid_price`/`bid_size`
/// each cover `n_bids`; `ask_price`/`ask_size` each cover `n_asks`.
#[no_mangle]
pub unsafe extern "C" fn wickra_depth_slope_update(
handle: *mut DepthSlope,
bid_price: *const f64,
bid_size: *const f64,
n_bids: usize,
ask_price: *const f64,
ask_size: *const f64,
n_asks: usize,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if bid_price.is_null() || bid_size.is_null() || ask_price.is_null() || ask_size.is_null() {
return f64::NAN;
}
let bid_px = slice::from_raw_parts(bid_price, n_bids);
let bid_sz = slice::from_raw_parts(bid_size, n_bids);
let ask_px = slice::from_raw_parts(ask_price, n_asks);
let ask_sz = slice::from_raw_parts(ask_size, n_asks);
let mut bids = Vec::with_capacity(n_bids);
for (&px, &sz) in bid_px.iter().zip(bid_sz) {
let Ok(level) = Level::new(px, sz) else {
return f64::NAN;
};
bids.push(level);
}
let mut asks = Vec::with_capacity(n_asks);
for (&px, &sz) in ask_px.iter().zip(ask_sz) {
let Ok(level) = Level::new(px, sz) else {
return f64::NAN;
};
asks.push(level);
}
match OrderBook::new(bids, asks) {
Ok(book) => ind.update(book).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_depth_slope_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_depth_slope_reset(handle: *mut DepthSlope) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_depth_slope_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_depth_slope_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_depth_slope_free(handle: *mut DepthSlope) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Microprice` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_microprice_free`.
#[no_mangle]
pub extern "C" fn wickra_microprice_new() -> *mut Microprice {
Box::into_raw(Box::new(Microprice::new()))
}
/// Feed one order-book snapshot as parallel bid/ask price+size arrays; returns the
/// output, or `NaN` during warmup / on a `NULL` handle / if a level or the book is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_microprice_new`, not freed) or `NULL`. `bid_price`/`bid_size`
/// each cover `n_bids`; `ask_price`/`ask_size` each cover `n_asks`.
#[no_mangle]
pub unsafe extern "C" fn wickra_microprice_update(
handle: *mut Microprice,
bid_price: *const f64,
bid_size: *const f64,
n_bids: usize,
ask_price: *const f64,
ask_size: *const f64,
n_asks: usize,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if bid_price.is_null() || bid_size.is_null() || ask_price.is_null() || ask_size.is_null() {
return f64::NAN;
}
let bid_px = slice::from_raw_parts(bid_price, n_bids);
let bid_sz = slice::from_raw_parts(bid_size, n_bids);
let ask_px = slice::from_raw_parts(ask_price, n_asks);
let ask_sz = slice::from_raw_parts(ask_size, n_asks);
let mut bids = Vec::with_capacity(n_bids);
for (&px, &sz) in bid_px.iter().zip(bid_sz) {
let Ok(level) = Level::new(px, sz) else {
return f64::NAN;
};
bids.push(level);
}
let mut asks = Vec::with_capacity(n_asks);
for (&px, &sz) in ask_px.iter().zip(ask_sz) {
let Ok(level) = Level::new(px, sz) else {
return f64::NAN;
};
asks.push(level);
}
match OrderBook::new(bids, asks) {
Ok(book) => ind.update(book).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_microprice_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_microprice_reset(handle: *mut Microprice) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_microprice_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_microprice_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_microprice_free(handle: *mut Microprice) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OrderBookImbalanceFull` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_order_book_imbalance_full_free`.
#[no_mangle]
pub extern "C" fn wickra_order_book_imbalance_full_new() -> *mut OrderBookImbalanceFull {
Box::into_raw(Box::new(OrderBookImbalanceFull::new()))
}
/// Feed one order-book snapshot as parallel bid/ask price+size arrays; returns the
/// output, or `NaN` during warmup / on a `NULL` handle / if a level or the book is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_order_book_imbalance_full_new`, not freed) or `NULL`. `bid_price`/`bid_size`
/// each cover `n_bids`; `ask_price`/`ask_size` each cover `n_asks`.
#[no_mangle]
pub unsafe extern "C" fn wickra_order_book_imbalance_full_update(
handle: *mut OrderBookImbalanceFull,
bid_price: *const f64,
bid_size: *const f64,
n_bids: usize,
ask_price: *const f64,
ask_size: *const f64,
n_asks: usize,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if bid_price.is_null() || bid_size.is_null() || ask_price.is_null() || ask_size.is_null() {
return f64::NAN;
}
let bid_px = slice::from_raw_parts(bid_price, n_bids);
let bid_sz = slice::from_raw_parts(bid_size, n_bids);
let ask_px = slice::from_raw_parts(ask_price, n_asks);
let ask_sz = slice::from_raw_parts(ask_size, n_asks);
let mut bids = Vec::with_capacity(n_bids);
for (&px, &sz) in bid_px.iter().zip(bid_sz) {
let Ok(level) = Level::new(px, sz) else {
return f64::NAN;
};
bids.push(level);
}
let mut asks = Vec::with_capacity(n_asks);
for (&px, &sz) in ask_px.iter().zip(ask_sz) {
let Ok(level) = Level::new(px, sz) else {
return f64::NAN;
};
asks.push(level);
}
match OrderBook::new(bids, asks) {
Ok(book) => ind.update(book).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_order_book_imbalance_full_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_order_book_imbalance_full_reset(
handle: *mut OrderBookImbalanceFull,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_order_book_imbalance_full_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_order_book_imbalance_full_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_order_book_imbalance_full_free(
handle: *mut OrderBookImbalanceFull,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OrderBookImbalanceTop1` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_order_book_imbalance_top1_free`.
#[no_mangle]
pub extern "C" fn wickra_order_book_imbalance_top1_new() -> *mut OrderBookImbalanceTop1 {
Box::into_raw(Box::new(OrderBookImbalanceTop1::new()))
}
/// Feed one order-book snapshot as parallel bid/ask price+size arrays; returns the
/// output, or `NaN` during warmup / on a `NULL` handle / if a level or the book is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_order_book_imbalance_top1_new`, not freed) or `NULL`. `bid_price`/`bid_size`
/// each cover `n_bids`; `ask_price`/`ask_size` each cover `n_asks`.
#[no_mangle]
pub unsafe extern "C" fn wickra_order_book_imbalance_top1_update(
handle: *mut OrderBookImbalanceTop1,
bid_price: *const f64,
bid_size: *const f64,
n_bids: usize,
ask_price: *const f64,
ask_size: *const f64,
n_asks: usize,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if bid_price.is_null() || bid_size.is_null() || ask_price.is_null() || ask_size.is_null() {
return f64::NAN;
}
let bid_px = slice::from_raw_parts(bid_price, n_bids);
let bid_sz = slice::from_raw_parts(bid_size, n_bids);
let ask_px = slice::from_raw_parts(ask_price, n_asks);
let ask_sz = slice::from_raw_parts(ask_size, n_asks);
let mut bids = Vec::with_capacity(n_bids);
for (&px, &sz) in bid_px.iter().zip(bid_sz) {
let Ok(level) = Level::new(px, sz) else {
return f64::NAN;
};
bids.push(level);
}
let mut asks = Vec::with_capacity(n_asks);
for (&px, &sz) in ask_px.iter().zip(ask_sz) {
let Ok(level) = Level::new(px, sz) else {
return f64::NAN;
};
asks.push(level);
}
match OrderBook::new(bids, asks) {
Ok(book) => ind.update(book).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_order_book_imbalance_top1_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_order_book_imbalance_top1_reset(
handle: *mut OrderBookImbalanceTop1,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_order_book_imbalance_top1_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_order_book_imbalance_top1_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_order_book_imbalance_top1_free(
handle: *mut OrderBookImbalanceTop1,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OrderBookImbalanceTopN` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_order_book_imbalance_top_n_free`.
#[no_mangle]
pub extern "C" fn wickra_order_book_imbalance_top_n_new(
levels: usize,
) -> *mut OrderBookImbalanceTopN {
match OrderBookImbalanceTopN::new(levels) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one order-book snapshot as parallel bid/ask price+size arrays; returns the
/// output, or `NaN` during warmup / on a `NULL` handle / if a level or the book is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_order_book_imbalance_top_n_new`, not freed) or `NULL`. `bid_price`/`bid_size`
/// each cover `n_bids`; `ask_price`/`ask_size` each cover `n_asks`.
#[no_mangle]
pub unsafe extern "C" fn wickra_order_book_imbalance_top_n_update(
handle: *mut OrderBookImbalanceTopN,
bid_price: *const f64,
bid_size: *const f64,
n_bids: usize,
ask_price: *const f64,
ask_size: *const f64,
n_asks: usize,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if bid_price.is_null() || bid_size.is_null() || ask_price.is_null() || ask_size.is_null() {
return f64::NAN;
}
let bid_px = slice::from_raw_parts(bid_price, n_bids);
let bid_sz = slice::from_raw_parts(bid_size, n_bids);
let ask_px = slice::from_raw_parts(ask_price, n_asks);
let ask_sz = slice::from_raw_parts(ask_size, n_asks);
let mut bids = Vec::with_capacity(n_bids);
for (&px, &sz) in bid_px.iter().zip(bid_sz) {
let Ok(level) = Level::new(px, sz) else {
return f64::NAN;
};
bids.push(level);
}
let mut asks = Vec::with_capacity(n_asks);
for (&px, &sz) in ask_px.iter().zip(ask_sz) {
let Ok(level) = Level::new(px, sz) else {
return f64::NAN;
};
asks.push(level);
}
match OrderBook::new(bids, asks) {
Ok(book) => ind.update(book).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_order_book_imbalance_top_n_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_order_book_imbalance_top_n_reset(
handle: *mut OrderBookImbalanceTopN,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_order_book_imbalance_top_n_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_order_book_imbalance_top_n_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_order_book_imbalance_top_n_free(
handle: *mut OrderBookImbalanceTopN,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OrderFlowImbalance` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_order_flow_imbalance_free`.
#[no_mangle]
pub extern "C" fn wickra_order_flow_imbalance_new(period: usize) -> *mut OrderFlowImbalance {
match OrderFlowImbalance::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one order-book snapshot as parallel bid/ask price+size arrays; returns the
/// output, or `NaN` during warmup / on a `NULL` handle / if a level or the book is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_order_flow_imbalance_new`, not freed) or `NULL`. `bid_price`/`bid_size`
/// each cover `n_bids`; `ask_price`/`ask_size` each cover `n_asks`.
#[no_mangle]
pub unsafe extern "C" fn wickra_order_flow_imbalance_update(
handle: *mut OrderFlowImbalance,
bid_price: *const f64,
bid_size: *const f64,
n_bids: usize,
ask_price: *const f64,
ask_size: *const f64,
n_asks: usize,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if bid_price.is_null() || bid_size.is_null() || ask_price.is_null() || ask_size.is_null() {
return f64::NAN;
}
let bid_px = slice::from_raw_parts(bid_price, n_bids);
let bid_sz = slice::from_raw_parts(bid_size, n_bids);
let ask_px = slice::from_raw_parts(ask_price, n_asks);
let ask_sz = slice::from_raw_parts(ask_size, n_asks);
let mut bids = Vec::with_capacity(n_bids);
for (&px, &sz) in bid_px.iter().zip(bid_sz) {
let Ok(level) = Level::new(px, sz) else {
return f64::NAN;
};
bids.push(level);
}
let mut asks = Vec::with_capacity(n_asks);
for (&px, &sz) in ask_px.iter().zip(ask_sz) {
let Ok(level) = Level::new(px, sz) else {
return f64::NAN;
};
asks.push(level);
}
match OrderBook::new(bids, asks) {
Ok(book) => ind.update(book).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_order_flow_imbalance_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_order_flow_imbalance_reset(handle: *mut OrderFlowImbalance) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_order_flow_imbalance_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_order_flow_imbalance_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_order_flow_imbalance_free(handle: *mut OrderFlowImbalance) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `QuotedSpread` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_quoted_spread_free`.
#[no_mangle]
pub extern "C" fn wickra_quoted_spread_new() -> *mut QuotedSpread {
Box::into_raw(Box::new(QuotedSpread::new()))
}
/// Feed one order-book snapshot as parallel bid/ask price+size arrays; returns the
/// output, or `NaN` during warmup / on a `NULL` handle / if a level or the book is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_quoted_spread_new`, not freed) or `NULL`. `bid_price`/`bid_size`
/// each cover `n_bids`; `ask_price`/`ask_size` each cover `n_asks`.
#[no_mangle]
pub unsafe extern "C" fn wickra_quoted_spread_update(
handle: *mut QuotedSpread,
bid_price: *const f64,
bid_size: *const f64,
n_bids: usize,
ask_price: *const f64,
ask_size: *const f64,
n_asks: usize,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if bid_price.is_null() || bid_size.is_null() || ask_price.is_null() || ask_size.is_null() {
return f64::NAN;
}
let bid_px = slice::from_raw_parts(bid_price, n_bids);
let bid_sz = slice::from_raw_parts(bid_size, n_bids);
let ask_px = slice::from_raw_parts(ask_price, n_asks);
let ask_sz = slice::from_raw_parts(ask_size, n_asks);
let mut bids = Vec::with_capacity(n_bids);
for (&px, &sz) in bid_px.iter().zip(bid_sz) {
let Ok(level) = Level::new(px, sz) else {
return f64::NAN;
};
bids.push(level);
}
let mut asks = Vec::with_capacity(n_asks);
for (&px, &sz) in ask_px.iter().zip(ask_sz) {
let Ok(level) = Level::new(px, sz) else {
return f64::NAN;
};
asks.push(level);
}
match OrderBook::new(bids, asks) {
Ok(book) => ind.update(book).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_quoted_spread_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_quoted_spread_reset(handle: *mut QuotedSpread) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_quoted_spread_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_quoted_spread_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_quoted_spread_free(handle: *mut QuotedSpread) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
// ===== Cross-section-input indicators (market breadth) =====
/// Create a `AbsoluteBreadthIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_absolute_breadth_index_free`.
#[no_mangle]
pub extern "C" fn wickra_absolute_breadth_index_new() -> *mut AbsoluteBreadthIndex {
Box::into_raw(Box::new(AbsoluteBreadthIndex::new()))
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_absolute_breadth_index_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_absolute_breadth_index_update(
handle: *mut AbsoluteBreadthIndex,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_absolute_breadth_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_absolute_breadth_index_reset(handle: *mut AbsoluteBreadthIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_absolute_breadth_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_absolute_breadth_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_absolute_breadth_index_free(handle: *mut AbsoluteBreadthIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AdVolumeLine` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ad_volume_line_free`.
#[no_mangle]
pub extern "C" fn wickra_ad_volume_line_new() -> *mut AdVolumeLine {
Box::into_raw(Box::new(AdVolumeLine::new()))
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_ad_volume_line_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_ad_volume_line_update(
handle: *mut AdVolumeLine,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ad_volume_line_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ad_volume_line_reset(handle: *mut AdVolumeLine) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ad_volume_line_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ad_volume_line_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ad_volume_line_free(handle: *mut AdVolumeLine) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AdvanceDecline` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_advance_decline_free`.
#[no_mangle]
pub extern "C" fn wickra_advance_decline_new() -> *mut AdvanceDecline {
Box::into_raw(Box::new(AdvanceDecline::new()))
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_advance_decline_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_advance_decline_update(
handle: *mut AdvanceDecline,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_advance_decline_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_advance_decline_reset(handle: *mut AdvanceDecline) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_advance_decline_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_advance_decline_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_advance_decline_free(handle: *mut AdvanceDecline) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AdvanceDeclineRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_advance_decline_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_advance_decline_ratio_new() -> *mut AdvanceDeclineRatio {
Box::into_raw(Box::new(AdvanceDeclineRatio::new()))
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_advance_decline_ratio_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_advance_decline_ratio_update(
handle: *mut AdvanceDeclineRatio,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_advance_decline_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_advance_decline_ratio_reset(handle: *mut AdvanceDeclineRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_advance_decline_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_advance_decline_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_advance_decline_ratio_free(handle: *mut AdvanceDeclineRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `BreadthThrust` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_breadth_thrust_free`.
#[no_mangle]
pub extern "C" fn wickra_breadth_thrust_new(period: usize) -> *mut BreadthThrust {
match BreadthThrust::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_breadth_thrust_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_breadth_thrust_update(
handle: *mut BreadthThrust,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_breadth_thrust_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_breadth_thrust_reset(handle: *mut BreadthThrust) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_breadth_thrust_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_breadth_thrust_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_breadth_thrust_free(handle: *mut BreadthThrust) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `BullishPercentIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_bullish_percent_index_free`.
#[no_mangle]
pub extern "C" fn wickra_bullish_percent_index_new() -> *mut BullishPercentIndex {
Box::into_raw(Box::new(BullishPercentIndex::new()))
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_bullish_percent_index_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_bullish_percent_index_update(
handle: *mut BullishPercentIndex,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_bullish_percent_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bullish_percent_index_reset(handle: *mut BullishPercentIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_bullish_percent_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_bullish_percent_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bullish_percent_index_free(handle: *mut BullishPercentIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `CumulativeVolumeIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_cumulative_volume_index_free`.
#[no_mangle]
pub extern "C" fn wickra_cumulative_volume_index_new() -> *mut CumulativeVolumeIndex {
Box::into_raw(Box::new(CumulativeVolumeIndex::new()))
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_cumulative_volume_index_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_cumulative_volume_index_update(
handle: *mut CumulativeVolumeIndex,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_cumulative_volume_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cumulative_volume_index_reset(handle: *mut CumulativeVolumeIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_cumulative_volume_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_cumulative_volume_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cumulative_volume_index_free(handle: *mut CumulativeVolumeIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HighLowIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_high_low_index_free`.
#[no_mangle]
pub extern "C" fn wickra_high_low_index_new(period: usize) -> *mut HighLowIndex {
match HighLowIndex::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_high_low_index_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_high_low_index_update(
handle: *mut HighLowIndex,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_high_low_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_high_low_index_reset(handle: *mut HighLowIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_high_low_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_high_low_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_high_low_index_free(handle: *mut HighLowIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `McClellanOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_mc_clellan_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_mc_clellan_oscillator_new() -> *mut McClellanOscillator {
Box::into_raw(Box::new(McClellanOscillator::new()))
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_mc_clellan_oscillator_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_mc_clellan_oscillator_update(
handle: *mut McClellanOscillator,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_mc_clellan_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mc_clellan_oscillator_reset(handle: *mut McClellanOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_mc_clellan_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_mc_clellan_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mc_clellan_oscillator_free(handle: *mut McClellanOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `McClellanSummationIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_mc_clellan_summation_index_free`.
#[no_mangle]
pub extern "C" fn wickra_mc_clellan_summation_index_new() -> *mut McClellanSummationIndex {
Box::into_raw(Box::new(McClellanSummationIndex::new()))
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_mc_clellan_summation_index_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_mc_clellan_summation_index_update(
handle: *mut McClellanSummationIndex,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_mc_clellan_summation_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mc_clellan_summation_index_reset(
handle: *mut McClellanSummationIndex,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_mc_clellan_summation_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_mc_clellan_summation_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mc_clellan_summation_index_free(
handle: *mut McClellanSummationIndex,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `NewHighsNewLows` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_new_highs_new_lows_free`.
#[no_mangle]
pub extern "C" fn wickra_new_highs_new_lows_new() -> *mut NewHighsNewLows {
Box::into_raw(Box::new(NewHighsNewLows::new()))
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_new_highs_new_lows_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_new_highs_new_lows_update(
handle: *mut NewHighsNewLows,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_new_highs_new_lows_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_new_highs_new_lows_reset(handle: *mut NewHighsNewLows) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_new_highs_new_lows_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_new_highs_new_lows_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_new_highs_new_lows_free(handle: *mut NewHighsNewLows) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PercentAboveMa` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_percent_above_ma_free`.
#[no_mangle]
pub extern "C" fn wickra_percent_above_ma_new() -> *mut PercentAboveMa {
Box::into_raw(Box::new(PercentAboveMa::new()))
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_percent_above_ma_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_percent_above_ma_update(
handle: *mut PercentAboveMa,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_percent_above_ma_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_percent_above_ma_reset(handle: *mut PercentAboveMa) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_percent_above_ma_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_percent_above_ma_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_percent_above_ma_free(handle: *mut PercentAboveMa) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TickIndex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_tick_index_free`.
#[no_mangle]
pub extern "C" fn wickra_tick_index_new() -> *mut TickIndex {
Box::into_raw(Box::new(TickIndex::new()))
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_tick_index_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_tick_index_update(
handle: *mut TickIndex,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_tick_index_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tick_index_reset(handle: *mut TickIndex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_tick_index_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_tick_index_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tick_index_free(handle: *mut TickIndex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Trin` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_trin_free`.
#[no_mangle]
pub extern "C" fn wickra_trin_new() -> *mut Trin {
Box::into_raw(Box::new(Trin::new()))
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_trin_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_trin_update(
handle: *mut Trin,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_trin_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trin_reset(handle: *mut Trin) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_trin_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_trin_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_trin_free(handle: *mut Trin) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `UpDownVolumeRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_up_down_volume_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_up_down_volume_ratio_new() -> *mut UpDownVolumeRatio {
Box::into_raw(Box::new(UpDownVolumeRatio::new()))
}
/// Feed one cross-sectional snapshot as parallel per-member arrays; returns the output,
/// or `NaN` during warmup / on a `NULL` handle / if the snapshot is invalid.
///
/// # Safety
/// `handle` valid (from `wickra_up_down_volume_ratio_new`, not freed) or `NULL`. Every member array
/// covers `n` elements.
#[no_mangle]
#[allow(clippy::needless_range_loop)]
pub unsafe extern "C" fn wickra_up_down_volume_ratio_update(
handle: *mut UpDownVolumeRatio,
change: *const f64,
volume: *const f64,
new_high: *const bool,
new_low: *const bool,
above_ma: *const bool,
on_buy_signal: *const bool,
n: usize,
timestamp: i64,
) -> f64 {
let Some(ind) = handle.as_mut() else {
return f64::NAN;
};
if change.is_null()
|| volume.is_null()
|| new_high.is_null()
|| new_low.is_null()
|| above_ma.is_null()
|| on_buy_signal.is_null()
{
return f64::NAN;
}
let changes = slice::from_raw_parts(change, n);
let volumes = slice::from_raw_parts(volume, n);
let new_highs = slice::from_raw_parts(new_high, n);
let new_lows = slice::from_raw_parts(new_low, n);
let above_mas = slice::from_raw_parts(above_ma, n);
let on_buy_signals = slice::from_raw_parts(on_buy_signal, n);
let mut members = Vec::with_capacity(n);
for idx in 0..n {
let mut member = Member::new(changes[idx], volumes[idx], new_highs[idx], new_lows[idx]);
member.above_ma = above_mas[idx];
member.on_buy_signal = on_buy_signals[idx];
members.push(member);
}
match CrossSection::new(members, timestamp) {
Ok(snapshot) => ind.update(snapshot).unwrap_or(f64::NAN),
Err(_) => f64::NAN,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_up_down_volume_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_up_down_volume_ratio_reset(handle: *mut UpDownVolumeRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_up_down_volume_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_up_down_volume_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_up_down_volume_ratio_free(handle: *mut UpDownVolumeRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
// ===== Multi-output indicators (fixed-size struct via out-param) =====
/// C-ABI view of `AccelerationBandsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraAccelerationBandsOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
}
/// C-ABI view of `AdxOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraAdxOutput {
pub plus_di: f64,
pub minus_di: f64,
pub adx: f64,
}
/// C-ABI view of `AlligatorOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraAlligatorOutput {
pub jaw: f64,
pub teeth: f64,
pub lips: f64,
}
/// C-ABI view of `AndrewsPitchforkOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraAndrewsPitchforkOutput {
pub median: f64,
pub upper: f64,
pub lower: f64,
}
/// C-ABI view of `AroonOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraAroonOutput {
pub up: f64,
pub down: f64,
}
/// C-ABI view of `AtrBandsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraAtrBandsOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
}
/// C-ABI view of `AtrRatchetOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraAtrRatchetOutput {
pub value: f64,
pub direction: f64,
}
/// C-ABI view of `AutoFibOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraAutoFibOutput {
pub level_0: f64,
pub level_236: f64,
pub level_382: f64,
pub level_500: f64,
pub level_618: f64,
pub level_786: f64,
pub level_1000: f64,
}
/// C-ABI view of `BollingerOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraBollingerOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
pub stddev: f64,
}
/// C-ABI view of `BomarBandsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraBomarBandsOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
}
/// C-ABI view of `CamarillaPivotsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraCamarillaPivotsOutput {
pub pp: f64,
pub r1: f64,
pub r2: f64,
pub r3: f64,
pub r4: f64,
pub s1: f64,
pub s2: f64,
pub s3: f64,
pub s4: f64,
}
/// C-ABI view of `CandleVolumeOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraCandleVolumeOutput {
pub body: f64,
pub width: f64,
}
/// C-ABI view of `CentralPivotRangeOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraCentralPivotRangeOutput {
pub pivot: f64,
pub tc: f64,
pub bc: f64,
}
/// C-ABI view of `ChandeKrollStopOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraChandeKrollStopOutput {
pub stop_long: f64,
pub stop_short: f64,
}
/// C-ABI view of `ChandelierExitOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraChandelierExitOutput {
pub long_stop: f64,
pub short_stop: f64,
}
/// C-ABI view of `ClassicPivotsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraClassicPivotsOutput {
pub pp: f64,
pub r1: f64,
pub r2: f64,
pub r3: f64,
pub s1: f64,
pub s2: f64,
pub s3: f64,
}
/// C-ABI view of `CointegrationOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraCointegrationOutput {
pub hedge_ratio: f64,
pub spread: f64,
pub adf_stat: f64,
}
/// C-ABI view of `CompositeProfileOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraCompositeProfileOutput {
pub poc: f64,
pub vah: f64,
pub val: f64,
}
/// C-ABI view of `DemarkPivotsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraDemarkPivotsOutput {
pub pp: f64,
pub r1: f64,
pub s1: f64,
}
/// C-ABI view of `DonchianOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraDonchianOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
}
/// C-ABI view of `DonchianStopOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraDonchianStopOutput {
pub stop_long: f64,
pub stop_short: f64,
}
/// C-ABI view of `DoubleBollingerOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraDoubleBollingerOutput {
pub upper_outer: f64,
pub upper_inner: f64,
pub middle: f64,
pub lower_inner: f64,
pub lower_outer: f64,
}
/// C-ABI view of `ElderRayOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraElderRayOutput {
pub bull_power: f64,
pub bear_power: f64,
}
/// C-ABI view of `ElderSafeZoneOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraElderSafeZoneOutput {
pub value: f64,
pub direction: f64,
}
/// C-ABI view of `EquivolumeOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraEquivolumeOutput {
pub height: f64,
pub width: f64,
}
/// C-ABI view of `FibArcsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraFibArcsOutput {
pub arc_382: f64,
pub arc_500: f64,
pub arc_618: f64,
}
/// C-ABI view of `FibChannelOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraFibChannelOutput {
pub base: f64,
pub level_618: f64,
pub level_1000: f64,
pub level_1618: f64,
}
/// C-ABI view of `FibConfluenceOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraFibConfluenceOutput {
pub price: f64,
pub strength: f64,
}
/// C-ABI view of `FibExtensionOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraFibExtensionOutput {
pub level_1272: f64,
pub level_1414: f64,
pub level_1618: f64,
pub level_2000: f64,
pub level_2618: f64,
}
/// C-ABI view of `FibFanOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraFibFanOutput {
pub fan_382: f64,
pub fan_500: f64,
pub fan_618: f64,
}
/// C-ABI view of `FibProjectionOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraFibProjectionOutput {
pub level_618: f64,
pub level_1000: f64,
pub level_1618: f64,
pub level_2618: f64,
}
/// C-ABI view of `FibRetracementOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraFibRetracementOutput {
pub level_0: f64,
pub level_236: f64,
pub level_382: f64,
pub level_500: f64,
pub level_618: f64,
pub level_786: f64,
pub level_1000: f64,
}
/// C-ABI view of `FibTimeZonesOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraFibTimeZonesOutput {
pub on_zone: f64,
pub bars_to_next: f64,
}
/// C-ABI view of `FibonacciPivotsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraFibonacciPivotsOutput {
pub pp: f64,
pub r1: f64,
pub r2: f64,
pub r3: f64,
pub s1: f64,
pub s2: f64,
pub s3: f64,
}
/// C-ABI view of `FractalChaosBandsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraFractalChaosBandsOutput {
pub upper: f64,
pub lower: f64,
}
/// C-ABI view of `GatorOscillatorOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraGatorOscillatorOutput {
pub upper: f64,
pub lower: f64,
}
/// C-ABI view of `GoldenPocketOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraGoldenPocketOutput {
pub low: f64,
pub mid: f64,
pub high: f64,
}
/// C-ABI view of `HeikinAshiOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraHeikinAshiOutput {
pub open: f64,
pub high: f64,
pub low: f64,
pub close: f64,
}
/// C-ABI view of `HighLowVolumeNodesOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraHighLowVolumeNodesOutput {
pub hvn: f64,
pub lvn: f64,
}
/// C-ABI view of `HtPhasorOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraHtPhasorOutput {
pub inphase: f64,
pub quadrature: f64,
}
/// C-ABI view of `HurstChannelOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraHurstChannelOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
}
/// C-ABI view of `IchimokuOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraIchimokuOutput {
pub tenkan: f64,
pub kijun: f64,
pub senkou_a: f64,
pub senkou_b: f64,
pub chikou: f64,
}
/// C-ABI view of `InitialBalanceOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraInitialBalanceOutput {
pub high: f64,
pub low: f64,
}
/// C-ABI view of `KalmanHedgeRatioOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraKalmanHedgeRatioOutput {
pub hedge_ratio: f64,
pub intercept: f64,
pub spread: f64,
}
/// C-ABI view of `KaseDevStopOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraKaseDevStopOutput {
pub value: f64,
pub direction: f64,
}
/// C-ABI view of `KasePermissionStochasticOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraKasePermissionStochasticOutput {
pub fast: f64,
pub slow: f64,
}
/// C-ABI view of `KeltnerOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraKeltnerOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
}
/// C-ABI view of `KstOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraKstOutput {
pub kst: f64,
pub signal: f64,
}
/// C-ABI view of `LeadLagCrossCorrelationOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraLeadLagCrossCorrelationOutput {
pub lag: i64,
pub correlation: f64,
}
/// C-ABI view of `LinRegChannelOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraLinRegChannelOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
}
/// C-ABI view of `LiquidationFeaturesOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraLiquidationFeaturesOutput {
pub long: f64,
pub short: f64,
pub net: f64,
pub total: f64,
pub imbalance: f64,
}
/// C-ABI view of `MaEnvelopeOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraMaEnvelopeOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
}
/// C-ABI view of `MacdOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraMacdOutput {
pub macd: f64,
pub signal: f64,
pub histogram: f64,
}
/// C-ABI view of `MamaOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraMamaOutput {
pub mama: f64,
pub fama: f64,
}
/// C-ABI view of `MedianChannelOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraMedianChannelOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
}
/// C-ABI view of `ModifiedMaStopOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraModifiedMaStopOutput {
pub value: f64,
pub direction: f64,
}
/// C-ABI view of `MurreyMathLinesOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraMurreyMathLinesOutput {
pub mm8_8: f64,
pub mm7_8: f64,
pub mm6_8: f64,
pub mm5_8: f64,
pub mm4_8: f64,
pub mm3_8: f64,
pub mm2_8: f64,
pub mm1_8: f64,
pub mm0_8: f64,
}
/// C-ABI view of `NrtrOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraNrtrOutput {
pub value: f64,
pub direction: f64,
}
/// C-ABI view of `OpeningRangeOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraOpeningRangeOutput {
pub high: f64,
pub low: f64,
pub breakout_distance: f64,
}
/// C-ABI view of `OvernightIntradayReturnOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraOvernightIntradayReturnOutput {
pub overnight: f64,
pub intraday: f64,
}
/// C-ABI view of `ProjectionBandsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraProjectionBandsOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
}
/// C-ABI view of `QqeOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraQqeOutput {
pub rsi_ma: f64,
pub trailing_line: f64,
}
/// C-ABI view of `QuartileBandsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraQuartileBandsOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
}
/// C-ABI view of `RelativeStrengthOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraRelativeStrengthOutput {
pub ratio: f64,
pub ratio_ma: f64,
pub ratio_rsi: f64,
}
/// C-ABI view of `RwiOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraRwiOutput {
pub high: f64,
pub low: f64,
}
/// C-ABI view of `SessionHighLowOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraSessionHighLowOutput {
pub high: f64,
pub low: f64,
}
/// C-ABI view of `SessionRangeOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraSessionRangeOutput {
pub asia: f64,
pub eu: f64,
pub us: f64,
}
/// C-ABI view of `SmoothedHeikinAshiOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraSmoothedHeikinAshiOutput {
pub open: f64,
pub high: f64,
pub low: f64,
pub close: f64,
}
/// C-ABI view of `SpreadBollingerBandsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraSpreadBollingerBandsOutput {
pub middle: f64,
pub upper: f64,
pub lower: f64,
pub percent_b: f64,
}
/// C-ABI view of `StandardErrorBandsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraStandardErrorBandsOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
}
/// C-ABI view of `StarcBandsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraStarcBandsOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
}
/// C-ABI view of `StochasticOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraStochasticOutput {
pub k: f64,
pub d: f64,
}
/// C-ABI view of `SuperTrendOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraSuperTrendOutput {
pub value: f64,
pub direction: f64,
}
/// C-ABI view of `TdLinesOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraTdLinesOutput {
pub resistance: f64,
pub support: f64,
}
/// C-ABI view of `TdMovingAverageOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraTdMovingAverageOutput {
pub st1: f64,
pub st2: f64,
}
/// C-ABI view of `TdRangeProjectionOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraTdRangeProjectionOutput {
pub high: f64,
pub low: f64,
}
/// C-ABI view of `TdRiskLevelOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraTdRiskLevelOutput {
pub buy_risk: f64,
pub sell_risk: f64,
}
/// C-ABI view of `TdSequentialOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraTdSequentialOutput {
pub setup: f64,
pub countdown: f64,
pub direction: f64,
}
/// C-ABI view of `TtmSqueezeOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraTtmSqueezeOutput {
pub squeeze: f64,
pub momentum: f64,
}
/// C-ABI view of `ValueAreaOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraValueAreaOutput {
pub poc: f64,
pub vah: f64,
pub val: f64,
}
/// C-ABI view of `VolatilityConeOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraVolatilityConeOutput {
pub current: f64,
pub min: f64,
pub median: f64,
pub max: f64,
pub percentile: f64,
}
/// C-ABI view of `VolumeWeightedMacdOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraVolumeWeightedMacdOutput {
pub macd: f64,
pub signal: f64,
pub histogram: f64,
}
/// C-ABI view of `VolumeWeightedSrOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraVolumeWeightedSrOutput {
pub support: f64,
pub resistance: f64,
}
/// C-ABI view of `VortexOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraVortexOutput {
pub plus: f64,
pub minus: f64,
}
/// C-ABI view of `VwapStdDevBandsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraVwapStdDevBandsOutput {
pub upper: f64,
pub middle: f64,
pub lower: f64,
pub stddev: f64,
}
/// C-ABI view of `WaveTrendOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraWaveTrendOutput {
pub wt1: f64,
pub wt2: f64,
}
/// C-ABI view of `WilliamsFractalsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraWilliamsFractalsOutput {
pub up: f64,
pub down: f64,
}
/// C-ABI view of `WoodiePivotsOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraWoodiePivotsOutput {
pub pp: f64,
pub r1: f64,
pub r2: f64,
pub s1: f64,
pub s2: f64,
}
/// C-ABI view of `ZeroLagMacdOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraZeroLagMacdOutput {
pub macd: f64,
pub signal: f64,
pub histogram: f64,
}
/// C-ABI view of `ZigZagOutput` (fixed-size; `Option<f64>` fields surface as `NaN`).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraZigZagOutput {
pub swing: f64,
pub direction: f64,
}
/// Create a `AccelerationBands` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_acceleration_bands_free`.
#[no_mangle]
pub extern "C" fn wickra_acceleration_bands_new(
period: usize,
factor: f64,
) -> *mut AccelerationBands {
match AccelerationBands::new(period, factor) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_acceleration_bands_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_acceleration_bands_update(
handle: *mut AccelerationBands,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraAccelerationBandsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraAccelerationBandsOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_acceleration_bands_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_acceleration_bands_reset(handle: *mut AccelerationBands) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_acceleration_bands_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_acceleration_bands_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_acceleration_bands_free(handle: *mut AccelerationBands) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Adx` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_adx_free`.
#[no_mangle]
pub extern "C" fn wickra_adx_new(period: usize) -> *mut Adx {
match Adx::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_adx_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adx_update(
handle: *mut Adx,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraAdxOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraAdxOutput {
plus_di: out_val.plus_di,
minus_di: out_val.minus_di,
adx: out_val.adx,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_adx_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adx_reset(handle: *mut Adx) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_adx_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_adx_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_adx_free(handle: *mut Adx) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Alligator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_alligator_free`.
#[no_mangle]
pub extern "C" fn wickra_alligator_new(
jaw_period: usize,
teeth_period: usize,
lips_period: usize,
) -> *mut Alligator {
match Alligator::new(jaw_period, teeth_period, lips_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_alligator_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_alligator_update(
handle: *mut Alligator,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraAlligatorOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraAlligatorOutput {
jaw: out_val.jaw,
teeth: out_val.teeth,
lips: out_val.lips,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_alligator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_alligator_reset(handle: *mut Alligator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_alligator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_alligator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_alligator_free(handle: *mut Alligator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AndrewsPitchfork` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_andrews_pitchfork_free`.
#[no_mangle]
pub extern "C" fn wickra_andrews_pitchfork_new(strength: usize) -> *mut AndrewsPitchfork {
match AndrewsPitchfork::new(strength) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_andrews_pitchfork_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_andrews_pitchfork_update(
handle: *mut AndrewsPitchfork,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraAndrewsPitchforkOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraAndrewsPitchforkOutput {
median: out_val.median,
upper: out_val.upper,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_andrews_pitchfork_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_andrews_pitchfork_reset(handle: *mut AndrewsPitchfork) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_andrews_pitchfork_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_andrews_pitchfork_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_andrews_pitchfork_free(handle: *mut AndrewsPitchfork) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Aroon` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_aroon_free`.
#[no_mangle]
pub extern "C" fn wickra_aroon_new(period: usize) -> *mut Aroon {
match Aroon::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_aroon_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_aroon_update(
handle: *mut Aroon,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraAroonOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraAroonOutput {
up: out_val.up,
down: out_val.down,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_aroon_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_aroon_reset(handle: *mut Aroon) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_aroon_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_aroon_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_aroon_free(handle: *mut Aroon) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AtrBands` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_atr_bands_free`.
#[no_mangle]
pub extern "C" fn wickra_atr_bands_new(period: usize, multiplier: f64) -> *mut AtrBands {
match AtrBands::new(period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_atr_bands_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_atr_bands_update(
handle: *mut AtrBands,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraAtrBandsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraAtrBandsOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_atr_bands_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_atr_bands_reset(handle: *mut AtrBands) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_atr_bands_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_atr_bands_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_atr_bands_free(handle: *mut AtrBands) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AtrRatchet` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_atr_ratchet_free`.
#[no_mangle]
pub extern "C" fn wickra_atr_ratchet_new(
atr_period: usize,
start_mult: f64,
increment: f64,
) -> *mut AtrRatchet {
match AtrRatchet::new(atr_period, start_mult, increment) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_atr_ratchet_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_atr_ratchet_update(
handle: *mut AtrRatchet,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraAtrRatchetOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraAtrRatchetOutput {
value: out_val.value,
direction: out_val.direction,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_atr_ratchet_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_atr_ratchet_reset(handle: *mut AtrRatchet) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_atr_ratchet_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_atr_ratchet_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_atr_ratchet_free(handle: *mut AtrRatchet) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `AutoFib` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_auto_fib_free`.
#[no_mangle]
pub extern "C" fn wickra_auto_fib_new() -> *mut AutoFib {
Box::into_raw(Box::new(AutoFib::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_auto_fib_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_auto_fib_update(
handle: *mut AutoFib,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraAutoFibOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraAutoFibOutput {
level_0: out_val.level_0,
level_236: out_val.level_236,
level_382: out_val.level_382,
level_500: out_val.level_500,
level_618: out_val.level_618,
level_786: out_val.level_786,
level_1000: out_val.level_1000,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_auto_fib_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_auto_fib_reset(handle: *mut AutoFib) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_auto_fib_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_auto_fib_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_auto_fib_free(handle: *mut AutoFib) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `BollingerBands` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_bollinger_bands_free`.
#[no_mangle]
pub extern "C" fn wickra_bollinger_bands_new(
period: usize,
multiplier: f64,
) -> *mut BollingerBands {
match BollingerBands::new(period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_bollinger_bands_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bollinger_bands_update(
handle: *mut BollingerBands,
value: f64,
out: *mut WickraBollingerOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraBollingerOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
stddev: out_val.stddev,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_bollinger_bands_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bollinger_bands_reset(handle: *mut BollingerBands) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_bollinger_bands_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_bollinger_bands_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bollinger_bands_free(handle: *mut BollingerBands) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `BomarBands` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_bomar_bands_free`.
#[no_mangle]
pub extern "C" fn wickra_bomar_bands_new(period: usize, coverage: f64) -> *mut BomarBands {
match BomarBands::new(period, coverage) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_bomar_bands_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bomar_bands_update(
handle: *mut BomarBands,
value: f64,
out: *mut WickraBomarBandsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraBomarBandsOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_bomar_bands_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bomar_bands_reset(handle: *mut BomarBands) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_bomar_bands_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_bomar_bands_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_bomar_bands_free(handle: *mut BomarBands) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Camarilla` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_camarilla_free`.
#[no_mangle]
pub extern "C" fn wickra_camarilla_new() -> *mut Camarilla {
Box::into_raw(Box::new(Camarilla::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_camarilla_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_camarilla_update(
handle: *mut Camarilla,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraCamarillaPivotsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraCamarillaPivotsOutput {
pp: out_val.pp,
r1: out_val.r1,
r2: out_val.r2,
r3: out_val.r3,
r4: out_val.r4,
s1: out_val.s1,
s2: out_val.s2,
s3: out_val.s3,
s4: out_val.s4,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_camarilla_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_camarilla_reset(handle: *mut Camarilla) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_camarilla_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_camarilla_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_camarilla_free(handle: *mut Camarilla) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `CandleVolume` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_candle_volume_free`.
#[no_mangle]
pub extern "C" fn wickra_candle_volume_new(period: usize) -> *mut CandleVolume {
match CandleVolume::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_candle_volume_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_candle_volume_update(
handle: *mut CandleVolume,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraCandleVolumeOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraCandleVolumeOutput {
body: out_val.body,
width: out_val.width,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_candle_volume_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_candle_volume_reset(handle: *mut CandleVolume) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_candle_volume_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_candle_volume_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_candle_volume_free(handle: *mut CandleVolume) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `CentralPivotRange` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_central_pivot_range_free`.
#[no_mangle]
pub extern "C" fn wickra_central_pivot_range_new() -> *mut CentralPivotRange {
Box::into_raw(Box::new(CentralPivotRange::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_central_pivot_range_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_central_pivot_range_update(
handle: *mut CentralPivotRange,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraCentralPivotRangeOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraCentralPivotRangeOutput {
pivot: out_val.pivot,
tc: out_val.tc,
bc: out_val.bc,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_central_pivot_range_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_central_pivot_range_reset(handle: *mut CentralPivotRange) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_central_pivot_range_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_central_pivot_range_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_central_pivot_range_free(handle: *mut CentralPivotRange) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ChandeKrollStop` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_chande_kroll_stop_free`.
#[no_mangle]
pub extern "C" fn wickra_chande_kroll_stop_new(
atr_period: usize,
atr_multiplier: f64,
stop_period: usize,
) -> *mut ChandeKrollStop {
match ChandeKrollStop::new(atr_period, atr_multiplier, stop_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_chande_kroll_stop_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chande_kroll_stop_update(
handle: *mut ChandeKrollStop,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraChandeKrollStopOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraChandeKrollStopOutput {
stop_long: out_val.stop_long,
stop_short: out_val.stop_short,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_chande_kroll_stop_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chande_kroll_stop_reset(handle: *mut ChandeKrollStop) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_chande_kroll_stop_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_chande_kroll_stop_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chande_kroll_stop_free(handle: *mut ChandeKrollStop) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ChandelierExit` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_chandelier_exit_free`.
#[no_mangle]
pub extern "C" fn wickra_chandelier_exit_new(
period: usize,
multiplier: f64,
) -> *mut ChandelierExit {
match ChandelierExit::new(period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_chandelier_exit_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chandelier_exit_update(
handle: *mut ChandelierExit,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraChandelierExitOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraChandelierExitOutput {
long_stop: out_val.long_stop,
short_stop: out_val.short_stop,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_chandelier_exit_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chandelier_exit_reset(handle: *mut ChandelierExit) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_chandelier_exit_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_chandelier_exit_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_chandelier_exit_free(handle: *mut ChandelierExit) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ClassicPivots` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_classic_pivots_free`.
#[no_mangle]
pub extern "C" fn wickra_classic_pivots_new() -> *mut ClassicPivots {
Box::into_raw(Box::new(ClassicPivots::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_classic_pivots_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_classic_pivots_update(
handle: *mut ClassicPivots,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraClassicPivotsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraClassicPivotsOutput {
pp: out_val.pp,
r1: out_val.r1,
r2: out_val.r2,
r3: out_val.r3,
s1: out_val.s1,
s2: out_val.s2,
s3: out_val.s3,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_classic_pivots_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_classic_pivots_reset(handle: *mut ClassicPivots) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_classic_pivots_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_classic_pivots_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_classic_pivots_free(handle: *mut ClassicPivots) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Cointegration` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_cointegration_free`.
#[no_mangle]
pub extern "C" fn wickra_cointegration_new(period: usize, adf_lags: usize) -> *mut Cointegration {
match Cointegration::new(period, adf_lags) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_cointegration_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cointegration_update(
handle: *mut Cointegration,
x: f64,
y: f64,
out: *mut WickraCointegrationOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update((x, y)) {
Some(out_val) => {
*out = WickraCointegrationOutput {
hedge_ratio: out_val.hedge_ratio,
spread: out_val.spread,
adf_stat: out_val.adf_stat,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_cointegration_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cointegration_reset(handle: *mut Cointegration) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_cointegration_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_cointegration_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_cointegration_free(handle: *mut Cointegration) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `CompositeProfile` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_composite_profile_free`.
#[no_mangle]
pub extern "C" fn wickra_composite_profile_new(
period: usize,
bins: usize,
value_area_pct: f64,
) -> *mut CompositeProfile {
match CompositeProfile::new(period, bins, value_area_pct) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_composite_profile_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_composite_profile_update(
handle: *mut CompositeProfile,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraCompositeProfileOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraCompositeProfileOutput {
poc: out_val.poc,
vah: out_val.vah,
val: out_val.val,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_composite_profile_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_composite_profile_reset(handle: *mut CompositeProfile) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_composite_profile_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_composite_profile_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_composite_profile_free(handle: *mut CompositeProfile) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DemarkPivots` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_demark_pivots_free`.
#[no_mangle]
pub extern "C" fn wickra_demark_pivots_new() -> *mut DemarkPivots {
Box::into_raw(Box::new(DemarkPivots::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_demark_pivots_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_demark_pivots_update(
handle: *mut DemarkPivots,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraDemarkPivotsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraDemarkPivotsOutput {
pp: out_val.pp,
r1: out_val.r1,
s1: out_val.s1,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_demark_pivots_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_demark_pivots_reset(handle: *mut DemarkPivots) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_demark_pivots_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_demark_pivots_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_demark_pivots_free(handle: *mut DemarkPivots) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Donchian` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_donchian_free`.
#[no_mangle]
pub extern "C" fn wickra_donchian_new(period: usize) -> *mut Donchian {
match Donchian::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_donchian_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_donchian_update(
handle: *mut Donchian,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraDonchianOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraDonchianOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_donchian_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_donchian_reset(handle: *mut Donchian) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_donchian_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_donchian_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_donchian_free(handle: *mut Donchian) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DonchianStop` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_donchian_stop_free`.
#[no_mangle]
pub extern "C" fn wickra_donchian_stop_new(period: usize) -> *mut DonchianStop {
match DonchianStop::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_donchian_stop_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_donchian_stop_update(
handle: *mut DonchianStop,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraDonchianStopOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraDonchianStopOutput {
stop_long: out_val.stop_long,
stop_short: out_val.stop_short,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_donchian_stop_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_donchian_stop_reset(handle: *mut DonchianStop) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_donchian_stop_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_donchian_stop_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_donchian_stop_free(handle: *mut DonchianStop) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `DoubleBollinger` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_double_bollinger_free`.
#[no_mangle]
pub extern "C" fn wickra_double_bollinger_new(
period: usize,
k_inner: f64,
k_outer: f64,
) -> *mut DoubleBollinger {
match DoubleBollinger::new(period, k_inner, k_outer) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_double_bollinger_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_double_bollinger_update(
handle: *mut DoubleBollinger,
value: f64,
out: *mut WickraDoubleBollingerOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraDoubleBollingerOutput {
upper_outer: out_val.upper_outer,
upper_inner: out_val.upper_inner,
middle: out_val.middle,
lower_inner: out_val.lower_inner,
lower_outer: out_val.lower_outer,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_double_bollinger_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_double_bollinger_reset(handle: *mut DoubleBollinger) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_double_bollinger_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_double_bollinger_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_double_bollinger_free(handle: *mut DoubleBollinger) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ElderRay` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_elder_ray_free`.
#[no_mangle]
pub extern "C" fn wickra_elder_ray_new(period: usize) -> *mut ElderRay {
match ElderRay::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_elder_ray_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_elder_ray_update(
handle: *mut ElderRay,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraElderRayOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraElderRayOutput {
bull_power: out_val.bull_power,
bear_power: out_val.bear_power,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_elder_ray_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_elder_ray_reset(handle: *mut ElderRay) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_elder_ray_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_elder_ray_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_elder_ray_free(handle: *mut ElderRay) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ElderSafeZone` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_elder_safe_zone_free`.
#[no_mangle]
pub extern "C" fn wickra_elder_safe_zone_new(period: usize, coeff: f64) -> *mut ElderSafeZone {
match ElderSafeZone::new(period, coeff) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_elder_safe_zone_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_elder_safe_zone_update(
handle: *mut ElderSafeZone,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraElderSafeZoneOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraElderSafeZoneOutput {
value: out_val.value,
direction: out_val.direction,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_elder_safe_zone_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_elder_safe_zone_reset(handle: *mut ElderSafeZone) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_elder_safe_zone_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_elder_safe_zone_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_elder_safe_zone_free(handle: *mut ElderSafeZone) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Equivolume` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_equivolume_free`.
#[no_mangle]
pub extern "C" fn wickra_equivolume_new(period: usize) -> *mut Equivolume {
match Equivolume::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_equivolume_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_equivolume_update(
handle: *mut Equivolume,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraEquivolumeOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraEquivolumeOutput {
height: out_val.height,
width: out_val.width,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_equivolume_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_equivolume_reset(handle: *mut Equivolume) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_equivolume_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_equivolume_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_equivolume_free(handle: *mut Equivolume) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FibArcs` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_fib_arcs_free`.
#[no_mangle]
pub extern "C" fn wickra_fib_arcs_new() -> *mut FibArcs {
Box::into_raw(Box::new(FibArcs::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_fib_arcs_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_arcs_update(
handle: *mut FibArcs,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraFibArcsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraFibArcsOutput {
arc_382: out_val.arc_382,
arc_500: out_val.arc_500,
arc_618: out_val.arc_618,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_fib_arcs_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_arcs_reset(handle: *mut FibArcs) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_fib_arcs_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_fib_arcs_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_arcs_free(handle: *mut FibArcs) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FibChannel` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_fib_channel_free`.
#[no_mangle]
pub extern "C" fn wickra_fib_channel_new() -> *mut FibChannel {
Box::into_raw(Box::new(FibChannel::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_fib_channel_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_channel_update(
handle: *mut FibChannel,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraFibChannelOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraFibChannelOutput {
base: out_val.base,
level_618: out_val.level_618,
level_1000: out_val.level_1000,
level_1618: out_val.level_1618,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_fib_channel_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_channel_reset(handle: *mut FibChannel) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_fib_channel_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_fib_channel_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_channel_free(handle: *mut FibChannel) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FibConfluence` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_fib_confluence_free`.
#[no_mangle]
pub extern "C" fn wickra_fib_confluence_new() -> *mut FibConfluence {
Box::into_raw(Box::new(FibConfluence::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_fib_confluence_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_confluence_update(
handle: *mut FibConfluence,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraFibConfluenceOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraFibConfluenceOutput {
price: out_val.price,
strength: out_val.strength,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_fib_confluence_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_confluence_reset(handle: *mut FibConfluence) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_fib_confluence_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_fib_confluence_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_confluence_free(handle: *mut FibConfluence) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FibExtension` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_fib_extension_free`.
#[no_mangle]
pub extern "C" fn wickra_fib_extension_new() -> *mut FibExtension {
Box::into_raw(Box::new(FibExtension::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_fib_extension_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_extension_update(
handle: *mut FibExtension,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraFibExtensionOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraFibExtensionOutput {
level_1272: out_val.level_1272,
level_1414: out_val.level_1414,
level_1618: out_val.level_1618,
level_2000: out_val.level_2000,
level_2618: out_val.level_2618,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_fib_extension_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_extension_reset(handle: *mut FibExtension) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_fib_extension_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_fib_extension_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_extension_free(handle: *mut FibExtension) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FibFan` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_fib_fan_free`.
#[no_mangle]
pub extern "C" fn wickra_fib_fan_new() -> *mut FibFan {
Box::into_raw(Box::new(FibFan::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_fib_fan_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_fan_update(
handle: *mut FibFan,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraFibFanOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraFibFanOutput {
fan_382: out_val.fan_382,
fan_500: out_val.fan_500,
fan_618: out_val.fan_618,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_fib_fan_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_fan_reset(handle: *mut FibFan) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_fib_fan_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_fib_fan_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_fan_free(handle: *mut FibFan) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FibProjection` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_fib_projection_free`.
#[no_mangle]
pub extern "C" fn wickra_fib_projection_new() -> *mut FibProjection {
Box::into_raw(Box::new(FibProjection::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_fib_projection_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_projection_update(
handle: *mut FibProjection,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraFibProjectionOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraFibProjectionOutput {
level_618: out_val.level_618,
level_1000: out_val.level_1000,
level_1618: out_val.level_1618,
level_2618: out_val.level_2618,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_fib_projection_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_projection_reset(handle: *mut FibProjection) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_fib_projection_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_fib_projection_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_projection_free(handle: *mut FibProjection) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FibRetracement` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_fib_retracement_free`.
#[no_mangle]
pub extern "C" fn wickra_fib_retracement_new() -> *mut FibRetracement {
Box::into_raw(Box::new(FibRetracement::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_fib_retracement_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_retracement_update(
handle: *mut FibRetracement,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraFibRetracementOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraFibRetracementOutput {
level_0: out_val.level_0,
level_236: out_val.level_236,
level_382: out_val.level_382,
level_500: out_val.level_500,
level_618: out_val.level_618,
level_786: out_val.level_786,
level_1000: out_val.level_1000,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_fib_retracement_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_retracement_reset(handle: *mut FibRetracement) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_fib_retracement_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_fib_retracement_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_retracement_free(handle: *mut FibRetracement) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FibTimeZones` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_fib_time_zones_free`.
#[no_mangle]
pub extern "C" fn wickra_fib_time_zones_new() -> *mut FibTimeZones {
Box::into_raw(Box::new(FibTimeZones::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_fib_time_zones_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_time_zones_update(
handle: *mut FibTimeZones,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraFibTimeZonesOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraFibTimeZonesOutput {
on_zone: out_val.on_zone,
bars_to_next: out_val.bars_to_next,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_fib_time_zones_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_time_zones_reset(handle: *mut FibTimeZones) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_fib_time_zones_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_fib_time_zones_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fib_time_zones_free(handle: *mut FibTimeZones) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FibonacciPivots` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_fibonacci_pivots_free`.
#[no_mangle]
pub extern "C" fn wickra_fibonacci_pivots_new() -> *mut FibonacciPivots {
Box::into_raw(Box::new(FibonacciPivots::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_fibonacci_pivots_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fibonacci_pivots_update(
handle: *mut FibonacciPivots,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraFibonacciPivotsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraFibonacciPivotsOutput {
pp: out_val.pp,
r1: out_val.r1,
r2: out_val.r2,
r3: out_val.r3,
s1: out_val.s1,
s2: out_val.s2,
s3: out_val.s3,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_fibonacci_pivots_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fibonacci_pivots_reset(handle: *mut FibonacciPivots) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_fibonacci_pivots_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_fibonacci_pivots_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fibonacci_pivots_free(handle: *mut FibonacciPivots) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `FractalChaosBands` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_fractal_chaos_bands_free`.
#[no_mangle]
pub extern "C" fn wickra_fractal_chaos_bands_new(k: usize) -> *mut FractalChaosBands {
match FractalChaosBands::new(k) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_fractal_chaos_bands_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fractal_chaos_bands_update(
handle: *mut FractalChaosBands,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraFractalChaosBandsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraFractalChaosBandsOutput {
upper: out_val.upper,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_fractal_chaos_bands_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fractal_chaos_bands_reset(handle: *mut FractalChaosBands) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_fractal_chaos_bands_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_fractal_chaos_bands_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_fractal_chaos_bands_free(handle: *mut FractalChaosBands) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `GatorOscillator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_gator_oscillator_free`.
#[no_mangle]
pub extern "C" fn wickra_gator_oscillator_new(
jaw_period: usize,
teeth_period: usize,
lips_period: usize,
) -> *mut GatorOscillator {
match GatorOscillator::new(jaw_period, teeth_period, lips_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_gator_oscillator_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gator_oscillator_update(
handle: *mut GatorOscillator,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraGatorOscillatorOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraGatorOscillatorOutput {
upper: out_val.upper,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_gator_oscillator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gator_oscillator_reset(handle: *mut GatorOscillator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_gator_oscillator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_gator_oscillator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_gator_oscillator_free(handle: *mut GatorOscillator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `GoldenPocket` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_golden_pocket_free`.
#[no_mangle]
pub extern "C" fn wickra_golden_pocket_new() -> *mut GoldenPocket {
Box::into_raw(Box::new(GoldenPocket::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_golden_pocket_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_golden_pocket_update(
handle: *mut GoldenPocket,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraGoldenPocketOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraGoldenPocketOutput {
low: out_val.low,
mid: out_val.mid,
high: out_val.high,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_golden_pocket_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_golden_pocket_reset(handle: *mut GoldenPocket) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_golden_pocket_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_golden_pocket_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_golden_pocket_free(handle: *mut GoldenPocket) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HeikinAshi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_heikin_ashi_free`.
#[no_mangle]
pub extern "C" fn wickra_heikin_ashi_new() -> *mut HeikinAshi {
Box::into_raw(Box::new(HeikinAshi::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_heikin_ashi_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_heikin_ashi_update(
handle: *mut HeikinAshi,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraHeikinAshiOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraHeikinAshiOutput {
open: out_val.open,
high: out_val.high,
low: out_val.low,
close: out_val.close,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_heikin_ashi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_heikin_ashi_reset(handle: *mut HeikinAshi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_heikin_ashi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_heikin_ashi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_heikin_ashi_free(handle: *mut HeikinAshi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HighLowVolumeNodes` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_high_low_volume_nodes_free`.
#[no_mangle]
pub extern "C" fn wickra_high_low_volume_nodes_new(
period: usize,
bins: usize,
) -> *mut HighLowVolumeNodes {
match HighLowVolumeNodes::new(period, bins) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_high_low_volume_nodes_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_high_low_volume_nodes_update(
handle: *mut HighLowVolumeNodes,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraHighLowVolumeNodesOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraHighLowVolumeNodesOutput {
hvn: out_val.hvn,
lvn: out_val.lvn,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_high_low_volume_nodes_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_high_low_volume_nodes_reset(handle: *mut HighLowVolumeNodes) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_high_low_volume_nodes_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_high_low_volume_nodes_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_high_low_volume_nodes_free(handle: *mut HighLowVolumeNodes) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HtPhasor` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ht_phasor_free`.
#[no_mangle]
pub extern "C" fn wickra_ht_phasor_new() -> *mut HtPhasor {
Box::into_raw(Box::new(HtPhasor::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_ht_phasor_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ht_phasor_update(
handle: *mut HtPhasor,
value: f64,
out: *mut WickraHtPhasorOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraHtPhasorOutput {
inphase: out_val.inphase,
quadrature: out_val.quadrature,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ht_phasor_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ht_phasor_reset(handle: *mut HtPhasor) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ht_phasor_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ht_phasor_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ht_phasor_free(handle: *mut HtPhasor) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `HurstChannel` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_hurst_channel_free`.
#[no_mangle]
pub extern "C" fn wickra_hurst_channel_new(period: usize, multiplier: f64) -> *mut HurstChannel {
match HurstChannel::new(period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_hurst_channel_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hurst_channel_update(
handle: *mut HurstChannel,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraHurstChannelOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraHurstChannelOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_hurst_channel_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hurst_channel_reset(handle: *mut HurstChannel) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_hurst_channel_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_hurst_channel_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_hurst_channel_free(handle: *mut HurstChannel) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Ichimoku` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ichimoku_free`.
#[no_mangle]
pub extern "C" fn wickra_ichimoku_new(
tenkan_period: usize,
kijun_period: usize,
senkou_b_period: usize,
displacement: usize,
) -> *mut Ichimoku {
match Ichimoku::new(tenkan_period, kijun_period, senkou_b_period, displacement) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_ichimoku_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ichimoku_update(
handle: *mut Ichimoku,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraIchimokuOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraIchimokuOutput {
tenkan: out_val.tenkan.unwrap_or(f64::NAN),
kijun: out_val.kijun.unwrap_or(f64::NAN),
senkou_a: out_val.senkou_a.unwrap_or(f64::NAN),
senkou_b: out_val.senkou_b.unwrap_or(f64::NAN),
chikou: out_val.chikou.unwrap_or(f64::NAN),
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ichimoku_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ichimoku_reset(handle: *mut Ichimoku) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ichimoku_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ichimoku_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ichimoku_free(handle: *mut Ichimoku) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `InitialBalance` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_initial_balance_free`.
#[no_mangle]
pub extern "C" fn wickra_initial_balance_new(period: usize) -> *mut InitialBalance {
match InitialBalance::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_initial_balance_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_initial_balance_update(
handle: *mut InitialBalance,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraInitialBalanceOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraInitialBalanceOutput {
high: out_val.high,
low: out_val.low,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_initial_balance_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_initial_balance_reset(handle: *mut InitialBalance) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_initial_balance_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_initial_balance_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_initial_balance_free(handle: *mut InitialBalance) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `KalmanHedgeRatio` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_kalman_hedge_ratio_free`.
#[no_mangle]
pub extern "C" fn wickra_kalman_hedge_ratio_new(
delta: f64,
observation_var: f64,
) -> *mut KalmanHedgeRatio {
match KalmanHedgeRatio::new(delta, observation_var) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_kalman_hedge_ratio_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kalman_hedge_ratio_update(
handle: *mut KalmanHedgeRatio,
x: f64,
y: f64,
out: *mut WickraKalmanHedgeRatioOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update((x, y)) {
Some(out_val) => {
*out = WickraKalmanHedgeRatioOutput {
hedge_ratio: out_val.hedge_ratio,
intercept: out_val.intercept,
spread: out_val.spread,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_kalman_hedge_ratio_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kalman_hedge_ratio_reset(handle: *mut KalmanHedgeRatio) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_kalman_hedge_ratio_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_kalman_hedge_ratio_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kalman_hedge_ratio_free(handle: *mut KalmanHedgeRatio) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `KaseDevStop` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_kase_dev_stop_free`.
#[no_mangle]
pub extern "C" fn wickra_kase_dev_stop_new(period: usize, dev: f64) -> *mut KaseDevStop {
match KaseDevStop::new(period, dev) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_kase_dev_stop_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kase_dev_stop_update(
handle: *mut KaseDevStop,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraKaseDevStopOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraKaseDevStopOutput {
value: out_val.value,
direction: out_val.direction,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_kase_dev_stop_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kase_dev_stop_reset(handle: *mut KaseDevStop) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_kase_dev_stop_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_kase_dev_stop_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kase_dev_stop_free(handle: *mut KaseDevStop) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `KasePermissionStochastic` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_kase_permission_stochastic_free`.
#[no_mangle]
pub extern "C" fn wickra_kase_permission_stochastic_new(
length: usize,
smooth: usize,
) -> *mut KasePermissionStochastic {
match KasePermissionStochastic::new(length, smooth) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_kase_permission_stochastic_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kase_permission_stochastic_update(
handle: *mut KasePermissionStochastic,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraKasePermissionStochasticOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraKasePermissionStochasticOutput {
fast: out_val.fast,
slow: out_val.slow,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_kase_permission_stochastic_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kase_permission_stochastic_reset(
handle: *mut KasePermissionStochastic,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_kase_permission_stochastic_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_kase_permission_stochastic_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kase_permission_stochastic_free(
handle: *mut KasePermissionStochastic,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Keltner` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_keltner_free`.
#[no_mangle]
pub extern "C" fn wickra_keltner_new(
ema_period: usize,
atr_period: usize,
multiplier: f64,
) -> *mut Keltner {
match Keltner::new(ema_period, atr_period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_keltner_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_keltner_update(
handle: *mut Keltner,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraKeltnerOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraKeltnerOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_keltner_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_keltner_reset(handle: *mut Keltner) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_keltner_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_keltner_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_keltner_free(handle: *mut Keltner) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Kst` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_kst_free`.
#[no_mangle]
pub extern "C" fn wickra_kst_new(
roc1: usize,
roc2: usize,
roc3: usize,
roc4: usize,
sma1: usize,
sma2: usize,
sma3: usize,
sma4: usize,
signal: usize,
) -> *mut Kst {
match Kst::new(roc1, roc2, roc3, roc4, sma1, sma2, sma3, sma4, signal) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_kst_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kst_update(
handle: *mut Kst,
value: f64,
out: *mut WickraKstOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraKstOutput {
kst: out_val.kst,
signal: out_val.signal,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_kst_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kst_reset(handle: *mut Kst) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_kst_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_kst_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kst_free(handle: *mut Kst) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `LeadLagCrossCorrelation` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_lead_lag_cross_correlation_free`.
#[no_mangle]
pub extern "C" fn wickra_lead_lag_cross_correlation_new(
window: usize,
max_lag: usize,
) -> *mut LeadLagCrossCorrelation {
match LeadLagCrossCorrelation::new(window, max_lag) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_lead_lag_cross_correlation_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lead_lag_cross_correlation_update(
handle: *mut LeadLagCrossCorrelation,
x: f64,
y: f64,
out: *mut WickraLeadLagCrossCorrelationOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update((x, y)) {
Some(out_val) => {
*out = WickraLeadLagCrossCorrelationOutput {
lag: out_val.lag,
correlation: out_val.correlation,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_lead_lag_cross_correlation_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lead_lag_cross_correlation_reset(
handle: *mut LeadLagCrossCorrelation,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_lead_lag_cross_correlation_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_lead_lag_cross_correlation_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lead_lag_cross_correlation_free(
handle: *mut LeadLagCrossCorrelation,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `LinRegChannel` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_lin_reg_channel_free`.
#[no_mangle]
pub extern "C" fn wickra_lin_reg_channel_new(period: usize, multiplier: f64) -> *mut LinRegChannel {
match LinRegChannel::new(period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_lin_reg_channel_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_channel_update(
handle: *mut LinRegChannel,
value: f64,
out: *mut WickraLinRegChannelOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraLinRegChannelOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_lin_reg_channel_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_channel_reset(handle: *mut LinRegChannel) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_lin_reg_channel_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_lin_reg_channel_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_lin_reg_channel_free(handle: *mut LinRegChannel) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `LiquidationFeatures` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_liquidation_features_free`.
#[no_mangle]
pub extern "C" fn wickra_liquidation_features_new() -> *mut LiquidationFeatures {
Box::into_raw(Box::new(LiquidationFeatures::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_liquidation_features_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_liquidation_features_update(
handle: *mut LiquidationFeatures,
funding_rate: f64,
mark_price: f64,
index_price: f64,
futures_price: f64,
open_interest: f64,
long_size: f64,
short_size: f64,
taker_buy_volume: f64,
taker_sell_volume: f64,
long_liquidation: f64,
short_liquidation: f64,
timestamp: i64,
out: *mut WickraLiquidationFeaturesOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = DerivativesTick::new(
funding_rate,
mark_price,
index_price,
futures_price,
open_interest,
long_size,
short_size,
taker_buy_volume,
taker_sell_volume,
long_liquidation,
short_liquidation,
timestamp,
) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraLiquidationFeaturesOutput {
long: out_val.long,
short: out_val.short,
net: out_val.net,
total: out_val.total,
imbalance: out_val.imbalance,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_liquidation_features_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_liquidation_features_reset(handle: *mut LiquidationFeatures) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_liquidation_features_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_liquidation_features_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_liquidation_features_free(handle: *mut LiquidationFeatures) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MaEnvelope` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ma_envelope_free`.
#[no_mangle]
pub extern "C" fn wickra_ma_envelope_new(period: usize, percent: f64) -> *mut MaEnvelope {
match MaEnvelope::new(period, percent) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_ma_envelope_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ma_envelope_update(
handle: *mut MaEnvelope,
value: f64,
out: *mut WickraMaEnvelopeOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraMaEnvelopeOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ma_envelope_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ma_envelope_reset(handle: *mut MaEnvelope) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ma_envelope_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ma_envelope_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ma_envelope_free(handle: *mut MaEnvelope) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MacdIndicator` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_macd_indicator_free`.
#[no_mangle]
pub extern "C" fn wickra_macd_indicator_new(
fast: usize,
slow: usize,
signal: usize,
) -> *mut MacdIndicator {
match MacdIndicator::new(fast, slow, signal) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_macd_indicator_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_macd_indicator_update(
handle: *mut MacdIndicator,
value: f64,
out: *mut WickraMacdOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraMacdOutput {
macd: out_val.macd,
signal: out_val.signal,
histogram: out_val.histogram,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_macd_indicator_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_macd_indicator_reset(handle: *mut MacdIndicator) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_macd_indicator_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_macd_indicator_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_macd_indicator_free(handle: *mut MacdIndicator) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MacdFix` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_macd_fix_free`.
#[no_mangle]
pub extern "C" fn wickra_macd_fix_new(signal: usize) -> *mut MacdFix {
match MacdFix::new(signal) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_macd_fix_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_macd_fix_update(
handle: *mut MacdFix,
value: f64,
out: *mut WickraMacdOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraMacdOutput {
macd: out_val.macd,
signal: out_val.signal,
histogram: out_val.histogram,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_macd_fix_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_macd_fix_reset(handle: *mut MacdFix) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_macd_fix_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_macd_fix_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_macd_fix_free(handle: *mut MacdFix) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Mama` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_mama_free`.
#[no_mangle]
pub extern "C" fn wickra_mama_new(fast_limit: f64, slow_limit: f64) -> *mut Mama {
match Mama::new(fast_limit, slow_limit) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_mama_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mama_update(
handle: *mut Mama,
value: f64,
out: *mut WickraMamaOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraMamaOutput {
mama: out_val.mama,
fama: out_val.fama,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_mama_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mama_reset(handle: *mut Mama) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_mama_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_mama_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_mama_free(handle: *mut Mama) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MedianChannel` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_median_channel_free`.
#[no_mangle]
pub extern "C" fn wickra_median_channel_new(period: usize, multiplier: f64) -> *mut MedianChannel {
match MedianChannel::new(period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_median_channel_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_channel_update(
handle: *mut MedianChannel,
value: f64,
out: *mut WickraMedianChannelOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraMedianChannelOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_median_channel_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_channel_reset(handle: *mut MedianChannel) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_median_channel_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_median_channel_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_median_channel_free(handle: *mut MedianChannel) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ModifiedMaStop` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_modified_ma_stop_free`.
#[no_mangle]
pub extern "C" fn wickra_modified_ma_stop_new(period: usize) -> *mut ModifiedMaStop {
match ModifiedMaStop::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_modified_ma_stop_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_modified_ma_stop_update(
handle: *mut ModifiedMaStop,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraModifiedMaStopOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraModifiedMaStopOutput {
value: out_val.value,
direction: out_val.direction,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_modified_ma_stop_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_modified_ma_stop_reset(handle: *mut ModifiedMaStop) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_modified_ma_stop_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_modified_ma_stop_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_modified_ma_stop_free(handle: *mut ModifiedMaStop) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `MurreyMathLines` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_murrey_math_lines_free`.
#[no_mangle]
pub extern "C" fn wickra_murrey_math_lines_new(period: usize) -> *mut MurreyMathLines {
match MurreyMathLines::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_murrey_math_lines_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_murrey_math_lines_update(
handle: *mut MurreyMathLines,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraMurreyMathLinesOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraMurreyMathLinesOutput {
mm8_8: out_val.mm8_8,
mm7_8: out_val.mm7_8,
mm6_8: out_val.mm6_8,
mm5_8: out_val.mm5_8,
mm4_8: out_val.mm4_8,
mm3_8: out_val.mm3_8,
mm2_8: out_val.mm2_8,
mm1_8: out_val.mm1_8,
mm0_8: out_val.mm0_8,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_murrey_math_lines_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_murrey_math_lines_reset(handle: *mut MurreyMathLines) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_murrey_math_lines_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_murrey_math_lines_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_murrey_math_lines_free(handle: *mut MurreyMathLines) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Nrtr` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_nrtr_free`.
#[no_mangle]
pub extern "C" fn wickra_nrtr_new(pct: f64) -> *mut Nrtr {
match Nrtr::new(pct) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_nrtr_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_nrtr_update(
handle: *mut Nrtr,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraNrtrOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraNrtrOutput {
value: out_val.value,
direction: out_val.direction,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_nrtr_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_nrtr_reset(handle: *mut Nrtr) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_nrtr_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_nrtr_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_nrtr_free(handle: *mut Nrtr) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OpeningRange` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_opening_range_free`.
#[no_mangle]
pub extern "C" fn wickra_opening_range_new(period: usize) -> *mut OpeningRange {
match OpeningRange::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_opening_range_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_opening_range_update(
handle: *mut OpeningRange,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraOpeningRangeOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraOpeningRangeOutput {
high: out_val.high,
low: out_val.low,
breakout_distance: out_val.breakout_distance,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_opening_range_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_opening_range_reset(handle: *mut OpeningRange) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_opening_range_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_opening_range_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_opening_range_free(handle: *mut OpeningRange) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `OvernightIntradayReturn` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_overnight_intraday_return_free`.
#[no_mangle]
pub extern "C" fn wickra_overnight_intraday_return_new(
utc_offset_minutes: i32,
) -> *mut OvernightIntradayReturn {
Box::into_raw(Box::new(OvernightIntradayReturn::new(utc_offset_minutes)))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_overnight_intraday_return_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_overnight_intraday_return_update(
handle: *mut OvernightIntradayReturn,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraOvernightIntradayReturnOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraOvernightIntradayReturnOutput {
overnight: out_val.overnight,
intraday: out_val.intraday,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_overnight_intraday_return_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_overnight_intraday_return_reset(
handle: *mut OvernightIntradayReturn,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_overnight_intraday_return_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_overnight_intraday_return_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_overnight_intraday_return_free(
handle: *mut OvernightIntradayReturn,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ProjectionBands` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_projection_bands_free`.
#[no_mangle]
pub extern "C" fn wickra_projection_bands_new(period: usize) -> *mut ProjectionBands {
match ProjectionBands::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_projection_bands_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_projection_bands_update(
handle: *mut ProjectionBands,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraProjectionBandsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraProjectionBandsOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_projection_bands_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_projection_bands_reset(handle: *mut ProjectionBands) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_projection_bands_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_projection_bands_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_projection_bands_free(handle: *mut ProjectionBands) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Qqe` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_qqe_free`.
#[no_mangle]
pub extern "C" fn wickra_qqe_new(rsi_period: usize, smoothing: usize, factor: f64) -> *mut Qqe {
match Qqe::new(rsi_period, smoothing, factor) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_qqe_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_qqe_update(
handle: *mut Qqe,
value: f64,
out: *mut WickraQqeOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraQqeOutput {
rsi_ma: out_val.rsi_ma,
trailing_line: out_val.trailing_line,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_qqe_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_qqe_reset(handle: *mut Qqe) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_qqe_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_qqe_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_qqe_free(handle: *mut Qqe) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `QuartileBands` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_quartile_bands_free`.
#[no_mangle]
pub extern "C" fn wickra_quartile_bands_new(period: usize) -> *mut QuartileBands {
match QuartileBands::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_quartile_bands_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_quartile_bands_update(
handle: *mut QuartileBands,
value: f64,
out: *mut WickraQuartileBandsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraQuartileBandsOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_quartile_bands_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_quartile_bands_reset(handle: *mut QuartileBands) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_quartile_bands_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_quartile_bands_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_quartile_bands_free(handle: *mut QuartileBands) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RelativeStrengthAB` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_relative_strength_ab_free`.
#[no_mangle]
pub extern "C" fn wickra_relative_strength_ab_new(
ma_period: usize,
rsi_period: usize,
) -> *mut RelativeStrengthAB {
match RelativeStrengthAB::new(ma_period, rsi_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_relative_strength_ab_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_relative_strength_ab_update(
handle: *mut RelativeStrengthAB,
x: f64,
y: f64,
out: *mut WickraRelativeStrengthOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update((x, y)) {
Some(out_val) => {
*out = WickraRelativeStrengthOutput {
ratio: out_val.ratio,
ratio_ma: out_val.ratio_ma,
ratio_rsi: out_val.ratio_rsi,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_relative_strength_ab_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_relative_strength_ab_reset(handle: *mut RelativeStrengthAB) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_relative_strength_ab_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_relative_strength_ab_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_relative_strength_ab_free(handle: *mut RelativeStrengthAB) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Rwi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_rwi_free`.
#[no_mangle]
pub extern "C" fn wickra_rwi_new(period: usize) -> *mut Rwi {
match Rwi::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_rwi_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rwi_update(
handle: *mut Rwi,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraRwiOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraRwiOutput {
high: out_val.high,
low: out_val.low,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_rwi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rwi_reset(handle: *mut Rwi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_rwi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_rwi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_rwi_free(handle: *mut Rwi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SessionHighLow` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_session_high_low_free`.
#[no_mangle]
pub extern "C" fn wickra_session_high_low_new(utc_offset_minutes: i32) -> *mut SessionHighLow {
Box::into_raw(Box::new(SessionHighLow::new(utc_offset_minutes)))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_session_high_low_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_session_high_low_update(
handle: *mut SessionHighLow,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraSessionHighLowOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraSessionHighLowOutput {
high: out_val.high,
low: out_val.low,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_session_high_low_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_session_high_low_reset(handle: *mut SessionHighLow) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_session_high_low_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_session_high_low_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_session_high_low_free(handle: *mut SessionHighLow) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SessionRange` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_session_range_free`.
#[no_mangle]
pub extern "C" fn wickra_session_range_new(utc_offset_minutes: i32) -> *mut SessionRange {
Box::into_raw(Box::new(SessionRange::new(utc_offset_minutes)))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_session_range_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_session_range_update(
handle: *mut SessionRange,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraSessionRangeOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraSessionRangeOutput {
asia: out_val.asia,
eu: out_val.eu,
us: out_val.us,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_session_range_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_session_range_reset(handle: *mut SessionRange) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_session_range_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_session_range_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_session_range_free(handle: *mut SessionRange) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SmoothedHeikinAshi` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_smoothed_heikin_ashi_free`.
#[no_mangle]
pub extern "C" fn wickra_smoothed_heikin_ashi_new(period: usize) -> *mut SmoothedHeikinAshi {
match SmoothedHeikinAshi::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_smoothed_heikin_ashi_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_smoothed_heikin_ashi_update(
handle: *mut SmoothedHeikinAshi,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraSmoothedHeikinAshiOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraSmoothedHeikinAshiOutput {
open: out_val.open,
high: out_val.high,
low: out_val.low,
close: out_val.close,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_smoothed_heikin_ashi_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_smoothed_heikin_ashi_reset(handle: *mut SmoothedHeikinAshi) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_smoothed_heikin_ashi_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_smoothed_heikin_ashi_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_smoothed_heikin_ashi_free(handle: *mut SmoothedHeikinAshi) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SpreadBollingerBands` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_spread_bollinger_bands_free`.
#[no_mangle]
pub extern "C" fn wickra_spread_bollinger_bands_new(
period: usize,
num_std: f64,
) -> *mut SpreadBollingerBands {
match SpreadBollingerBands::new(period, num_std) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_spread_bollinger_bands_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spread_bollinger_bands_update(
handle: *mut SpreadBollingerBands,
x: f64,
y: f64,
out: *mut WickraSpreadBollingerBandsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update((x, y)) {
Some(out_val) => {
*out = WickraSpreadBollingerBandsOutput {
middle: out_val.middle,
upper: out_val.upper,
lower: out_val.lower,
percent_b: out_val.percent_b,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_spread_bollinger_bands_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spread_bollinger_bands_reset(handle: *mut SpreadBollingerBands) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_spread_bollinger_bands_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_spread_bollinger_bands_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_spread_bollinger_bands_free(handle: *mut SpreadBollingerBands) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `StandardErrorBands` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_standard_error_bands_free`.
#[no_mangle]
pub extern "C" fn wickra_standard_error_bands_new(
period: usize,
multiplier: f64,
) -> *mut StandardErrorBands {
match StandardErrorBands::new(period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_standard_error_bands_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_standard_error_bands_update(
handle: *mut StandardErrorBands,
value: f64,
out: *mut WickraStandardErrorBandsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraStandardErrorBandsOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_standard_error_bands_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_standard_error_bands_reset(handle: *mut StandardErrorBands) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_standard_error_bands_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_standard_error_bands_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_standard_error_bands_free(handle: *mut StandardErrorBands) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `StarcBands` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_starc_bands_free`.
#[no_mangle]
pub extern "C" fn wickra_starc_bands_new(
sma_period: usize,
atr_period: usize,
multiplier: f64,
) -> *mut StarcBands {
match StarcBands::new(sma_period, atr_period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_starc_bands_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_starc_bands_update(
handle: *mut StarcBands,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraStarcBandsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraStarcBandsOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_starc_bands_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_starc_bands_reset(handle: *mut StarcBands) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_starc_bands_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_starc_bands_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_starc_bands_free(handle: *mut StarcBands) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Stochastic` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_stochastic_free`.
#[no_mangle]
pub extern "C" fn wickra_stochastic_new(k_period: usize, d_period: usize) -> *mut Stochastic {
match Stochastic::new(k_period, d_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_stochastic_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stochastic_update(
handle: *mut Stochastic,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraStochasticOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraStochasticOutput {
k: out_val.k,
d: out_val.d,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_stochastic_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stochastic_reset(handle: *mut Stochastic) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_stochastic_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_stochastic_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_stochastic_free(handle: *mut Stochastic) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `SuperTrend` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_super_trend_free`.
#[no_mangle]
pub extern "C" fn wickra_super_trend_new(atr_period: usize, multiplier: f64) -> *mut SuperTrend {
match SuperTrend::new(atr_period, multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_super_trend_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_super_trend_update(
handle: *mut SuperTrend,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraSuperTrendOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraSuperTrendOutput {
value: out_val.value,
direction: out_val.direction,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_super_trend_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_super_trend_reset(handle: *mut SuperTrend) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_super_trend_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_super_trend_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_super_trend_free(handle: *mut SuperTrend) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdLines` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_lines_free`.
#[no_mangle]
pub extern "C" fn wickra_td_lines_new(lookback: usize, target: usize) -> *mut TdLines {
match TdLines::new(lookback, target) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_td_lines_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_lines_update(
handle: *mut TdLines,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraTdLinesOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraTdLinesOutput {
resistance: out_val.resistance,
support: out_val.support,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_lines_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_lines_reset(handle: *mut TdLines) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_lines_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_lines_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_lines_free(handle: *mut TdLines) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdMovingAverage` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_moving_average_free`.
#[no_mangle]
pub extern "C" fn wickra_td_moving_average_new(
period_st1: usize,
period_st2: usize,
) -> *mut TdMovingAverage {
match TdMovingAverage::new(period_st1, period_st2) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_td_moving_average_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_moving_average_update(
handle: *mut TdMovingAverage,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraTdMovingAverageOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraTdMovingAverageOutput {
st1: out_val.st1,
st2: out_val.st2,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_moving_average_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_moving_average_reset(handle: *mut TdMovingAverage) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_moving_average_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_moving_average_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_moving_average_free(handle: *mut TdMovingAverage) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdRangeProjection` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_range_projection_free`.
#[no_mangle]
pub extern "C" fn wickra_td_range_projection_new() -> *mut TdRangeProjection {
Box::into_raw(Box::new(TdRangeProjection::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_td_range_projection_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_range_projection_update(
handle: *mut TdRangeProjection,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraTdRangeProjectionOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraTdRangeProjectionOutput {
high: out_val.high,
low: out_val.low,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_range_projection_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_range_projection_reset(handle: *mut TdRangeProjection) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_range_projection_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_range_projection_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_range_projection_free(handle: *mut TdRangeProjection) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdRiskLevel` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_risk_level_free`.
#[no_mangle]
pub extern "C" fn wickra_td_risk_level_new(lookback: usize, target: usize) -> *mut TdRiskLevel {
match TdRiskLevel::new(lookback, target) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_td_risk_level_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_risk_level_update(
handle: *mut TdRiskLevel,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraTdRiskLevelOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraTdRiskLevelOutput {
buy_risk: out_val.buy_risk,
sell_risk: out_val.sell_risk,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_risk_level_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_risk_level_reset(handle: *mut TdRiskLevel) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_risk_level_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_risk_level_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_risk_level_free(handle: *mut TdRiskLevel) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TdSequential` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_td_sequential_free`.
#[no_mangle]
pub extern "C" fn wickra_td_sequential_new(
setup_lookback: usize,
setup_target: usize,
countdown_lookback: usize,
countdown_target: usize,
) -> *mut TdSequential {
match TdSequential::new(
setup_lookback,
setup_target,
countdown_lookback,
countdown_target,
) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_td_sequential_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_sequential_update(
handle: *mut TdSequential,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraTdSequentialOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraTdSequentialOutput {
setup: out_val.setup,
countdown: out_val.countdown,
direction: out_val.direction,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_td_sequential_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_sequential_reset(handle: *mut TdSequential) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_td_sequential_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_td_sequential_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_td_sequential_free(handle: *mut TdSequential) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TtmSqueeze` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_ttm_squeeze_free`.
#[no_mangle]
pub extern "C" fn wickra_ttm_squeeze_new(
period: usize,
bb_mult: f64,
kc_mult: f64,
) -> *mut TtmSqueeze {
match TtmSqueeze::new(period, bb_mult, kc_mult) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_ttm_squeeze_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ttm_squeeze_update(
handle: *mut TtmSqueeze,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraTtmSqueezeOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraTtmSqueezeOutput {
squeeze: out_val.squeeze,
momentum: out_val.momentum,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_ttm_squeeze_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ttm_squeeze_reset(handle: *mut TtmSqueeze) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_ttm_squeeze_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_ttm_squeeze_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_ttm_squeeze_free(handle: *mut TtmSqueeze) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ValueArea` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_value_area_free`.
#[no_mangle]
pub extern "C" fn wickra_value_area_new(
period: usize,
bin_count: usize,
value_area_pct: f64,
) -> *mut ValueArea {
match ValueArea::new(period, bin_count, value_area_pct) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_value_area_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_value_area_update(
handle: *mut ValueArea,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraValueAreaOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraValueAreaOutput {
poc: out_val.poc,
vah: out_val.vah,
val: out_val.val,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_value_area_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_value_area_reset(handle: *mut ValueArea) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_value_area_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_value_area_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_value_area_free(handle: *mut ValueArea) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VolatilityCone` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_volatility_cone_free`.
#[no_mangle]
pub extern "C" fn wickra_volatility_cone_new(
window: usize,
lookback: usize,
) -> *mut VolatilityCone {
match VolatilityCone::new(window, lookback) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_volatility_cone_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volatility_cone_update(
handle: *mut VolatilityCone,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraVolatilityConeOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraVolatilityConeOutput {
current: out_val.current,
min: out_val.min,
median: out_val.median,
max: out_val.max,
percentile: out_val.percentile,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_volatility_cone_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volatility_cone_reset(handle: *mut VolatilityCone) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_volatility_cone_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_volatility_cone_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volatility_cone_free(handle: *mut VolatilityCone) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VolumeWeightedMacd` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_volume_weighted_macd_free`.
#[no_mangle]
pub extern "C" fn wickra_volume_weighted_macd_new(
fast: usize,
slow: usize,
signal: usize,
) -> *mut VolumeWeightedMacd {
match VolumeWeightedMacd::new(fast, slow, signal) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_volume_weighted_macd_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_weighted_macd_update(
handle: *mut VolumeWeightedMacd,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraVolumeWeightedMacdOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraVolumeWeightedMacdOutput {
macd: out_val.macd,
signal: out_val.signal,
histogram: out_val.histogram,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_volume_weighted_macd_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_weighted_macd_reset(handle: *mut VolumeWeightedMacd) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_volume_weighted_macd_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_volume_weighted_macd_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_weighted_macd_free(handle: *mut VolumeWeightedMacd) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VolumeWeightedSr` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_volume_weighted_sr_free`.
#[no_mangle]
pub extern "C" fn wickra_volume_weighted_sr_new(period: usize) -> *mut VolumeWeightedSr {
match VolumeWeightedSr::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_volume_weighted_sr_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_weighted_sr_update(
handle: *mut VolumeWeightedSr,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraVolumeWeightedSrOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraVolumeWeightedSrOutput {
support: out_val.support,
resistance: out_val.resistance,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_volume_weighted_sr_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_weighted_sr_reset(handle: *mut VolumeWeightedSr) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_volume_weighted_sr_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_volume_weighted_sr_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_weighted_sr_free(handle: *mut VolumeWeightedSr) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `Vortex` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_vortex_free`.
#[no_mangle]
pub extern "C" fn wickra_vortex_new(period: usize) -> *mut Vortex {
match Vortex::new(period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_vortex_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vortex_update(
handle: *mut Vortex,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraVortexOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraVortexOutput {
plus: out_val.plus,
minus: out_val.minus,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_vortex_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vortex_reset(handle: *mut Vortex) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_vortex_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_vortex_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vortex_free(handle: *mut Vortex) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VwapStdDevBands` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_vwap_std_dev_bands_free`.
#[no_mangle]
pub extern "C" fn wickra_vwap_std_dev_bands_new(multiplier: f64) -> *mut VwapStdDevBands {
match VwapStdDevBands::new(multiplier) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_vwap_std_dev_bands_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vwap_std_dev_bands_update(
handle: *mut VwapStdDevBands,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraVwapStdDevBandsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraVwapStdDevBandsOutput {
upper: out_val.upper,
middle: out_val.middle,
lower: out_val.lower,
stddev: out_val.stddev,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_vwap_std_dev_bands_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vwap_std_dev_bands_reset(handle: *mut VwapStdDevBands) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_vwap_std_dev_bands_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_vwap_std_dev_bands_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_vwap_std_dev_bands_free(handle: *mut VwapStdDevBands) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `WaveTrend` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_wave_trend_free`.
#[no_mangle]
pub extern "C" fn wickra_wave_trend_new(
channel_period: usize,
average_period: usize,
signal_period: usize,
) -> *mut WaveTrend {
match WaveTrend::new(channel_period, average_period, signal_period) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_wave_trend_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wave_trend_update(
handle: *mut WaveTrend,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraWaveTrendOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraWaveTrendOutput {
wt1: out_val.wt1,
wt2: out_val.wt2,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_wave_trend_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wave_trend_reset(handle: *mut WaveTrend) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_wave_trend_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_wave_trend_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_wave_trend_free(handle: *mut WaveTrend) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `WilliamsFractals` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_williams_fractals_free`.
#[no_mangle]
pub extern "C" fn wickra_williams_fractals_new() -> *mut WilliamsFractals {
Box::into_raw(Box::new(WilliamsFractals::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_williams_fractals_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_williams_fractals_update(
handle: *mut WilliamsFractals,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraWilliamsFractalsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraWilliamsFractalsOutput {
up: out_val.up.unwrap_or(f64::NAN),
down: out_val.down.unwrap_or(f64::NAN),
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_williams_fractals_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_williams_fractals_reset(handle: *mut WilliamsFractals) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_williams_fractals_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_williams_fractals_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_williams_fractals_free(handle: *mut WilliamsFractals) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `WoodiePivots` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_woodie_pivots_free`.
#[no_mangle]
pub extern "C" fn wickra_woodie_pivots_new() -> *mut WoodiePivots {
Box::into_raw(Box::new(WoodiePivots::new()))
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_woodie_pivots_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_woodie_pivots_update(
handle: *mut WoodiePivots,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraWoodiePivotsOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraWoodiePivotsOutput {
pp: out_val.pp,
r1: out_val.r1,
r2: out_val.r2,
s1: out_val.s1,
s2: out_val.s2,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_woodie_pivots_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_woodie_pivots_reset(handle: *mut WoodiePivots) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_woodie_pivots_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_woodie_pivots_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_woodie_pivots_free(handle: *mut WoodiePivots) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ZeroLagMacd` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_zero_lag_macd_free`.
#[no_mangle]
pub extern "C" fn wickra_zero_lag_macd_new(
fast: usize,
slow: usize,
signal: usize,
) -> *mut ZeroLagMacd {
match ZeroLagMacd::new(fast, slow, signal) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_zero_lag_macd_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_zero_lag_macd_update(
handle: *mut ZeroLagMacd,
value: f64,
out: *mut WickraZeroLagMacdOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraZeroLagMacdOutput {
macd: out_val.macd,
signal: out_val.signal,
histogram: out_val.histogram,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_zero_lag_macd_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_zero_lag_macd_reset(handle: *mut ZeroLagMacd) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_zero_lag_macd_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_zero_lag_macd_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_zero_lag_macd_free(handle: *mut ZeroLagMacd) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ZigZag` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_zig_zag_free`.
#[no_mangle]
pub extern "C" fn wickra_zig_zag_new(threshold: f64) -> *mut ZigZag {
match ZigZag::new(threshold) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input; on `true` the freshly computed multi-field output is written to
/// `*out`. Returns `false` during warmup, on a `NULL` handle / `out`, or on invalid input.
///
/// # Safety
/// `handle` (from `wickra_zig_zag_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_zig_zag_update(
handle: *mut ZigZag,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraZigZagOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return false;
};
match ind.update(input) {
Some(out_val) => {
*out = WickraZigZagOutput {
swing: out_val.swing,
direction: out_val.direction,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_zig_zag_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_zig_zag_reset(handle: *mut ZigZag) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_zig_zag_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_zig_zag_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_zig_zag_free(handle: *mut ZigZag) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
// ===== Vec<f64>-output indicators (profiles; caller buffer + length return) =====
/// Scalar fields of `TpoProfileOutput` (its `Vec` payload is delivered separately).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraTpoProfileOutputScalars {
pub price_low: f64,
pub price_high: f64,
}
/// Scalar fields of `VolumeProfileOutput` (its `Vec` payload is delivered separately).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraVolumeProfileOutputScalars {
pub price_low: f64,
pub price_high: f64,
}
/// Create a `DayOfWeekProfile` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_day_of_week_profile_free`.
#[no_mangle]
pub extern "C" fn wickra_day_of_week_profile_new(utc_offset_minutes: i32) -> *mut DayOfWeekProfile {
Box::into_raw(Box::new(DayOfWeekProfile::new(utc_offset_minutes)))
}
/// Feed one input. On warmup / `NULL` handle / invalid input returns `-1`. Otherwise
/// returns the length of the `bins` payload and writes up to `cap` of its values
/// into `values` (enlarge `cap` if the return exceeds it); the scalar fields are written
/// to `*scalars` when non-`NULL`.
///
/// # Safety
/// `handle` (from `wickra_day_of_week_profile_new`, not freed), `scalars` and `values` must be valid
/// or `NULL`; when non-`NULL`, `values` must cover `cap` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_day_of_week_profile_update(
handle: *mut DayOfWeekProfile,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
values: *mut f64,
cap: usize,
) -> isize {
let Some(ind) = handle.as_mut() else {
return -1;
};
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return -1;
};
match ind.update(input) {
Some(out_val) => {
if !values.is_null() {
let slots = slice::from_raw_parts_mut(values, cap);
for (slot, &v) in slots.iter_mut().zip(&out_val.bins) {
*slot = v;
}
}
isize::try_from(out_val.bins.len()).unwrap_or(isize::MAX)
}
None => -1,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_day_of_week_profile_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_day_of_week_profile_reset(handle: *mut DayOfWeekProfile) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_day_of_week_profile_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_day_of_week_profile_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_day_of_week_profile_free(handle: *mut DayOfWeekProfile) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `IntradayVolatilityProfile` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_intraday_volatility_profile_free`.
#[no_mangle]
pub extern "C" fn wickra_intraday_volatility_profile_new(
buckets: usize,
utc_offset_minutes: i32,
) -> *mut IntradayVolatilityProfile {
match IntradayVolatilityProfile::new(buckets, utc_offset_minutes) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input. On warmup / `NULL` handle / invalid input returns `-1`. Otherwise
/// returns the length of the `bins` payload and writes up to `cap` of its values
/// into `values` (enlarge `cap` if the return exceeds it); the scalar fields are written
/// to `*scalars` when non-`NULL`.
///
/// # Safety
/// `handle` (from `wickra_intraday_volatility_profile_new`, not freed), `scalars` and `values` must be valid
/// or `NULL`; when non-`NULL`, `values` must cover `cap` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_intraday_volatility_profile_update(
handle: *mut IntradayVolatilityProfile,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
values: *mut f64,
cap: usize,
) -> isize {
let Some(ind) = handle.as_mut() else {
return -1;
};
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return -1;
};
match ind.update(input) {
Some(out_val) => {
if !values.is_null() {
let slots = slice::from_raw_parts_mut(values, cap);
for (slot, &v) in slots.iter_mut().zip(&out_val.bins) {
*slot = v;
}
}
isize::try_from(out_val.bins.len()).unwrap_or(isize::MAX)
}
None => -1,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_intraday_volatility_profile_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_intraday_volatility_profile_reset(
handle: *mut IntradayVolatilityProfile,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_intraday_volatility_profile_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_intraday_volatility_profile_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_intraday_volatility_profile_free(
handle: *mut IntradayVolatilityProfile,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TimeOfDayReturnProfile` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_time_of_day_return_profile_free`.
#[no_mangle]
pub extern "C" fn wickra_time_of_day_return_profile_new(
buckets: usize,
utc_offset_minutes: i32,
) -> *mut TimeOfDayReturnProfile {
match TimeOfDayReturnProfile::new(buckets, utc_offset_minutes) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input. On warmup / `NULL` handle / invalid input returns `-1`. Otherwise
/// returns the length of the `bins` payload and writes up to `cap` of its values
/// into `values` (enlarge `cap` if the return exceeds it); the scalar fields are written
/// to `*scalars` when non-`NULL`.
///
/// # Safety
/// `handle` (from `wickra_time_of_day_return_profile_new`, not freed), `scalars` and `values` must be valid
/// or `NULL`; when non-`NULL`, `values` must cover `cap` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_time_of_day_return_profile_update(
handle: *mut TimeOfDayReturnProfile,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
values: *mut f64,
cap: usize,
) -> isize {
let Some(ind) = handle.as_mut() else {
return -1;
};
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return -1;
};
match ind.update(input) {
Some(out_val) => {
if !values.is_null() {
let slots = slice::from_raw_parts_mut(values, cap);
for (slot, &v) in slots.iter_mut().zip(&out_val.bins) {
*slot = v;
}
}
isize::try_from(out_val.bins.len()).unwrap_or(isize::MAX)
}
None => -1,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_time_of_day_return_profile_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_time_of_day_return_profile_reset(
handle: *mut TimeOfDayReturnProfile,
) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_time_of_day_return_profile_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_time_of_day_return_profile_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_time_of_day_return_profile_free(
handle: *mut TimeOfDayReturnProfile,
) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TpoProfile` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_tpo_profile_free`.
#[no_mangle]
pub extern "C" fn wickra_tpo_profile_new(period: usize, bin_count: usize) -> *mut TpoProfile {
match TpoProfile::new(period, bin_count) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input. On warmup / `NULL` handle / invalid input returns `-1`. Otherwise
/// returns the length of the `counts` payload and writes up to `cap` of its values
/// into `values` (enlarge `cap` if the return exceeds it); the scalar fields are written
/// to `*scalars` when non-`NULL`.
///
/// # Safety
/// `handle` (from `wickra_tpo_profile_new`, not freed), `scalars` and `values` must be valid
/// or `NULL`; when non-`NULL`, `values` must cover `cap` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_tpo_profile_update(
handle: *mut TpoProfile,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
scalars: *mut WickraTpoProfileOutputScalars,
values: *mut f64,
cap: usize,
) -> isize {
let Some(ind) = handle.as_mut() else {
return -1;
};
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return -1;
};
match ind.update(input) {
Some(out_val) => {
if !scalars.is_null() {
*scalars = WickraTpoProfileOutputScalars {
price_low: out_val.price_low,
price_high: out_val.price_high,
};
}
if !values.is_null() {
let slots = slice::from_raw_parts_mut(values, cap);
for (slot, &v) in slots.iter_mut().zip(&out_val.counts) {
*slot = v;
}
}
isize::try_from(out_val.counts.len()).unwrap_or(isize::MAX)
}
None => -1,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_tpo_profile_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tpo_profile_reset(handle: *mut TpoProfile) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_tpo_profile_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_tpo_profile_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tpo_profile_free(handle: *mut TpoProfile) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VolumeByTimeProfile` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_volume_by_time_profile_free`.
#[no_mangle]
pub extern "C" fn wickra_volume_by_time_profile_new(
buckets: usize,
utc_offset_minutes: i32,
) -> *mut VolumeByTimeProfile {
match VolumeByTimeProfile::new(buckets, utc_offset_minutes) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input. On warmup / `NULL` handle / invalid input returns `-1`. Otherwise
/// returns the length of the `bins` payload and writes up to `cap` of its values
/// into `values` (enlarge `cap` if the return exceeds it); the scalar fields are written
/// to `*scalars` when non-`NULL`.
///
/// # Safety
/// `handle` (from `wickra_volume_by_time_profile_new`, not freed), `scalars` and `values` must be valid
/// or `NULL`; when non-`NULL`, `values` must cover `cap` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_by_time_profile_update(
handle: *mut VolumeByTimeProfile,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
values: *mut f64,
cap: usize,
) -> isize {
let Some(ind) = handle.as_mut() else {
return -1;
};
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return -1;
};
match ind.update(input) {
Some(out_val) => {
if !values.is_null() {
let slots = slice::from_raw_parts_mut(values, cap);
for (slot, &v) in slots.iter_mut().zip(&out_val.bins) {
*slot = v;
}
}
isize::try_from(out_val.bins.len()).unwrap_or(isize::MAX)
}
None => -1,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_volume_by_time_profile_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_by_time_profile_reset(handle: *mut VolumeByTimeProfile) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_volume_by_time_profile_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_volume_by_time_profile_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_by_time_profile_free(handle: *mut VolumeByTimeProfile) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VolumeProfile` indicator.
///
/// Returns `NULL` on invalid parameters; release with `wickra_volume_profile_free`.
#[no_mangle]
pub extern "C" fn wickra_volume_profile_new(period: usize, bin_count: usize) -> *mut VolumeProfile {
match VolumeProfile::new(period, bin_count) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one input. On warmup / `NULL` handle / invalid input returns `-1`. Otherwise
/// returns the length of the `bins` payload and writes up to `cap` of its values
/// into `values` (enlarge `cap` if the return exceeds it); the scalar fields are written
/// to `*scalars` when non-`NULL`.
///
/// # Safety
/// `handle` (from `wickra_volume_profile_new`, not freed), `scalars` and `values` must be valid
/// or `NULL`; when non-`NULL`, `values` must cover `cap` `double`s.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_profile_update(
handle: *mut VolumeProfile,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
scalars: *mut WickraVolumeProfileOutputScalars,
values: *mut f64,
cap: usize,
) -> isize {
let Some(ind) = handle.as_mut() else {
return -1;
};
let Ok(input) = Candle::new(open, high, low, close, volume, timestamp) else {
return -1;
};
match ind.update(input) {
Some(out_val) => {
if !scalars.is_null() {
*scalars = WickraVolumeProfileOutputScalars {
price_low: out_val.price_low,
price_high: out_val.price_high,
};
}
if !values.is_null() {
let slots = slice::from_raw_parts_mut(values, cap);
for (slot, &v) in slots.iter_mut().zip(&out_val.bins) {
*slot = v;
}
}
isize::try_from(out_val.bins.len()).unwrap_or(isize::MAX)
}
None => -1,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_volume_profile_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_profile_reset(handle: *mut VolumeProfile) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_volume_profile_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_volume_profile_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_profile_free(handle: *mut VolumeProfile) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
// ===== Alt-chart bar builders (BarBuilder -> bars via caller buffer + count) =====
/// C-ABI view of one `DollarBar` (alt-chart bar element).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraDollarBar {
pub open: f64,
pub high: f64,
pub low: f64,
pub close: f64,
pub volume: f64,
pub dollar: f64,
}
/// C-ABI view of one `ImbalanceBar` (alt-chart bar element).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraImbalanceBar {
pub open: f64,
pub high: f64,
pub low: f64,
pub close: f64,
pub imbalance: f64,
pub direction: i8,
}
/// C-ABI view of one `KagiBar` (alt-chart bar element).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraKagiBar {
pub start: f64,
pub end: f64,
pub direction: i8,
}
/// C-ABI view of one `PnfColumn` (alt-chart bar element).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraPnfColumn {
pub direction: i8,
pub high: f64,
pub low: f64,
}
/// C-ABI view of one `RangeBar` (alt-chart bar element).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraRangeBar {
pub open: f64,
pub close: f64,
pub direction: i8,
}
/// C-ABI view of one `RenkoBrick` (alt-chart bar element).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraRenkoBrick {
pub open: f64,
pub close: f64,
pub direction: i8,
}
/// C-ABI view of one `RunBar` (alt-chart bar element).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraRunBar {
pub open: f64,
pub high: f64,
pub low: f64,
pub close: f64,
pub length: usize,
pub direction: i8,
}
/// C-ABI view of one `LineBreakBar` (alt-chart bar element).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraLineBreakBar {
pub open: f64,
pub close: f64,
pub direction: i8,
}
/// C-ABI view of one `TickBar` (alt-chart bar element).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraTickBar {
pub open: f64,
pub high: f64,
pub low: f64,
pub close: f64,
pub volume: f64,
}
/// C-ABI view of one `VolumeBar` (alt-chart bar element).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraVolumeBar {
pub open: f64,
pub high: f64,
pub low: f64,
pub close: f64,
pub volume: f64,
}
/// Create a `DollarBars` bar builder.
///
/// Returns `NULL` on invalid parameters; release with `wickra_dollar_bars_free`.
#[no_mangle]
pub extern "C" fn wickra_dollar_bars_new(dollar_per_bar: f64) -> *mut DollarBars {
match DollarBars::new(dollar_per_bar) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; writes up to `cap` completed bars into `out` and returns the
/// total number completed on this candle (0, 1, or several). If the return exceeds `cap`,
/// the surplus is not written — enlarge `cap` (a single candle rarely completes many bars;
/// `cap >= 64` is safe). Returns 0 on a `NULL` handle or an invalid candle.
///
/// # Safety
/// `handle` (from `wickra_dollar_bars_new`, not freed) and `out` must be valid or `NULL`; when
/// non-`NULL`, `out` must cover `cap` `WickraDollarBar` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_dollar_bars_update(
handle: *mut DollarBars,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraDollarBar,
cap: usize,
) -> usize {
let Some(builder) = handle.as_mut() else {
return 0;
};
let Ok(candle) = Candle::new(open, high, low, close, volume, timestamp) else {
return 0;
};
let bars = builder.update(candle);
if !out.is_null() {
let slots = slice::from_raw_parts_mut(out, cap);
for (slot, bar) in slots.iter_mut().zip(&bars) {
*slot = WickraDollarBar {
open: bar.open,
high: bar.high,
low: bar.low,
close: bar.close,
volume: bar.volume,
dollar: bar.dollar,
};
}
}
bars.len()
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_dollar_bars_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dollar_bars_reset(handle: *mut DollarBars) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_dollar_bars_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_dollar_bars_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_dollar_bars_free(handle: *mut DollarBars) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ImbalanceBars` bar builder.
///
/// Returns `NULL` on invalid parameters; release with `wickra_imbalance_bars_free`.
#[no_mangle]
pub extern "C" fn wickra_imbalance_bars_new(threshold: f64) -> *mut ImbalanceBars {
match ImbalanceBars::new(threshold) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; writes up to `cap` completed bars into `out` and returns the
/// total number completed on this candle (0, 1, or several). If the return exceeds `cap`,
/// the surplus is not written — enlarge `cap` (a single candle rarely completes many bars;
/// `cap >= 64` is safe). Returns 0 on a `NULL` handle or an invalid candle.
///
/// # Safety
/// `handle` (from `wickra_imbalance_bars_new`, not freed) and `out` must be valid or `NULL`; when
/// non-`NULL`, `out` must cover `cap` `WickraImbalanceBar` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_imbalance_bars_update(
handle: *mut ImbalanceBars,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraImbalanceBar,
cap: usize,
) -> usize {
let Some(builder) = handle.as_mut() else {
return 0;
};
let Ok(candle) = Candle::new(open, high, low, close, volume, timestamp) else {
return 0;
};
let bars = builder.update(candle);
if !out.is_null() {
let slots = slice::from_raw_parts_mut(out, cap);
for (slot, bar) in slots.iter_mut().zip(&bars) {
*slot = WickraImbalanceBar {
open: bar.open,
high: bar.high,
low: bar.low,
close: bar.close,
imbalance: bar.imbalance,
direction: bar.direction,
};
}
}
bars.len()
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_imbalance_bars_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_imbalance_bars_reset(handle: *mut ImbalanceBars) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_imbalance_bars_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_imbalance_bars_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_imbalance_bars_free(handle: *mut ImbalanceBars) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `KagiBars` bar builder.
///
/// Returns `NULL` on invalid parameters; release with `wickra_kagi_bars_free`.
#[no_mangle]
pub extern "C" fn wickra_kagi_bars_new(reversal: f64) -> *mut KagiBars {
match KagiBars::new(reversal) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; writes up to `cap` completed bars into `out` and returns the
/// total number completed on this candle (0, 1, or several). If the return exceeds `cap`,
/// the surplus is not written — enlarge `cap` (a single candle rarely completes many bars;
/// `cap >= 64` is safe). Returns 0 on a `NULL` handle or an invalid candle.
///
/// # Safety
/// `handle` (from `wickra_kagi_bars_new`, not freed) and `out` must be valid or `NULL`; when
/// non-`NULL`, `out` must cover `cap` `WickraKagiBar` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_kagi_bars_update(
handle: *mut KagiBars,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraKagiBar,
cap: usize,
) -> usize {
let Some(builder) = handle.as_mut() else {
return 0;
};
let Ok(candle) = Candle::new(open, high, low, close, volume, timestamp) else {
return 0;
};
let bars = builder.update(candle);
if !out.is_null() {
let slots = slice::from_raw_parts_mut(out, cap);
for (slot, bar) in slots.iter_mut().zip(&bars) {
*slot = WickraKagiBar {
start: bar.start,
end: bar.end,
direction: bar.direction,
};
}
}
bars.len()
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_kagi_bars_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kagi_bars_reset(handle: *mut KagiBars) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_kagi_bars_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_kagi_bars_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_kagi_bars_free(handle: *mut KagiBars) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `PointAndFigureBars` bar builder.
///
/// Returns `NULL` on invalid parameters; release with `wickra_point_and_figure_bars_free`.
#[no_mangle]
pub extern "C" fn wickra_point_and_figure_bars_new(
box_size: f64,
reversal: usize,
) -> *mut PointAndFigureBars {
match PointAndFigureBars::new(box_size, reversal) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; writes up to `cap` completed bars into `out` and returns the
/// total number completed on this candle (0, 1, or several). If the return exceeds `cap`,
/// the surplus is not written — enlarge `cap` (a single candle rarely completes many bars;
/// `cap >= 64` is safe). Returns 0 on a `NULL` handle or an invalid candle.
///
/// # Safety
/// `handle` (from `wickra_point_and_figure_bars_new`, not freed) and `out` must be valid or `NULL`; when
/// non-`NULL`, `out` must cover `cap` `WickraPnfColumn` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_point_and_figure_bars_update(
handle: *mut PointAndFigureBars,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraPnfColumn,
cap: usize,
) -> usize {
let Some(builder) = handle.as_mut() else {
return 0;
};
let Ok(candle) = Candle::new(open, high, low, close, volume, timestamp) else {
return 0;
};
let bars = builder.update(candle);
if !out.is_null() {
let slots = slice::from_raw_parts_mut(out, cap);
for (slot, bar) in slots.iter_mut().zip(&bars) {
*slot = WickraPnfColumn {
direction: bar.direction,
high: bar.high,
low: bar.low,
};
}
}
bars.len()
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_point_and_figure_bars_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_point_and_figure_bars_reset(handle: *mut PointAndFigureBars) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_point_and_figure_bars_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_point_and_figure_bars_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_point_and_figure_bars_free(handle: *mut PointAndFigureBars) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RangeBars` bar builder.
///
/// Returns `NULL` on invalid parameters; release with `wickra_range_bars_free`.
#[no_mangle]
pub extern "C" fn wickra_range_bars_new(range: f64) -> *mut RangeBars {
match RangeBars::new(range) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; writes up to `cap` completed bars into `out` and returns the
/// total number completed on this candle (0, 1, or several). If the return exceeds `cap`,
/// the surplus is not written — enlarge `cap` (a single candle rarely completes many bars;
/// `cap >= 64` is safe). Returns 0 on a `NULL` handle or an invalid candle.
///
/// # Safety
/// `handle` (from `wickra_range_bars_new`, not freed) and `out` must be valid or `NULL`; when
/// non-`NULL`, `out` must cover `cap` `WickraRangeBar` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_range_bars_update(
handle: *mut RangeBars,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraRangeBar,
cap: usize,
) -> usize {
let Some(builder) = handle.as_mut() else {
return 0;
};
let Ok(candle) = Candle::new(open, high, low, close, volume, timestamp) else {
return 0;
};
let bars = builder.update(candle);
if !out.is_null() {
let slots = slice::from_raw_parts_mut(out, cap);
for (slot, bar) in slots.iter_mut().zip(&bars) {
*slot = WickraRangeBar {
open: bar.open,
close: bar.close,
direction: bar.direction,
};
}
}
bars.len()
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_range_bars_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_range_bars_reset(handle: *mut RangeBars) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_range_bars_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_range_bars_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_range_bars_free(handle: *mut RangeBars) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RenkoBars` bar builder.
///
/// Returns `NULL` on invalid parameters; release with `wickra_renko_bars_free`.
#[no_mangle]
pub extern "C" fn wickra_renko_bars_new(box_size: f64) -> *mut RenkoBars {
match RenkoBars::new(box_size) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; writes up to `cap` completed bars into `out` and returns the
/// total number completed on this candle (0, 1, or several). If the return exceeds `cap`,
/// the surplus is not written — enlarge `cap` (a single candle rarely completes many bars;
/// `cap >= 64` is safe). Returns 0 on a `NULL` handle or an invalid candle.
///
/// # Safety
/// `handle` (from `wickra_renko_bars_new`, not freed) and `out` must be valid or `NULL`; when
/// non-`NULL`, `out` must cover `cap` `WickraRenkoBrick` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_renko_bars_update(
handle: *mut RenkoBars,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraRenkoBrick,
cap: usize,
) -> usize {
let Some(builder) = handle.as_mut() else {
return 0;
};
let Ok(candle) = Candle::new(open, high, low, close, volume, timestamp) else {
return 0;
};
let bars = builder.update(candle);
if !out.is_null() {
let slots = slice::from_raw_parts_mut(out, cap);
for (slot, bar) in slots.iter_mut().zip(&bars) {
*slot = WickraRenkoBrick {
open: bar.open,
close: bar.close,
direction: bar.direction,
};
}
}
bars.len()
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_renko_bars_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_renko_bars_reset(handle: *mut RenkoBars) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_renko_bars_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_renko_bars_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_renko_bars_free(handle: *mut RenkoBars) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `RunBars` bar builder.
///
/// Returns `NULL` on invalid parameters; release with `wickra_run_bars_free`.
#[no_mangle]
pub extern "C" fn wickra_run_bars_new(run_length: usize) -> *mut RunBars {
match RunBars::new(run_length) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; writes up to `cap` completed bars into `out` and returns the
/// total number completed on this candle (0, 1, or several). If the return exceeds `cap`,
/// the surplus is not written — enlarge `cap` (a single candle rarely completes many bars;
/// `cap >= 64` is safe). Returns 0 on a `NULL` handle or an invalid candle.
///
/// # Safety
/// `handle` (from `wickra_run_bars_new`, not freed) and `out` must be valid or `NULL`; when
/// non-`NULL`, `out` must cover `cap` `WickraRunBar` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_run_bars_update(
handle: *mut RunBars,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraRunBar,
cap: usize,
) -> usize {
let Some(builder) = handle.as_mut() else {
return 0;
};
let Ok(candle) = Candle::new(open, high, low, close, volume, timestamp) else {
return 0;
};
let bars = builder.update(candle);
if !out.is_null() {
let slots = slice::from_raw_parts_mut(out, cap);
for (slot, bar) in slots.iter_mut().zip(&bars) {
*slot = WickraRunBar {
open: bar.open,
high: bar.high,
low: bar.low,
close: bar.close,
length: bar.length,
direction: bar.direction,
};
}
}
bars.len()
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_run_bars_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_run_bars_reset(handle: *mut RunBars) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_run_bars_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_run_bars_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_run_bars_free(handle: *mut RunBars) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `ThreeLineBreakBars` bar builder.
///
/// Returns `NULL` on invalid parameters; release with `wickra_three_line_break_bars_free`.
#[no_mangle]
pub extern "C" fn wickra_three_line_break_bars_new(lines: usize) -> *mut ThreeLineBreakBars {
match ThreeLineBreakBars::new(lines) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; writes up to `cap` completed bars into `out` and returns the
/// total number completed on this candle (0, 1, or several). If the return exceeds `cap`,
/// the surplus is not written — enlarge `cap` (a single candle rarely completes many bars;
/// `cap >= 64` is safe). Returns 0 on a `NULL` handle or an invalid candle.
///
/// # Safety
/// `handle` (from `wickra_three_line_break_bars_new`, not freed) and `out` must be valid or `NULL`; when
/// non-`NULL`, `out` must cover `cap` `WickraLineBreakBar` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_line_break_bars_update(
handle: *mut ThreeLineBreakBars,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraLineBreakBar,
cap: usize,
) -> usize {
let Some(builder) = handle.as_mut() else {
return 0;
};
let Ok(candle) = Candle::new(open, high, low, close, volume, timestamp) else {
return 0;
};
let bars = builder.update(candle);
if !out.is_null() {
let slots = slice::from_raw_parts_mut(out, cap);
for (slot, bar) in slots.iter_mut().zip(&bars) {
*slot = WickraLineBreakBar {
open: bar.open,
close: bar.close,
direction: bar.direction,
};
}
}
bars.len()
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_three_line_break_bars_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_line_break_bars_reset(handle: *mut ThreeLineBreakBars) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_three_line_break_bars_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_three_line_break_bars_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_three_line_break_bars_free(handle: *mut ThreeLineBreakBars) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `TickBars` bar builder.
///
/// Returns `NULL` on invalid parameters; release with `wickra_tick_bars_free`.
#[no_mangle]
pub extern "C" fn wickra_tick_bars_new(ticks: usize) -> *mut TickBars {
match TickBars::new(ticks) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; writes up to `cap` completed bars into `out` and returns the
/// total number completed on this candle (0, 1, or several). If the return exceeds `cap`,
/// the surplus is not written — enlarge `cap` (a single candle rarely completes many bars;
/// `cap >= 64` is safe). Returns 0 on a `NULL` handle or an invalid candle.
///
/// # Safety
/// `handle` (from `wickra_tick_bars_new`, not freed) and `out` must be valid or `NULL`; when
/// non-`NULL`, `out` must cover `cap` `WickraTickBar` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_tick_bars_update(
handle: *mut TickBars,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraTickBar,
cap: usize,
) -> usize {
let Some(builder) = handle.as_mut() else {
return 0;
};
let Ok(candle) = Candle::new(open, high, low, close, volume, timestamp) else {
return 0;
};
let bars = builder.update(candle);
if !out.is_null() {
let slots = slice::from_raw_parts_mut(out, cap);
for (slot, bar) in slots.iter_mut().zip(&bars) {
*slot = WickraTickBar {
open: bar.open,
high: bar.high,
low: bar.low,
close: bar.close,
volume: bar.volume,
};
}
}
bars.len()
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_tick_bars_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tick_bars_reset(handle: *mut TickBars) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_tick_bars_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_tick_bars_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_tick_bars_free(handle: *mut TickBars) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// Create a `VolumeBars` bar builder.
///
/// Returns `NULL` on invalid parameters; release with `wickra_volume_bars_free`.
#[no_mangle]
pub extern "C" fn wickra_volume_bars_new(volume_per_bar: f64) -> *mut VolumeBars {
match VolumeBars::new(volume_per_bar) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one OHLCV candle; writes up to `cap` completed bars into `out` and returns the
/// total number completed on this candle (0, 1, or several). If the return exceeds `cap`,
/// the surplus is not written — enlarge `cap` (a single candle rarely completes many bars;
/// `cap >= 64` is safe). Returns 0 on a `NULL` handle or an invalid candle.
///
/// # Safety
/// `handle` (from `wickra_volume_bars_new`, not freed) and `out` must be valid or `NULL`; when
/// non-`NULL`, `out` must cover `cap` `WickraVolumeBar` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_bars_update(
handle: *mut VolumeBars,
open: f64,
high: f64,
low: f64,
close: f64,
volume: f64,
timestamp: i64,
out: *mut WickraVolumeBar,
cap: usize,
) -> usize {
let Some(builder) = handle.as_mut() else {
return 0;
};
let Ok(candle) = Candle::new(open, high, low, close, volume, timestamp) else {
return 0;
};
let bars = builder.update(candle);
if !out.is_null() {
let slots = slice::from_raw_parts_mut(out, cap);
for (slot, bar) in slots.iter_mut().zip(&bars) {
*slot = WickraVolumeBar {
open: bar.open,
high: bar.high,
low: bar.low,
close: bar.close,
volume: bar.volume,
};
}
}
bars.len()
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_volume_bars_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_bars_reset(handle: *mut VolumeBars) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_volume_bars_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_volume_bars_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_volume_bars_free(handle: *mut VolumeBars) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
// ===== Bespoke wirings (MaType-enum ctor, Vec<struct> output) =====
/// Moving-average selector for `wickra_macd_ext_new`: 0=SMA, 1=EMA, 2=WMA, 3=DEMA,
/// 4=TEMA, 5=TRIMA. Any other value is rejected.
fn ma_type_from_u8(value: u8) -> Option<MaType> {
match value {
0 => Some(MaType::Sma),
1 => Some(MaType::Ema),
2 => Some(MaType::Wma),
3 => Some(MaType::Dema),
4 => Some(MaType::Tema),
5 => Some(MaType::Trima),
_ => None,
}
}
/// Create a `MacdExt`. `fast_type` / `slow_type` / `signal_type` pick the moving
/// average per `ma_type_from_u8`. Returns `NULL` on invalid parameters or an unknown
/// MA-type code; release with `wickra_macd_ext_free`.
#[no_mangle]
pub extern "C" fn wickra_macd_ext_new(
fast: usize,
fast_type: u8,
slow: usize,
slow_type: u8,
signal: usize,
signal_type: u8,
) -> *mut MacdExt {
let (Some(ft), Some(st), Some(gt)) = (
ma_type_from_u8(fast_type),
ma_type_from_u8(slow_type),
ma_type_from_u8(signal_type),
) else {
return ptr::null_mut();
};
match MacdExt::new(fast, ft, slow, st, signal, gt) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one value; on `true` the MACD/signal/histogram triple is written to `*out`.
/// Returns `false` during warmup, on a `NULL` handle / `out`.
///
/// # Safety
/// `handle` (from `wickra_macd_ext_new`, not freed) and `out` must be valid or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_macd_ext_update(
handle: *mut MacdExt,
value: f64,
out: *mut WickraMacdOutput,
) -> bool {
let Some(ind) = handle.as_mut() else {
return false;
};
if out.is_null() {
return false;
}
match ind.update(value) {
Some(out_val) => {
*out = WickraMacdOutput {
macd: out_val.macd,
signal: out_val.signal,
histogram: out_val.histogram,
};
true
}
None => false,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_macd_ext_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_macd_ext_reset(handle: *mut MacdExt) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_macd_ext_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_macd_ext_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_macd_ext_free(handle: *mut MacdExt) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
/// C-ABI view of one `FootprintLevel` (price bucket with bid/ask volume).
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WickraFootprintLevel {
pub price: f64,
pub bid_vol: f64,
pub ask_vol: f64,
}
/// Create a `Footprint` order-flow aggregator. Returns `NULL` on invalid parameters;
/// release with `wickra_footprint_free`.
#[no_mangle]
pub extern "C" fn wickra_footprint_new(tick_size: f64) -> *mut Footprint {
match Footprint::new(tick_size) {
Ok(ind) => Box::into_raw(Box::new(ind)),
Err(_) => ptr::null_mut(),
}
}
/// Feed one trade. Returns `-1` during warmup / on a `NULL` handle / invalid trade,
/// otherwise the number of price levels in the completed footprint; up to `cap` levels
/// are written to `out` (enlarge `cap` if the return exceeds it).
///
/// # Safety
/// `handle` (from `wickra_footprint_new`, not freed) and `out` must be valid or `NULL`;
/// when non-`NULL`, `out` must cover `cap` `WickraFootprintLevel` elements.
#[no_mangle]
pub unsafe extern "C" fn wickra_footprint_update(
handle: *mut Footprint,
price: f64,
size: f64,
is_buy: bool,
timestamp: i64,
out: *mut WickraFootprintLevel,
cap: usize,
) -> isize {
let Some(ind) = handle.as_mut() else {
return -1;
};
let side = if is_buy { Side::Buy } else { Side::Sell };
let Ok(trade) = Trade::new(price, size, side, timestamp) else {
return -1;
};
match ind.update(trade) {
Some(out_val) => {
if !out.is_null() {
let slots = slice::from_raw_parts_mut(out, cap);
for (slot, level) in slots.iter_mut().zip(&out_val.levels) {
*slot = WickraFootprintLevel {
price: level.price,
bid_vol: level.bid_vol,
ask_vol: level.ask_vol,
};
}
}
isize::try_from(out_val.levels.len()).unwrap_or(isize::MAX)
}
None => -1,
}
}
/// Reset all internal state. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must be valid (from `wickra_footprint_new`, not freed), or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_footprint_reset(handle: *mut Footprint) {
if let Some(ind) = handle.as_mut() {
ind.reset();
}
}
/// Destroy a handle created by `wickra_footprint_new`. No-op if `handle` is `NULL`.
///
/// # Safety
/// `handle` must have been returned by `wickra_footprint_new` and not previously freed, or `NULL`.
#[no_mangle]
pub unsafe extern "C" fn wickra_footprint_free(handle: *mut Footprint) {
if !handle.is_null() {
drop(Box::from_raw(handle));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_rejects_zero_period() {
assert!(wickra_sma_new(0).is_null());
}
#[test]
fn scalar_streaming_batch_and_lifecycle() {
let handle = wickra_sma_new(3);
assert!(!handle.is_null());
unsafe {
assert!(wickra_sma_update(handle, 1.0).is_nan());
assert!(wickra_sma_update(handle, 2.0).is_nan());
assert!((wickra_sma_update(handle, 3.0) - 2.0).abs() < 1e-9);
wickra_sma_reset(handle);
let input = [1.0_f64, 2.0, 3.0, 4.0, 5.0];
let mut out = [0.0_f64; 5];
wickra_sma_batch(handle, input.as_ptr(), out.as_mut_ptr(), 5);
assert!(out[0].is_nan());
assert!((out[2] - 2.0).abs() < 1e-9);
assert!((out[4] - 4.0).abs() < 1e-9);
wickra_sma_free(handle);
}
}
#[test]
fn null_handle_is_a_defined_noop() {
unsafe {
assert!(wickra_sma_update(ptr::null_mut(), 1.0).is_nan());
wickra_sma_reset(ptr::null_mut());
wickra_sma_free(ptr::null_mut());
}
}
}