Kase Peak Oscillator With Divergences

Parameters: deviations = 2 | short_cycle = 8 | long_cycle = 65 | sensitivity = 40 | all_peaks_mode = true | lb_r = 5 | lb_l = 5 | range_upper = 60 | range_lower = 5 | plot_bull = true | plot_hidden_bull = | plot_bear = true | plot_hidden_bear =

Overview

Kase Peak Oscillator With Divergences computes a volatility-normalized oscillator from OHLC data and then layers in threshold, peak, and divergence signals. Internally it builds a log-return based oscillator, smooths the strongest upside and downside cycle responses across the short_cycle to long_cycle scan, and then turns that structure into the main oscillator and histogram outputs. The current implementation sets histogram equal to the oscillator, then derives dynamic peak bands, market-extreme markers, bullish and bearish divergence markers, and go_long or go_short flags when a market extreme occurs.

Defaults: deviations = 2.0, short_cycle = 8, long_cycle = 65, sensitivity = 40.0, all_peaks_mode = true, lb_r = 5, lb_l = 5, range_upper = 60, range_lower = 5, plot_bull = true, plot_hidden_bull = false, plot_bear = true, and plot_hidden_bear = false. Candle input uses built-in high, low, and close values directly.

Implementation Examples

Use explicit OHLC slices or candle data:

