Absolute Price Oscillator (APO)
short_period = 10 • long_period = 20 Overview
The Absolute Price Oscillator (APO) measures momentum by calculating the difference between two exponential moving averages of different periods. The indicator outputs the raw price difference, providing a clear view of momentum strength in the security's native price units.
APO excels at identifying momentum shifts and trend strength by comparing fast and slow moving averages. The absolute difference approach makes it ideal for analyzing a single security's behavior over time, particularly when you need to understand momentum magnitude in actual price terms.
Formula: APOt = EMAshort(t) − EMAlong(t), with α = 2/(n+1). APO is in price units;
PPO normalizes by the slow EMA: PPO = 100 × (Fast − Slow) / Slow. Defaults (VectorTA): short=10, long=20. Typical elsewhere: 12/26.
See also
- Percentage Price Oscillator (PPO) — percent-normalized variant.
- MACD — APO line + signal + histogram.
Interpretation & Use
- Zero-line: APO above 0 suggests bullish momentum; below 0 suggests bearish momentum.
- Momentum shifts: Rising APO indicates strengthening upside momentum; falling APO indicates weakening or negative momentum.
- Crossovers: Zero-line crosses are a simple trend filter; add a signal line with
EMA(APO, 9)if desired. - Relation to MACD: APO is effectively the MACD line (FastEMA − SlowEMA). Signal = EMA(APO, 9), histogram = APO − signal.
- APO vs PPO: APO is in price units; PPO normalizes by the slow EMA (%). Prefer PPO for cross‑asset comparisons.
Implementation Examples
Get started with APO in just a few lines:
use vectorta::indicators::apo::{apo, ApoInput, ApoParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using with price data slice
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let params = ApoParams {
short_period: Some(10),
long_period: Some(20),
};
let input = ApoInput::from_slice(&prices, params);
let result = apo(&input)?;
// Using with Candles data structure
// Quick and simple with default parameters (short=10, long=20; source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = ApoInput::with_default_candles(&candles);
let result = apo(&input)?;
// Access the APO values
for value in result.values {
println!("APO: {}", value);
} API Reference
Input Methods ▼
// From price slice
ApoInput::from_slice(&[f64], ApoParams) -> ApoInput
// From candles with custom source
ApoInput::from_candles(&Candles, &str, ApoParams) -> ApoInput
// From candles with default params (close prices, 10/20 periods)
ApoInput::with_default_candles(&Candles) -> ApoInput Parameters Structure ▼
pub struct ApoParams {
pub short_period: Option<usize>, // Default: 10
pub long_period: Option<usize>, // Default: 20
} Output Structure ▼
pub struct ApoOutput {
pub values: Vec<f64>, // APO values (short_ema - long_ema)
} Validation, Warmup & NaNs ▼
short_period > 0,long_period > 0, andshort_period < long_period.- There must be at least
long_periodvalid points after the first finite value; otherwiseApoError::NotEnoughValidData. - Indices before the first finite input are
NaN. The first finite output is0.0(both EMAs seeded to that price). - Streaming: leading
NaNs delay the first value; subsequentNaNs propagate.
Error Handling ▼
use vectorta::indicators::apo::ApoError;
match apo(&input) {
Ok(output) => process_results(output.values),
Err(ApoError::EmptyInputData) =>
println!("Input data is empty"),
Err(ApoError::ShortPeriodNotLessThanLong { short, long }) =>
println!("Short period {} must be < long period {}", short, long),
Err(ApoError::NotEnoughValidData { needed, valid }) =>
println!("Need {} data points, only {} valid", needed, valid),
Err(e) => println!("APO error: {}", e)
} Python Bindings
Basic Usage ▼
Calculate APO using NumPy arrays (defaults: short=10, long=20):
import numpy as np
from vectorta import apo
# Prepare price data as NumPy array
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5])
# Calculate APO with defaults (10/20)
result = apo(prices)
# Or specify custom parameters
result = apo(prices, short_period=10, long_period=20)
# Specify kernel for performance optimization
result = apo(prices, short_period=10, long_period=20, kernel="avx2")
# Result is a NumPy array matching input length
print(f"APO values: {result}") Streaming Real-time Updates ▼
Process real-time price updates efficiently:
from vectorta import ApoStream
# Initialize streaming APO calculator
stream = ApoStream(short_period=10, long_period=20)
# Process real-time price updates
for price in price_feed:
apo_value = stream.update(price)
if apo_value is not None:
# APO value is ready (None during warmup period)
print(f"Current APO: {apo_value}")
# Make trading decisions based on APO
if apo_value > 0:
print("Momentum is positive")
else:
print("Momentum is negative") Batch Parameter Optimization ▼
Test multiple parameter combinations for optimization:
import numpy as np
from vectorta import apo_batch
# Your price data
prices = np.array([...]) # Your historical prices
# Define parameter ranges to test
# (start, end, step) for each parameter
short_range = (5, 20, 5) # Test: 5, 10, 15, 20
long_range = (15, 50, 5) # Test: 15, 20, 25, ..., 50
# Run batch calculation
results = apo_batch(
prices,
short_period_range=short_range,
long_period_range=long_range,
kernel="auto" # Auto-select best kernel
)
# Access results
print(f"Values shape: {results['values'].shape}") # (num_combinations, len(prices))
print(f"Short periods tested: {results['short_periods']}")
print(f"Long periods tested: {results['long_periods']}")
# Find best performing parameters
best_idx = np.argmax(some_performance_metric(results['values']))
best_short = results['short_periods'][best_idx]
best_long = results['long_periods'][best_idx] CUDA Acceleration ▼
CUDA support for APO is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.
# Coming soon: CUDA-accelerated APO calculations
#
# from vectorta import apo_cuda_batch, apo_cuda_many_series_one_param
# import numpy as np
#
# # Option 1: One Series, Many Parameters (parameter optimization)
# # Test multiple parameter combinations on a single price series
# results = apo_cuda_batch(
# data=prices, # Single price series
# short_period_range=(5, 20, 1), # Test all shorts from 5 to 20
# long_period_range=(15, 50, 1), # Test all longs from 15 to 50
# device_id=0
# )
# # Returns:
# # - results['values']: 2D array [num_combinations x len(prices)]
# # - results['short_periods']: array of short periods tested
# # - results['long_periods']: array of long periods tested
#
# # Option 2: Many Series, One Parameter Set (portfolio processing)
# # Process multiple stocks/assets with the same APO parameters
# portfolio_data = np.array([...]) # Shape: [time_steps, num_assets]
#
# results = apo_cuda_many_series_one_param(
# data_tm=portfolio_data, # Time-major format [T, N]
# short_period=12,
# long_period=26,
# device_id=0
# )
# # Returns: 2D array [time_steps, num_assets] with APO for each asset
#
# # Zero-copy variant with pre-allocated output (F32 for GPU efficiency)
# out = np.empty((time_steps, num_assets), dtype=np.float32)
# apo_cuda_many_series_one_param_into(
# data_tm_f32=portfolio_data.astype(np.float32),
# short_period=12,
# long_period=26,
# out=out,
# device_id=0
# ) JavaScript/WASM Bindings
Basic Usage ▼
Calculate APO in JavaScript/TypeScript:
import { apo_js } from 'vectorta-wasm';
// Price data as Float64Array or regular array
const prices = new Float64Array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5]);
// Calculate APO with specified parameters
const result = apo_js(prices, 10, 20); // short=10, long=20
// Result is a Float64Array
console.log('APO values:', result);
// TypeScript type definitions
interface ApoResult {
values: Float64Array;
}
// Use with async/await for better error handling
async function calculateAPO(prices: Float64Array): Promise<Float64Array> {
try {
return apo_js(prices, 10, 20);
} catch (error) {
console.error('APO calculation failed:', error);
throw error;
}
} Memory-Efficient Operations ▼
Use zero-copy operations for better performance with large datasets:
import { apo_alloc, apo_free, apo_into, memory } from 'vectorta-wasm';
// Prepare your price data
const prices = new Float64Array([/* your data */]);
const length = prices.length;
// Allocate WASM memory for input and output
const inPtr = apo_alloc(length);
const outPtr = apo_alloc(length);
// Copy input data into WASM memory
new Float64Array(memory.buffer, inPtr, length).set(prices);
// Calculate APO directly into allocated memory
// Args: in_ptr, out_ptr, len, short_period, long_period
apo_into(inPtr, outPtr, length, 10, 20);
// Read results from WASM memory (slice() to copy out)
const apoValues = new Float64Array(memory.buffer, outPtr, length).slice();
// Free allocated memory when done
apo_free(inPtr, length);
apo_free(outPtr, length);
console.log('APO values:', apoValues); Batch Processing ▼
Test multiple parameter combinations efficiently:
import { apo_batch_js, apo_batch_metadata_js } from 'vectorta-wasm';
// Your price data
const prices = new Float64Array([/* historical prices */]);
// Define parameter sweep ranges
const shortStart = 5, shortEnd = 20, shortStep = 5; // 5, 10, 15, 20
const longStart = 15, longEnd = 50, longStep = 5; // 15, 20, 25...50
// Get metadata about parameter combinations
const metadata = apo_batch_metadata_js(
shortStart, shortEnd, shortStep,
longStart, longEnd, longStep
);
// metadata contains [short1, long1, short2, long2, ...]
const numCombos = metadata.length / 2;
// Calculate all combinations
const results = apo_batch_js(
prices,
shortStart, shortEnd, shortStep,
longStart, longEnd, longStep
);
// Results is a flat array: [combo1_values..., combo2_values..., ...]
// Reshape based on your needs
const resultMatrix = [];
for (let i = 0; i < numCombos; i++) {
const start = i * prices.length;
const end = start + prices.length;
resultMatrix.push(results.slice(start, end));
}
// Access specific parameter combination results
const shortPeriod = metadata[0]; // First combo's short period
const longPeriod = metadata[1]; // First combo's long period
const apoValues = resultMatrix[0]; // First combo's APO values Performance Analysis
Related Indicators
Acceleration Oscillator
Technical analysis indicator
Awesome Oscillator
Technical analysis indicator
Commodity Channel Index
Technical analysis indicator
Center of Gravity
Technical analysis indicator
Chande Momentum Oscillator
Technical analysis indicator
Chande Momentum Oscillator
Technical analysis indicator