Logarithmic Moving Average

Parameters: period = 100 | steepness = 2.5 | ma_type = ema | smooth = 10 | momentum_weight = 1.2 | long_threshold = 0.5 | short_threshold = -0.5

Overview

Logarithmic Moving Average uses an inverse logarithmic weighting curve to emphasize recent prices without falling off as aggressively as a short EMA. VectorTA computes that weighted baseline, measures its slope against a lookback anchor, combines that slope with logarithmic momentum and an R-squared quality term, then smooths the resulting signal with the selected moving-average family.

The indicator returns four aligned series: the weighted average itself, the smoothed signal, a position state of `1`, `0`, or `-1` based on the long and short thresholds, and a momentum confirmation flag that turns on when the signal and log-momentum terms agree. The optional `vwma` smoothing path can also incorporate volume.

Defaults: `period = 100`, `steepness = 2.5`, `ma_type = "ema"`, `smooth = 10`, `momentum_weight = 1.2`, `long_threshold = 0.5`, and `short_threshold = -0.5`.

Implementation Examples

Run the indicator on a raw slice or on candle closes with the default configuration.

use vector_ta::indicators::moving_averages::logarithmic_moving_average::{
    logarithmic_moving_average,
    LogarithmicMovingAverageInput,
    LogarithmicMovingAverageParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let close = vec![100.0, 100.6, 101.2, 101.0, 102.4, 103.1, 103.6];

let output = logarithmic_moving_average(&LogarithmicMovingAverageInput::from_slice(
    &close,
    LogarithmicMovingAverageParams {
        period: Some(100),
        steepness: Some(2.5),
        ma_type: Some("ema".to_string()),
        smooth: Some(10),
        momentum_weight: Some(1.2),
        long_threshold: Some(0.5),
        short_threshold: Some(-0.5),
    },
))?;

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

println!("lma = {:?}", output.lma.last());
println!("signal = {:?}", candle_output.signal.last());
println!("position = {:?}", candle_output.position.last());
println!("momentum confirmed = {:?}", candle_output.momentum_confirmed.last());

API Reference

Input Methods
// From candles with an explicit source
LogarithmicMovingAverageInput::from_candles(&Candles, &str, LogarithmicMovingAverageParams)
    -> LogarithmicMovingAverageInput

// From a raw slice without volume
LogarithmicMovingAverageInput::from_slice(&[f64], LogarithmicMovingAverageParams)
    -> LogarithmicMovingAverageInput

// From a raw slice with an aligned volume series
LogarithmicMovingAverageInput::from_slice_with_volume(&[f64], &[f64], LogarithmicMovingAverageParams)
    -> LogarithmicMovingAverageInput

// From candles with default source and parameters
LogarithmicMovingAverageInput::with_default_candles(&Candles)
    -> LogarithmicMovingAverageInput
Parameters Structure
pub struct LogarithmicMovingAverageParams {
    pub period: Option<usize>,            // default 100
    pub steepness: Option<f64>,           // default 2.5
    pub ma_type: Option<String>,          // default "ema"
    pub smooth: Option<usize>,            // default 10
    pub momentum_weight: Option<f64>,     // default 1.2
    pub long_threshold: Option<f64>,      // default 0.5
    pub short_threshold: Option<f64>,     // default -0.5
}
Output Structure
pub struct LogarithmicMovingAverageOutput {
    pub lma: Vec<f64>,
    pub signal: Vec<f64>,
    pub position: Vec<f64>,
    pub momentum_confirmed: Vec<f64>,
}
Validation, Warmup & NaNs
  • period and smooth must both be greater than 0.
  • steepness and momentum_weight must be finite positive numbers.
  • long_threshold must stay greater than short_threshold.
  • ma_type must normalize to ema, sma, wma, rma, or vwma.
  • The input slice must be non-empty, contain at least one finite value, and include a contiguous finite run at least as long as period.
  • VWMA smoothing requires volume data, and any provided volume slice must match the price slice length.
  • Warmup values remain NaN until enough finite data exists for the logarithmic average, the slope lookback, and the selected signal smoother.
  • The stream returns None until the latest bar produces finite values for all four outputs.
  • Batch mode validates every range axis and rejects unsupported kernels through InvalidKernelForBatch.
Builder, Streaming & Batch APIs
// Builder
LogarithmicMovingAverageBuilder::new()
    .period(usize)
    .steepness(f64)
    .smooth(usize)
    .momentum_weight(f64)
    .long_threshold(f64)
    .short_threshold(f64)
    .kernel(Kernel)
    .apply(&Candles)

LogarithmicMovingAverageBuilder::new()
    .apply_slice(&[f64])

LogarithmicMovingAverageBuilder::new()
    .apply_slice_with_volume(&[f64], &[f64], &str)

LogarithmicMovingAverageBuilder::new()
    .into_stream(&str)

// Stream
LogarithmicMovingAverageStream::try_new(LogarithmicMovingAverageParams)
LogarithmicMovingAverageStream::update(f64, Option<f64>) -> Option<(f64, f64, f64, f64)>

// Batch
LogarithmicMovingAverageBatchBuilder::new()
    .period(usize, usize, usize)
    .steepness(f64, f64, f64)
    .smooth(usize, usize, usize)
    .momentum_weight(f64, f64, f64)
    .long_threshold(f64, f64, f64)
    .short_threshold(f64, f64, f64)
    .ma_type(&str)
    .kernel(Kernel)
    .apply_slice(&[f64])

LogarithmicMovingAverageBatchBuilder::new()
    .apply_slice_with_volume(&[f64], &[f64])

LogarithmicMovingAverageBatchBuilder::new()
    .apply(&Candles)
Error Handling
pub enum LogarithmicMovingAverageError {
    EmptyInputData,
    AllValuesNaN,
    InvalidPeriod { period: usize, data_len: usize },
    InvalidSmooth { smooth: usize, data_len: usize },
    InvalidSteepness { steepness: f64 },
    InvalidMaType { ma_type: String },
    InvalidMomentumWeight { momentum_weight: f64 },
    InvalidThresholds { long_threshold: f64, short_threshold: f64 },
    DataLengthMismatch { data_len: usize, volume_len: usize },
    MissingVolumeForVwma,
    NotEnoughValidData { needed: usize, valid: usize },
    OutputLengthMismatch { expected: usize, got: usize },
    InvalidRange { start: String, end: String, step: String },
    InvalidKernelForBatch(Kernel),
}

Python Bindings

Python exposes a scalar function, a streaming class, and a batch sweep. The scalar function returns four NumPy arrays: `lma`, `signal`, `position`, and `momentum_confirmed`. The stream returns one four-value tuple or `None`, while batch returns flattened matrices plus the tested parameter axes and output dimensions.

import numpy as np
from vector_ta import (
    logarithmic_moving_average,
    logarithmic_moving_average_batch,
    LogarithmicMovingAverageStream,
)

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

lma, signal, position, momentum_confirmed = logarithmic_moving_average(
    data,
    period=100,
    steepness=2.5,
    ma_type="ema",
    smooth=10,
    momentum_weight=1.2,
    long_threshold=0.5,
    short_threshold=-0.5,
    volume=None,
    kernel="auto",
)

stream = LogarithmicMovingAverageStream(
    period=80,
    steepness=2.8,
    ma_type="vwma",
    smooth=8,
    momentum_weight=1.4,
    long_threshold=0.7,
    short_threshold=-0.7,
)
print(stream.update(data[-1], float(volume[-1])))

batch = logarithmic_moving_average_batch(
    data,
    period_range=(60, 100, 20),
    steepness_range=(2.0, 3.0, 0.5),
    smooth_range=(6, 10, 2),
    momentum_weight_range=(1.0, 1.4, 0.2),
    long_threshold_range=(0.4, 0.8, 0.2),
    short_threshold_range=(-0.8, -0.4, 0.2),
    ma_type="ema",
    volume=None,
    kernel="auto",
)

print(batch["signal"].shape)
print(batch["periods"])
print(batch["steepnesses"])

JavaScript/WASM Bindings

The WASM surface exposes scalar, batch, and into-buffer entry points. The scalar function returns an object with `lma`, `signal`, `position`, and `momentum_confirmed` arrays. The batch function returns flattened matrices, output dimensions, and the tested parameter combinations.

import init, {
  logarithmic_moving_average_js,
  logarithmic_moving_average_batch_js,
} from "@vectoralpha/vector_ta";

await init();

const single = logarithmic_moving_average_js(
  close,
  [],
  100,
  2.5,
  "ema",
  10,
  1.2,
  0.5,
  -0.5,
);

console.log(single.lma);
console.log(single.signal);
console.log(single.position);
console.log(single.momentum_confirmed);

const batch = logarithmic_moving_average_batch_js(close, [], {
  period_range: [60, 100, 20],
  steepness_range: [2.0, 3.0, 0.5],
  smooth_range: [6, 10, 2],
  momentum_weight_range: [1.0, 1.4, 0.2],
  long_threshold_range: [0.4, 0.8, 0.2],
  short_threshold_range: [-0.8, -0.4, 0.2],
  ma_type: "ema",
});

console.log(batch.lma);
console.log(batch.signal);
console.log(batch.position);
console.log(batch.momentum_confirmed);
console.log(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