CCI Cycle

Parameters: length = 10 | factor = 0.5 (0.1–1)

Overview

CCI Cycle transforms the Commodity Channel Index into a smoothed cyclical oscillator by applying multiple stages of filtering and normalization to isolate market rhythms from noise. The indicator begins with standard CCI calculation, then processes it through double exponential moving averages followed by smoothed moving averages to remove erratic fluctuations. Next, it applies two layers of stochastic normalization that compress the output between 0 and 100, with the factor parameter controlling the final smoothing intensity. Values above 70 indicate cycle peaks where momentum exhausts and reversals become probable, while readings below 30 mark cycle troughs presenting potential bounce opportunities. The double stochastic transformation makes CCI Cycle particularly effective at identifying oversold and overbought conditions within the context of the dominant cycle rather than absolute price levels. Traders use this indicator to time entries at cycle lows and exits at cycle highs, especially in ranging markets where traditional momentum oscillators produce excessive whipsaws.

Implementation Examples

Get started with CCI Cycle in a few lines:

use vectorta::indicators::cci_cycle::{cci_cycle, CciCycleInput, CciCycleParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};

// From a price slice
let prices = vec![100.0, 101.2, 100.5, 102.3, 103.1, 104.0];
let params = CciCycleParams { length: Some(10), factor: Some(0.5) };
let input = CciCycleInput::from_slice(&prices, params);
let out = cci_cycle(&input)?;

// From Candles using defaults (length=10, factor=0.5, source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = CciCycleInput::with_default_candles(&candles);
let out = cci_cycle(&input)?;

// Access values
for v in out.values { println!("CCI Cycle: {}", v); }

API Reference

Input Methods
// From price slice
CciCycleInput::from_slice(&[f64], CciCycleParams) -> CciCycleInput

// From candles with custom source
CciCycleInput::from_candles(&Candles, &str, CciCycleParams) -> CciCycleInput

// Candles with VectorTA defaults (length=10, factor=0.5, source="close")
CciCycleInput::with_default_candles(&Candles) -> CciCycleInput
Parameters Structure
#[derive(Debug, Clone)]
pub struct CciCycleParams {
    pub length: Option<usize>, // Default: 10
    pub factor: Option<f64>,   // Default: 0.5
}
Output Structure
pub struct CciCycleOutput {
    pub values: Vec<f64>, // Normalized 0–100 oscillator values
}
Validation, Warmup & NaNs
  • length > 0 and length ≤ data_len; otherwise CciCycleError::InvalidPeriod.
  • Requires at least length * 2 valid points after the first finite value; otherwise CciCycleError::NotEnoughValidData.
  • Empty input ⇒ CciCycleError::EmptyInputData. All NaNCciCycleError::AllValuesNaN.
  • Warmup: conservative prefix of about first_valid + 4 × length is set to NaN.
  • Kernel selection: Kernel::Auto chooses a best-fit kernel; explicit kernels are supported via cci_cycle_with_kernel/cci_cycle_into_slice.
Error Handling
use vectorta::indicators::cci_cycle::{cci_cycle, CciCycleError, CciCycleInput, CciCycleParams};

let input = CciCycleInput::from_slice(&[], CciCycleParams::default());
match cci_cycle(&input) {
    Ok(out) => consume(out.values),
    Err(CciCycleError::EmptyInputData) => log::error!("no data provided"),
    Err(CciCycleError::AllValuesNaN) => log::error!("all values were NaN"),
    Err(CciCycleError::InvalidPeriod { period, data_len }) =>
        log::warn!("length {period} exceeds data length {data_len}"),
    Err(CciCycleError::NotEnoughValidData { needed, valid }) =>
        log::warn!("need {needed} valid points, only {valid} available"),
    Err(CciCycleError::CciError(e)) => log::error!("cci failed: {e}"),
    Err(CciCycleError::EmaError(e)) => log::error!("ema failed: {e}"),
    Err(CciCycleError::SmmaError(e)) => log::error!("smma failed: {e}"),
}

Python Bindings

Basic Usage
import numpy as np
from vectorta import cci_cycle

prices = np.asarray([100.0, 101.2, 100.5, 102.3, 103.1], dtype=np.float64)
values = cci_cycle(prices, length=10, factor=0.5, kernel="auto")
print(values)

# Force specific kernel during validation
values_scalar = cci_cycle(prices, length=10, factor=0.5, kernel="scalar")
Streaming

A CciCycleStream class is available, but its update method currently returns None (incremental dependencies pending).

from vectorta import CciCycleStream

stream = CciCycleStream(length=10, factor=0.5)
for px in feed_prices():
    _ = stream.update(px)  # returns None for now
Batch Processing
import numpy as np
from vectorta import cci_cycle_batch

prices = np.asarray(load_prices(), dtype=np.float64)
result = cci_cycle_batch(
    prices,
    length_range=(10, 20, 5),
    factor_range=(0.3, 0.7, 0.2),
    kernel="auto",
)

print(result["values"].shape)   # (rows, len(prices))
print(result["lengths"])        # array of length per row
print(result["factors"])        # array of factor per row
CUDA Acceleration

CUDA support for CCI Cycle is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.

# Coming soon: CUDA-accelerated CCI Cycle variants
# (one-series many-params, many-series one-param, zero-copy into)

JavaScript/WASM Bindings

Basic Usage
import { cci_cycle_js } from 'vectorta-wasm';

const prices = new Float64Array([100.0, 101.2, 100.5, 102.3, 103.1]);
const values = cci_cycle_js(prices, 10, 0.5);
console.log('CCI Cycle:', Array.from(values));
Memory-Efficient Operations
import { cci_cycle_alloc, cci_cycle_free, cci_cycle_into, memory } from 'vectorta-wasm';

const data = new Float64Array(loadPrices());
const len = data.length;
const inPtr = cci_cycle_alloc(len);
const outPtr = cci_cycle_alloc(len);

new Float64Array(memory.buffer, inPtr, len).set(data);
// in_ptr, out_ptr, len, length, factor
cci_cycle_into(inPtr, outPtr, len, 10, 0.5);

const out = new Float64Array(memory.buffer, outPtr, len).slice();
cci_cycle_free(inPtr, len);
cci_cycle_free(outPtr, len);
Batch Processing
import { cci_cycle_batch } from 'vectorta-wasm';

const prices = new Float64Array(loadPrices());
const result = cci_cycle_batch(prices, {
  length_range: [10, 20, 5],
  factor_range: [0.3, 0.7, 0.2],
});

console.log(result.rows, result.cols, result.combos.length);

Performance Analysis

Comparison:
View:
Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05

Related Indicators