Forward Backward Exponential Oscillator

Parameters: length = 20 | smooth = 10

Overview

Forward Backward Exponential Oscillator is a three-line momentum study built from a smoothed price stream and two complementary rolling transforms. The first output, `forward_backward`, evaluates the smoothed series through a forward-backward window. The second, `backward`, measures the signed balance of recent EMA differences against their absolute magnitude. The third line, `histogram`, blends the gap between those two scores back into a bounded oscillator-style series.

In practice, the indicator behaves like a normalized momentum framework rather than a raw trend overlay. Candle mode defaults to `close`, the streaming path works one value at a time, and both the one-shot and streaming implementations naturally withhold output until their rolling windows have enough history to produce finite scores.

Defaults: Forward Backward Exponential Oscillator uses `length = 20`, `smooth = 10`, and defaults candle input to `close`.

Implementation Examples

Compute the forward-backward score, backward score, and histogram from a raw series or candle closes.

use vector_ta::indicators::forward_backward_exponential_oscillator::{
    forward_backward_exponential_oscillator,
    ForwardBackwardExponentialOscillatorInput,
    ForwardBackwardExponentialOscillatorParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let close = vec![100.0, 100.7, 101.3, 101.0, 102.2, 101.9, 103.0];

let output = forward_backward_exponential_oscillator(
    &ForwardBackwardExponentialOscillatorInput::from_slice(
        &close,
        ForwardBackwardExponentialOscillatorParams {
            length: Some(20),
            smooth: Some(10),
        },
    )
)?;

let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = forward_backward_exponential_oscillator(
    &ForwardBackwardExponentialOscillatorInput::with_default_candles(&candles)
)?;

println!("forward_backward = {:?}", output.forward_backward.last());
println!("backward = {:?}", candle_output.backward.last());
println!("histogram = {:?}", candle_output.histogram.last());

API Reference

Input Methods
// From candles and a named source field
ForwardBackwardExponentialOscillatorInput::from_candles(
    &Candles,
    &str,
    ForwardBackwardExponentialOscillatorParams,
) -> ForwardBackwardExponentialOscillatorInput

// From a raw slice
ForwardBackwardExponentialOscillatorInput::from_slice(
    &[f64],
    ForwardBackwardExponentialOscillatorParams,
) -> ForwardBackwardExponentialOscillatorInput

// From candles with default parameters
ForwardBackwardExponentialOscillatorInput::with_default_candles(&Candles)
    -> ForwardBackwardExponentialOscillatorInput
Parameters Structure
pub struct ForwardBackwardExponentialOscillatorParams {
    pub length: Option<usize>, // default 20
    pub smooth: Option<usize>, // default 10
}
Output Structure
pub struct ForwardBackwardExponentialOscillatorOutput {
    pub forward_backward: Vec<f64>,
    pub backward: Vec<f64>,
    pub histogram: Vec<f64>,
}
Validation, Warmup & NaNs
  • The input series must be non-empty and contain at least one finite value.
  • length and smooth must both be positive and valid for the supplied data length.
  • The one-shot output is NaN-prefixed until the rolling windows are long enough to produce the forward-backward and backward scores.
  • Streaming resets on non-finite input and returns None until at least one of the oscillator components becomes finite.
  • histogram is only finite once both the forward-backward and backward scores are finite.
  • Batch mode validates integer ranges and rejects unsupported kernels through InvalidKernelForBatch.
Builder, Streaming & Batch APIs
// Builder
ForwardBackwardExponentialOscillatorBuilder::new()
    .length(usize)
    .smooth(usize)
    .kernel(Kernel)
    .apply_slice(&[f64])

ForwardBackwardExponentialOscillatorBuilder::new()
    .apply(&Candles)

ForwardBackwardExponentialOscillatorBuilder::new()
    .into_stream()

// Stream
ForwardBackwardExponentialOscillatorStream::try_new(
    ForwardBackwardExponentialOscillatorParams
)
ForwardBackwardExponentialOscillatorStream::update(f64)
    -> Option<ForwardBackwardExponentialOscillatorStreamOutput>

// Batch
ForwardBackwardExponentialOscillatorBatchBuilder::new()
    .range(ForwardBackwardExponentialOscillatorBatchRange)
    .kernel(Kernel)
    .apply_slice(&[f64])

ForwardBackwardExponentialOscillatorBatchBuilder::new()
    .apply(&Candles)
Error Handling
pub enum ForwardBackwardExponentialOscillatorError {
    EmptyInputData,
    AllValuesNaN,
    InvalidLength { length: usize, data_len: usize },
    InvalidSmooth { smooth: usize, data_len: usize },
    NotEnoughValidData { needed: usize, valid: usize },
    OutputLengthMismatch { expected: usize, got: usize },
    InvalidRange { start: String, end: String, step: String },
    InvalidKernelForBatch(Kernel),
}

Python Bindings

Python exposes dict-returning scalar and batch functions plus a streaming class. The scalar dict contains `forward_backward`, `backward`, and `histogram`. The stream returns a three-value tuple, and batch returns the same three outputs in matrix form plus the tested length and smooth arrays.

import numpy as np
from vector_ta import (
    forward_backward_exponential_oscillator,
    forward_backward_exponential_oscillator_batch,
    ForwardBackwardExponentialOscillatorStream,
)

data = np.asarray(close_values, dtype=np.float64)

result = forward_backward_exponential_oscillator(
    data,
    length=20,
    smooth=10,
    kernel="auto",
)

print(result["forward_backward"], result["histogram"])

stream = ForwardBackwardExponentialOscillatorStream(length=20, smooth=10)
print(stream.update(data[-1]))

batch = forward_backward_exponential_oscillator_batch(
    data,
    length_range=(20, 30, 10),
    smooth_range=(10, 14, 4),
    kernel="auto",
)

print(batch["forward_backward"].shape, batch["backward"].shape)
print(batch["lengths"], batch["smooths"], batch["rows"], batch["cols"])

JavaScript/WASM Bindings

The WASM layer exposes object-returning scalar and batch wrappers. The scalar JavaScript path returns `forward_backward`, `backward`, and `histogram` arrays. Batch adds `combos`, `rows`, and `cols`.

import init, {
  forward_backward_exponential_oscillator_js,
  forward_backward_exponential_oscillator_batch,
} from "/pkg/vector_ta.js";

await init();

const out = forward_backward_exponential_oscillator_js(closeValues, 20, 10);
console.log(out.forward_backward, out.backward, out.histogram);

const batch = forward_backward_exponential_oscillator_batch(closeValues, {
  length_range: [20, 30, 10],
  smooth_range: [10, 14, 4],
});

console.log(batch.forward_backward, batch.histogram, batch.lengths, batch.smooths, batch.rows, batch.cols);

CUDA Bindings (Rust)

Additional details for the CUDA bindings can be found inside the VectorTA repository.

Performance Analysis

Comparison:
View:
Placeholder data (no recorded benchmarks for this indicator)

Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.

Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)

Related Indicators