use vector_ta::indicators::kase_peak_oscillator_with_divergences::{
    kase_peak_oscillator_with_divergences,
    KasePeakOscillatorWithDivergencesInput,
    KasePeakOscillatorWithDivergencesParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let high = vec![101.0, 103.0, 104.2, 105.6, 106.1, 107.4];
let low = vec![99.5, 100.8, 101.7, 103.0, 103.9, 104.8];
let close = vec![100.2, 102.4, 103.6, 104.7, 105.2, 106.9];

let input = KasePeakOscillatorWithDivergencesInput::from_slices(
    &high,
    &low,
    &close,
    KasePeakOscillatorWithDivergencesParams::default(),
);
let out = kase_peak_oscillator_with_divergences(&input)?;

// Candles path uses candles.high / candles.low / candles.close
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_out = kase_peak_oscillator_with_divergences(
    &KasePeakOscillatorWithDivergencesInput::with_default_candles(&candles),
)?;

println!("oscillator last = {:?}", out.oscillator.last());
println!("go_long last = {:?}", out.go_long.last());
println!("regular_bearish last = {:?}", out.regular_bearish.last());

API Reference

Input Methods
// From candles (uses candles.high, candles.low, candles.close)
KasePeakOscillatorWithDivergencesInput::from_candles(
    &Candles,
    KasePeakOscillatorWithDivergencesParams,
) -> KasePeakOscillatorWithDivergencesInput

// From explicit OHLC slices
KasePeakOscillatorWithDivergencesInput::from_slices(
    &[f64],
    &[f64],
    &[f64],
    KasePeakOscillatorWithDivergencesParams,
) -> KasePeakOscillatorWithDivergencesInput

// From candles with defaults
KasePeakOscillatorWithDivergencesInput::with_default_candles(&Candles)
    -> KasePeakOscillatorWithDivergencesInput
Parameters and Outputs
pub struct KasePeakOscillatorWithDivergencesParams {
    pub deviations: Option<f64>,
    pub short_cycle: Option<usize>,
    pub long_cycle: Option<usize>,
    pub sensitivity: Option<f64>,
    pub all_peaks_mode: Option<bool>,
    pub lb_r: Option<usize>,
    pub lb_l: Option<usize>,
    pub range_upper: Option<usize>,
    pub range_lower: Option<usize>,
    pub plot_bull: Option<bool>,
    pub plot_hidden_bull: Option<bool>,
    pub plot_bear: Option<bool>,
    pub plot_hidden_bear: Option<bool>,
}

pub struct KasePeakOscillatorWithDivergencesOutput {
    pub oscillator: Vec<f64>,
    pub histogram: Vec<f64>,
    pub max_peak_value: Vec<f64>,
    pub min_peak_value: Vec<f64>,
    pub market_extreme: Vec<f64>,
    pub regular_bullish: Vec<f64>,
    pub hidden_bullish: Vec<f64>,
    pub regular_bearish: Vec<f64>,
    pub hidden_bearish: Vec<f64>,
    pub go_long: Vec<f64>,
    pub go_short: Vec<f64>,
}
Builder, Stream, and Batch Surface
KasePeakOscillatorWithDivergencesBuilder::new()
    .deviations(f64)
    .short_cycle(usize)
    .long_cycle(usize)
    .sensitivity(f64)
    .all_peaks_mode(bool)
    .lb_r(usize)
    .lb_l(usize)
    .range_upper(usize)
    .range_lower(usize)
    .plot_bull(bool)
    .plot_hidden_bull(bool)
    .plot_bear(bool)
    .plot_hidden_bear(bool)
    .kernel(Kernel)
    .apply(&Candles) -> Result<KasePeakOscillatorWithDivergencesOutput, _>

KasePeakOscillatorWithDivergencesBuilder::new()
    .apply_slices(&[f64], &[f64], &[f64]) -> Result<KasePeakOscillatorWithDivergencesOutput, _>

KasePeakOscillatorWithDivergencesBuilder::new()
    .into_stream() -> Result<KasePeakOscillatorWithDivergencesStream, _>

KasePeakOscillatorWithDivergencesStream::update(high, low, close)
    -> Option<(f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64)>

KasePeakOscillatorWithDivergencesBatchBuilder::new()
    .deviations_range((f64, f64, f64))
    .short_cycle_range((usize, usize, usize))
    .long_cycle_range((usize, usize, usize))
    .sensitivity_range((f64, f64, f64))
    .kernel(Kernel)
    .apply_slices(&[f64], &[f64], &[f64])
    -> Result<KasePeakOscillatorWithDivergencesBatchOutput, _>
Warmup, NaNs, and Validation
  • Inputs must be non-empty equal-length high, low, and close series.
  • Valid OHLC values must be finite and strictly positive. Invalid bars reset the stream and yield None for that update.
  • Parameter validation rejects negative or non-finite deviations, non-finite sensitivity, zero lb_l/lb_r, zero range_lower/range_upper, range_lower > range_upper, and any short_cycle >= long_cycle.
  • prepare_input requires at least main_warmup(short_cycle, long_cycle) + 1 valid bars, where main_warmup = max(long_cycle, 39) + 1.
  • For the batch API, leading NaN prefixes are allocated separately for main oscillator outputs, peak outputs, and divergence outputs.
  • Main oscillator and histogram warmup prefix: first_valid + main_warmup.
  • Peak and market-extreme warmup prefix: first_valid + main_warmup + 49, because the threshold logic uses 50-bar rolling stats of |oscillator|.
  • Divergence warmup prefix: first_valid + main_warmup + lb_l + lb_r.
Peak and Divergence Semantics
  • histogram currently mirrors oscillator.
  • max_peak_value and min_peak_value come from abs_avg + deviations * abs_std with a 90.0 floor/ceiling, then signed to match oscillator direction.
  • market_extreme marks a local turning point based on the previous two oscillator values. With all_peaks_mode = false, the prior peak must also exceed the threshold band.
  • go_long = 1.0 when market_extreme < 0; go_short = 1.0 when market_extreme > 0; otherwise both stay 0.0 once their warmup has passed.
  • Regular bullish divergence requires a lower price low and a higher oscillator low; hidden bullish requires a higher price low and a lower oscillator low.
  • Regular bearish divergence requires a higher price high and a lower oscillator high; hidden bearish requires a lower price high and a higher oscillator high.
  • Divergence pivots must be separated by a number of bars inside [range_lower, range_upper] and the corresponding plot_* toggle must be enabled.
Batch Output and Errors
pub struct KasePeakOscillatorWithDivergencesBatchOutput {
    pub oscillator: Vec<f64>,
    pub histogram: Vec<f64>,
    pub max_peak_value: Vec<f64>,
    pub min_peak_value: Vec<f64>,
    pub market_extreme: Vec<f64>,
    pub regular_bullish: Vec<f64>,
    pub hidden_bullish: Vec<f64>,
    pub regular_bearish: Vec<f64>,
    pub hidden_bearish: Vec<f64>,
    pub go_long: Vec<f64>,
    pub go_short: Vec<f64>,
    pub deviations: Vec<f64>,
    pub short_cycles: Vec<usize>,
    pub long_cycles: Vec<usize>,
    pub sensitivities: Vec<f64>,
    pub rows: usize,
    pub cols: usize,
}

// Common errors:
// - EmptyInputData / AllValuesNaN
// - InconsistentSliceLengths
// - InvalidDeviations / InvalidShortCycle / InvalidLongCycle / InvalidCycleOrder
// - InvalidSensitivity / InvalidLbR / InvalidLbL
// - InvalidRangeUpper / InvalidRangeLower / InvalidDivergenceRange
// - NotEnoughValidData
// - OutputLengthMismatch
// - InvalidRange
// - InvalidKernelForBatch

Python Bindings

Basic Usage

The Python scalar function returns 11 NumPy arrays in output-struct order:

import numpy as np
from vector_ta import kase_peak_oscillator_with_divergences

oscillator, histogram, max_peak_value, min_peak_value, market_extreme, regular_bullish, hidden_bullish, regular_bearish, hidden_bearish, go_long, go_short = kase_peak_oscillator_with_divergences(
    high,
    low,
    close,
    deviations=2.0,
    short_cycle=8,
    long_cycle=65,
    sensitivity=40.0,
    all_peaks_mode=True,
    lb_r=5,
    lb_l=5,
    range_upper=60,
    range_lower=5,
    plot_bull=True,
    plot_hidden_bull=False,
    plot_bear=True,
    plot_hidden_bear=False,
    kernel="auto",
)
Streaming Real-time Updates

The Python stream class exposes the same 11-value tuple plus a warmup_period getter:

from vector_ta import KasePeakOscillatorWithDivergencesStream

stream = KasePeakOscillatorWithDivergencesStream()
print(stream.warmup_period)

for high_i, low_i, close_i in live_feed:
    result = stream.update(high_i, low_i, close_i)
    if result is not None:
        (
            oscillator,
            histogram,
            max_peak_value,
            min_peak_value,
            market_extreme,
            regular_bullish,
            hidden_bullish,
            regular_bearish,
            hidden_bearish,
            go_long,
            go_short,
        ) = result
Batch Processing

Batch results are returned as a dict of 2D outputs plus parameter columns:

from vector_ta import kase_peak_oscillator_with_divergences_batch

result = kase_peak_oscillator_with_divergences_batch(
    high,
    low,
    close,
    deviations_range=(1.5, 2.5, 0.5),
    short_cycle_range=(8, 10, 1),
    long_cycle_range=(55, 65, 5),
    sensitivity_range=(30.0, 40.0, 10.0),
    all_peaks_mode=True,
    lb_r=5,
    lb_l=5,
    range_upper=60,
    range_lower=5,
    plot_bull=True,
    plot_hidden_bull=False,
    plot_bear=True,
    plot_hidden_bear=False,
    kernel="auto",
)

oscillator = result["oscillator"]
histogram = result["histogram"]
max_peak_value = result["max_peak_value"]
min_peak_value = result["min_peak_value"]
market_extreme = result["market_extreme"]
regular_bullish = result["regular_bullish"]
hidden_bullish = result["hidden_bullish"]
regular_bearish = result["regular_bearish"]
hidden_bearish = result["hidden_bearish"]
go_long = result["go_long"]
go_short = result["go_short"]
deviations = result["deviations"]
short_cycles = result["short_cycles"]
long_cycles = result["long_cycles"]
sensitivities = result["sensitivities"]
rows = result["rows"]
cols = result["cols"]

JavaScript/WASM Bindings

Basic Usage

The JS/WASM scalar function returns an object with 11 typed arrays:

import { kase_peak_oscillator_with_divergences_js } from 'vectorta-wasm';

const result = kase_peak_oscillator_with_divergences_js(
  high,
  low,
  close,
  2.0,
  8,
  65,
  40.0,
  true,
  5,
  5,
  60,
  5,
  true,
  false,
  true,
  false,
) as {
  oscillator: Float64Array;
  histogram: Float64Array;
  max_peak_value: Float64Array;
  min_peak_value: Float64Array;
  market_extreme: Float64Array;
  regular_bullish: Float64Array;
  hidden_bullish: Float64Array;
  regular_bearish: Float64Array;
  hidden_bearish: Float64Array;
  go_long: Float64Array;
  go_short: Float64Array;
};

console.log(result.oscillator);
console.log(result.market_extreme);
console.log(result.go_long);
Host Buffer API

Low-level WASM writes into 11 separate output buffers. Allocate one buffer per output with kase_peak_oscillator_with_divergences_alloc(len):

import {
  kase_peak_oscillator_with_divergences_alloc,
  kase_peak_oscillator_with_divergences_free,
  kase_peak_oscillator_with_divergences_into,
} from 'vectorta-wasm';

const len = close.length;
const oscillatorPtr = kase_peak_oscillator_with_divergences_alloc(len);
const histogramPtr = kase_peak_oscillator_with_divergences_alloc(len);
// ... allocate max_peak_value, min_peak_value, market_extreme,
// regular_bullish, hidden_bullish, regular_bearish, hidden_bearish,
// go_long, and go_short the same way ...

try {
  kase_peak_oscillator_with_divergences_into(
    highPtr,
    lowPtr,
    closePtr,
    oscillatorPtr,
    histogramPtr,
    maxPeakPtr,
    minPeakPtr,
    marketExtremePtr,
    regularBullishPtr,
    hiddenBullishPtr,
    regularBearishPtr,
    hiddenBearishPtr,
    goLongPtr,
    goShortPtr,
    len,
    2.0,
    8,
    65,
    40.0,
    true,
    5,
    5,
    60,
    5,
    true,
    false,
    true,
    false,
  );
} finally {
  kase_peak_oscillator_with_divergences_free(oscillatorPtr, len);
  kase_peak_oscillator_with_divergences_free(histogramPtr, len);
}
Batch Processing

The JS batch config accepts optional ranges and optional fixed booleans/lookbacks:

import { kase_peak_oscillator_with_divergences_batch_js } from 'vectorta-wasm';

const batch = kase_peak_oscillator_with_divergences_batch_js(high, low, close, {
  deviations_range: [1.5, 2.5, 0.5],
  short_cycle_range: [8, 10, 1],
  long_cycle_range: [55, 65, 5],
  sensitivity_range: [30.0, 40.0, 10.0],
  all_peaks_mode: true,
  lb_r: 5,
  lb_l: 5,
  range_upper: 60,
  range_lower: 5,
  plot_bull: true,
  plot_hidden_bull: false,
  plot_bear: true,
  plot_hidden_bear: false,
}) as {
  oscillator: number[];
  histogram: number[];
  max_peak_value: number[];
  min_peak_value: number[];
  market_extreme: number[];
  regular_bullish: number[];
  hidden_bullish: number[];
  regular_bearish: number[];
  hidden_bearish: number[];
  go_long: number[];
  go_short: number[];
  deviations: number[];
  short_cycles: number[];
  long_cycles: number[];
  sensitivities: number[];
  rows: number;
  cols: number;
};

console.log(batch.rows, batch.cols);
console.log(batch.deviations);
console.log(batch.short_cycles);

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