Forward Backward Exponential Oscillator
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.
lengthandsmoothmust 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
Noneuntil at least one of the oscillator components becomes finite. histogramis 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
Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)