Daily Factor

Parameters: threshold_level = 0.35 (0–1)

Overview

Daily Factor reduces each bar to a simple normalized intensity measure: the size of the previous candle body divided by the previous candle range. That produces a value between zero and one when the range is valid, making it easy to treat the output as a compact measure of how forceful the prior session really was.

The indicator then compares the current close to a 14-period EMA of close and combines that directional context with the normalized body factor. If the factor rises above the configured threshold, the signal upgrades to a stronger positive or negative state depending on whether price sits above or below the EMA. Otherwise it falls back to a weaker trend classification tied only to the EMA relationship. The result is a small three-output tool that behaves like a regime label rather than a continuous oscillator alone.

Defaults: Daily Factor uses `threshold_level = 0.35` and an internal `EMA period = 14`.

Implementation Examples

Compute the normalized factor, its EMA companion, and the final signal state from OHLC slices or candle data.

use vector_ta::indicators::daily_factor::{
    daily_factor,
    DailyFactorInput,
    DailyFactorParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let output = daily_factor(&DailyFactorInput::from_slices(
    &open,
    &high,
    &low,
    &close,
    DailyFactorParams::default(),
))?;

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

println!("value = {:?}", output.value.last());
println!("ema = {:?}", output.ema.last());
println!("signal = {:?}", candle_output.signal.last());

API Reference

Input Methods
// From candles
DailyFactorInput::from_candles(&Candles, DailyFactorParams)
    -> DailyFactorInput

// From OHLC slices
DailyFactorInput::from_slices(&[f64], &[f64], &[f64], &[f64], DailyFactorParams)
    -> DailyFactorInput

// From candles with default parameters
DailyFactorInput::with_default_candles(&Candles)
    -> DailyFactorInput
Parameters Structure
pub struct DailyFactorParams {
    pub threshold_level: Option<f64>, // default 0.35
}
Output Structure
pub struct DailyFactorOutput {
    pub value: Vec<f64>,
    pub ema: Vec<f64>,
    pub signal: Vec<f64>,
}
Validation, Warmup & NaNs
  • Open, high, low, and close must all be non-empty slices with identical lengths.
  • The indicator requires at least one bar where all four OHLC values are finite, otherwise it returns AllValuesNaN.
  • threshold_level must be finite and stay within 0.0..=1.0.
  • The output is prefixed with NaN up to the first valid OHLC bar, since the factor uses the previous candle once a valid run begins.
  • Streaming returns (NaN, NaN, NaN) for invalid OHLC input rather than mutating into an error state.
  • Batch mode rejects invalid floating-point ranges and non-batch kernels.
  • In-place destination buffers must match the expected single-run or flattened batch output lengths exactly.
Builder, Streaming & Batch APIs
// Builder
DailyFactorBuilder::new()
    .threshold_level(f64)
    .kernel(Kernel)
    .apply_slices(&[f64], &[f64], &[f64], &[f64])

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

DailyFactorBuilder::new()
    .into_stream()

// Stream
DailyFactorStream::try_new(DailyFactorParams)
DailyFactorStream::update(open, high, low, close) -> (f64, f64, f64)

// Batch
DailyFactorBatchBuilder::new()
    .threshold_level_range((start, end, step))
    .kernel(Kernel)
    .apply_slices(&[f64], &[f64], &[f64], &[f64])
Error Handling
pub enum DailyFactorError {
    EmptyInputData,
    AllValuesNaN,
    InconsistentSliceLengths { open_len: usize, high_len: usize, low_len: usize, close_len: usize },
    InvalidThresholdLevel { threshold_level: f64 },
    OutputLengthMismatch { expected: usize, got: usize },
    InvalidRange { start: String, end: String, step: String },
    InvalidKernelForBatch(Kernel),
}

Python Bindings

Python exposes a dictionary-returning single-run function, a streaming class, and a batch function. The single-run binding returns NumPy arrays for value, ema, and signal. Batch returns those same matrices plus the tested threshold levels and the final rows and cols shape.

import numpy as np
from vector_ta import (
    daily_factor,
    daily_factor_batch,
    DailyFactorStream,
)

open_ = np.asarray(open_values, dtype=np.float64)
high = np.asarray(high_values, dtype=np.float64)
low = np.asarray(low_values, dtype=np.float64)
close = np.asarray(close_values, dtype=np.float64)

result = daily_factor(
    open_,
    high,
    low,
    close,
    threshold_level=0.35,
    kernel="auto",
)

print(result["value"], result["signal"])

stream = DailyFactorStream(threshold_level=0.35)
print(stream.update(open_[-1], high[-1], low[-1], close[-1]))

batch = daily_factor_batch(
    open_,
    high,
    low,
    close,
    threshold_level_range=(0.25, 0.45, 0.10),
    kernel="auto",
)

print(batch["threshold_levels"], batch["rows"], batch["cols"])

JavaScript/WASM Bindings

The WASM layer exposes object-returning single-run and batch wrappers plus lower-level allocation and in-place exports. The standard JavaScript path returns an object with value, ema, and signal arrays. The batch wrapper adds the tested threshold-level axis together with the final rows and cols shape.

import init, {
  daily_factor_js,
  daily_factor_batch_js,
} from "/pkg/vector_ta.js";

await init();

const open = new Float64Array(openValues);
const high = new Float64Array(highValues);
const low = new Float64Array(lowValues);
const close = new Float64Array(closeValues);

const result = daily_factor_js(open, high, low, close, 0.35);
console.log(result.value, result.signal);

const batch = daily_factor_batch_js(open, high, low, close, {
  threshold_level_range: [0.25, 0.45, 0.10],
});

console.log(batch.threshold_levels, 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