Accelerator Oscillator (ACOSC)
Overview
The Accelerator Oscillator (ACOSC) measures the acceleration and deceleration of the driving force behind price movements. ACOSC calculates the difference between the Awesome Oscillator (a 5 period minus 34 period SMA of median price) and its own 5 period moving average. The zero line represents where the driving force is at balance with acceleration. Above zero, it becomes easier for acceleration to continue increasing, while below zero indicates deceleration. According to Bill Williams, the indicator changes direction before the driving force changes, which itself changes before price, making AC an early warning system. The indicator provides both oscillator values and their bar to bar changes, helping traders identify momentum shifts before major reversals occur.
Defaults: ACOSC uses fixed internal periods (no user parameters).
Implementation Examples
Get started with ACOSC in just a few lines:
use vectorta::indicators::acosc::{acosc, AcoscInput, AcoscParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using with high/low price slices
let high = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let low = vec![99.0, 98.0, 99.5, 100.0, 102.0, 103.0];
let params = AcoscParams::default(); // No configurable parameters
let input = AcoscInput::from_slices(&high, &low, params);
let result = acosc(&input)?;
// Using with Candles data structure
// Quick and simple with default parameters (source = high/low)
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = AcoscInput::with_default_candles(&candles);
let result = acosc(&input)?;
// Access the oscillator and change values
for (osc, change) in result.osc.iter().zip(result.change.iter()) {
println!("AC: {}, Change: {}", osc, change);
} API Reference
Input Methods ▼
// From high/low slices
AcoscInput::from_slices(&[f64], &[f64], AcoscParams) -> AcoscInput
// From candles
AcoscInput::from_candles(&Candles, AcoscParams) -> AcoscInput
// From candles with default params
AcoscInput::with_default_candles(&Candles) -> AcoscInput Parameters Structure ▼
pub struct AcoscParams {} // Empty - ACOSC uses fixed parameters
// Fixed internal parameters:
// - Fast SMA period: 5
// - Slow SMA period: 34
// - Signal smoothing period: 5 Output Structure ▼
pub struct AcoscOutput {
pub osc: Vec<f64>, // AC oscillator values
pub change: Vec<f64>, // Momentum change between consecutive AC values
} Validation, Warmup & NaNs ▼
high.len() == low.len(); otherwiseAcoscError::LengthMismatch.- Find first index where both
high[i]andlow[i]are finite; require at least39valid points after that orAcoscError::NotEnoughData. - Warmup: indices before
first + 38are set toNaNin bothoscandchange. - Candles: failure to select
high/lowyieldsAcoscError::CandleFieldError. - Batch kernel validation: passing a non-batch kernel to
acosc_batch_with_kernelreturnsAcoscError::InvalidBatchKernel.
Error Handling ▼
use vectorta::indicators::acosc::AcoscError;
match acosc(&input) {
Ok(output) => {
process_results(output.osc, output.change);
},
Err(AcoscError::CandleFieldError { msg }) =>
eprintln!("Failed to get high/low from candles: {}", msg),
Err(AcoscError::LengthMismatch { high_len, low_len }) =>
eprintln!("High/low length mismatch: {} vs {}", high_len, low_len),
Err(AcoscError::NotEnoughData { required, actual }) =>
eprintln!("Need {} data points, only {} available", required, actual),
Err(AcoscError::InvalidBatchKernel { kernel }) =>
eprintln!("Invalid batch kernel: {:?}", kernel),
Err(e) => eprintln!("ACOSC error: {}", e),
} Python Bindings
Basic Usage ▼
Calculate ACOSC using NumPy arrays:
import numpy as np
from vectorta import acosc
high = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5])
low = np.array([99.0, 98.0, 99.5, 100.0, 102.0, 103.0])
# Calculate ACOSC (fixed parameters: 5/34 for AO, 5 for signal)
osc, change = acosc(high, low)
# Specify kernel for performance optimization
osc, change = acosc(high, low, kernel="avx2")
print("AC Oscillator:", osc)
print("Momentum Change:", change)
# The change array represents momentum between consecutive AC values
positive_momentum = change > 0
print("Periods with increasing momentum:", int(np.sum(positive_momentum))) Streaming Real-time Updates ▼
Process real-time price updates efficiently:
from vectorta import AcoscStream
stream = AcoscStream()
for high, low in price_feed:
result = stream.update(high, low)
if result is not None:
osc_value, change_value = result
print(f"Current AC: {osc_value}, Change: {change_value}") Batch Processing ▼
Batch API returns a single row (no parameter grid):
import numpy as np
from vectorta import acosc_batch
high = np.array([...], dtype=np.float64)
low = np.array([...], dtype=np.float64)
result = acosc_batch(high, low, kernel="auto")
osc = result["osc"][0]
change = result["change"][0]
print(osc.shape, change.shape) CUDA Acceleration ▼
CUDA support for ACOSC is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.
# Coming soon: CUDA-accelerated ACOSC calculations
# from vectorta import acosc_cuda_batch
# results = acosc_cuda_batch(high, low, device_id=0) JavaScript/WASM Bindings
Basic Usage ▼
Calculate ACOSC in JavaScript/TypeScript:
import { acosc_js } from 'vectorta-wasm';
// High/low price data as Float64Array or regular array
const high = new Float64Array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5]);
const low = new Float64Array([99.0, 98.0, 99.5, 100.0, 102.0, 103.0]);
// Calculate ACOSC (fixed parameters)
const result = acosc_js(high, low);
// Result is a flattened Float64Array [osc_values..., change_values...]
const len = high.length;
const osc = result.slice(0, len);
const change = result.slice(len);
console.log('AC Oscillator:', osc);
console.log('Momentum Change:', change);
interface AcoscResult { osc: Float64Array; change: Float64Array; }
const parseAcoscResult = (buf: Float64Array, length: number): AcoscResult => ({
osc: buf.slice(0, length),
change: buf.slice(length)
}); Memory-Efficient Operations ▼
Use zero-copy operations for better performance with large datasets:
import { acosc_alloc, acosc_free, acosc_into, memory } from 'vectorta-wasm';
// Prepare your high/low data
const high = new Float64Array([/* your data */]);
const low = new Float64Array([/* your data */]);
const length = high.length;
// Allocate WASM memory for inputs and outputs
const highPtr = acosc_alloc(length);
const lowPtr = acosc_alloc(length);
const oscPtr = acosc_alloc(length);
const changePtr = acosc_alloc(length);
// Copy inputs into WASM memory
new Float64Array(memory.buffer, highPtr, length).set(high);
new Float64Array(memory.buffer, lowPtr, length).set(low);
// Calculate ACOSC directly into allocated memory (zero-copy)
acosc_into(highPtr, lowPtr, oscPtr, changePtr, length);
// Read results and copy out
const oscValues = new Float64Array(memory.buffer, oscPtr, length).slice();
const changeValues = new Float64Array(memory.buffer, changePtr, length).slice();
// Free allocated memory when done
acosc_free(highPtr, length);
acosc_free(lowPtr, length);
acosc_free(oscPtr, length);
acosc_free(changePtr, length);
console.log('AC Oscillator:', oscValues);
console.log('Momentum Change:', changeValues); Batch Processing ▼
Unified batch call (single row since no parameters):
import { acosc_batch, acosc_batch_metadata_js } from 'vectorta-wasm';
const high = new Float64Array([/* historical highs */]);
const low = new Float64Array([/* historical lows */]);
// Metadata is empty for ACOSC (no parameter grid)
const metadata = acosc_batch_metadata_js();
console.log('Metadata length:', metadata.length); // 0
// Run batch
const config = {};
const result = acosc_batch(high, low, config);
// Result object: { values: Float64Array, rows: number (1), cols: number }
type AcoscBatchResult = { values: Float64Array; rows: number; cols: number };
const out = result as AcoscBatchResult;
const { rows, cols, values } = out;
console.log('Result dimensions: ' + rows + 'x' + cols);
const osc = values.slice(0, cols);
const change = values.slice(cols);
// ... use osc/change ... Performance Analysis
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05