Williams Alligator
jaw_period = 13 | jaw_offset = 8 | teeth_period = 8 | teeth_offset = 5 | lips_period = 5 | lips_offset = 3 Overview
The Williams Alligator identifies trend phases using three smoothed moving averages that represent an alligator's jaw, teeth, and lips, each calculated from median price with Fibonacci based periods and shifted forward in time. Bill Williams designed this system to filter out ranging markets by observing when the three lines converge and diverge. The Jaw uses a 13 period SMMA of median price shifted 8 bars forward, the Teeth employs an 8 period SMMA shifted 5 bars, and the Lips applies a 5 period SMMA shifted 3 bars ahead. When these lines intertwine, the market lacks direction and the alligator sleeps. As price begins trending, the lines separate in order with the fastest Lips leading, followed by Teeth, then Jaw, signaling the alligator awakens to feed on the trend. Traders enter positions when all three lines spread apart and align directionally, then exit when lines begin crossing back together, indicating the trend exhausts and the alligator returns to sleep.
Implementation Examples
Get started with the Alligator indicator in just a few lines:
use vectorta::indicators::alligator::{alligator, AlligatorInput, AlligatorParams};
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 = AlligatorParams {
jaw_period: Some(13),
jaw_offset: Some(8),
teeth_period: Some(8),
teeth_offset: Some(5),
lips_period: Some(5),
lips_offset: Some(3),
};
let input = AlligatorInput::from_slice(&prices, params);
let result = alligator(&input)?;
// Using with Candles data structure
// Quick and simple with default parameters
let input = AlligatorInput::with_default_candles(&candles);
let result = alligator(&input)?;
// Access the three Alligator lines
println!("Jaw: {:?}", result.jaw);
println!("Teeth: {:?}", result.teeth);
println!("Lips: {:?}", result.lips); API Reference
Input Methods ▼
// From price slice
AlligatorInput::from_slice(&[f64], AlligatorParams) -> AlligatorInput
// From candles with custom source
AlligatorInput::from_candles(&Candles, &str, AlligatorParams) -> AlligatorInput
// From candles with default params (hl2 prices, 13/8/5 periods, 8/5/3 offsets)
AlligatorInput::with_default_candles(&Candles) -> AlligatorInput Parameters Structure ▼
pub struct AlligatorParams {
pub jaw_period: Option<usize>, // Default: 13
pub jaw_offset: Option<usize>, // Default: 8
pub teeth_period: Option<usize>, // Default: 8
pub teeth_offset: Option<usize>, // Default: 5
pub lips_period: Option<usize>, // Default: 5
pub lips_offset: Option<usize>, // Default: 3
} Output Structure ▼
pub struct AlligatorOutput {
pub jaw: Vec<f64>, // SMMA with longest period and offset (Blue line)
pub teeth: Vec<f64>, // SMMA with medium period and offset (Red line)
pub lips: Vec<f64>, // SMMA with shortest period and offset (Green line)
} Validation, Warmup & NaNs ▼
jaw_period,teeth_period,lips_periodmust be> 0and ≤ input length; otherwiseInvalid*Perioderrors.jaw_offset,teeth_offset,lips_offsetmust be ≤ input length; otherwiseInvalid*Offseterrors.- All inputs NaN →
AlligatorError::AllValuesNaN. - Warmup per line:
first + period − 1 + offsetwherefirstis the index of the first finite value. Indices before areNaN. - Seeding uses the average of the first
periodsamples; update uses(prev*(n−1)+x)/n. - Streaming returns
Noneuntil the largest period fills; offsets are not applied in streaming outputs.
Error Handling ▼
use vectorta::indicators::alligator::AlligatorError;
match alligator(&input) {
Ok(output) => {
process_alligator_lines(output.jaw, output.teeth, output.lips)
},
Err(AlligatorError::AllValuesNaN) =>
println!("All input data is NaN"),
Err(AlligatorError::InvalidJawPeriod { period, data_len }) =>
println!("Invalid jaw period {} for data length {}", period, data_len),
Err(AlligatorError::InvalidJawOffset { offset, data_len }) =>
println!("Invalid jaw offset {} for data length {}", offset, data_len),
Err(AlligatorError::InvalidTeethPeriod { period, data_len }) =>
println!("Invalid teeth period {} for data length {}", period, data_len),
Err(AlligatorError::InvalidTeethOffset { offset, data_len }) =>
println!("Invalid teeth offset {} for data length {}", offset, data_len),
Err(AlligatorError::InvalidLipsPeriod { period, data_len }) =>
println!("Invalid lips period {} for data length {}", period, data_len),
Err(AlligatorError::InvalidLipsOffset { offset, data_len }) =>
println!("Invalid lips offset {} for data length {}", offset, data_len),
Err(e) => println!("Alligator error: {}", e)
} Python Bindings
Basic Usage ▼
Calculate Alligator using NumPy arrays:
import numpy as np
from vectorta import alligator
# Prepare price data as NumPy array
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5])
# Calculate Alligator with default parameters (13/8/5 periods, 8/5/3 offsets)
jaw, teeth, lips = alligator(prices)
# Or specify custom parameters
jaw, teeth, lips = alligator(
prices,
jaw_period=13, jaw_offset=8,
teeth_period=8, teeth_offset=5,
lips_period=5, lips_offset=3
)
# Specify kernel for performance optimization
jaw, teeth, lips = alligator(
prices,
jaw_period=13, jaw_offset=8,
teeth_period=8, teeth_offset=5,
lips_period=5, lips_offset=3,
kernel="avx2"
)
# Results are NumPy arrays matching input length
print(f"Jaw values: {jaw}")
print(f"Teeth values: {teeth}")
print(f"Lips values: {lips}")
# Check for trend alignment
if lips[-1] > teeth[-1] > jaw[-1]:
print("Bullish alignment - uptrend")
elif lips[-1] < teeth[-1] < jaw[-1]:
print("Bearish alignment - downtrend")
else:
print("No clear trend - alligator sleeping") Streaming Real-time Updates ▼
Process real-time price updates efficiently:
from vectorta import AlligatorStream
# Initialize streaming Alligator calculator
stream = AlligatorStream(
jaw_period=13, jaw_offset=8,
teeth_period=8, teeth_offset=5,
lips_period=5, lips_offset=3
)
# Process real-time price updates
for price in price_feed:
result = stream.update(price)
if result is not None:
# Alligator values are ready (None during warmup period)
jaw, teeth, lips = result
print(f"Current Alligator: Jaw={jaw:.2f}, Teeth={teeth:.2f}, Lips={lips:.2f}")
# Make trading decisions based on Alligator alignment
if lips > teeth > jaw:
print("Alligator awakening - bullish trend forming")
# Consider long entry
elif lips < teeth < jaw:
print("Alligator awakening - bearish trend forming")
# Consider short entry
else:
# Lines intertwined
print("Alligator sleeping - no clear trend")
# Stay out of market or use range strategies Batch Parameter Optimization ▼
Test multiple parameter combinations for optimization:
import numpy as np
from vectorta import alligator_batch
# Your price data
prices = np.array([...]) # Your historical prices
# Define parameter ranges to test
# (start, end, step) for each parameter
jaw_period_range = (10, 20, 2) # Test: 10, 12, 14, 16, 18, 20
jaw_offset_range = (5, 10, 1) # Test: 5, 6, 7, 8, 9, 10
teeth_period_range = (5, 10, 1) # Test: 5, 6, 7, 8, 9, 10
teeth_offset_range = (3, 7, 1) # Test: 3, 4, 5, 6, 7
lips_period_range = (3, 8, 1) # Test: 3, 4, 5, 6, 7, 8
lips_offset_range = (2, 5, 1) # Test: 2, 3, 4, 5
# Run batch calculation
results = alligator_batch(
prices,
jaw_period_range=jaw_period_range,
jaw_offset_range=jaw_offset_range,
teeth_period_range=teeth_period_range,
teeth_offset_range=teeth_offset_range,
lips_period_range=lips_period_range,
lips_offset_range=lips_offset_range,
kernel="auto" # Auto-select best kernel
)
# Access results
print(f"Jaw values shape: {results['jaw'].shape}") # (num_combinations, len(prices))
print(f"Teeth values shape: {results['teeth'].shape}")
print(f"Lips values shape: {results['lips'].shape}")
print(f"Parameter combinations tested: {results['params']}")
# Find best performing parameters based on trend clarity
best_score = 0
best_params = None
for i, params in enumerate(results['params']):
jaw_line = results['jaw'][i]
teeth_line = results['teeth'][i]
lips_line = results['lips'][i]
# Calculate a score based on line separation (trend clarity)
separation = np.mean(np.abs(lips_line - jaw_line))
if separation > best_score:
best_score = separation
best_params = params
print(f"Best parameters: {best_params}") CUDA Acceleration ▼
CUDA support for Alligator is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.
# Coming soon: CUDA-accelerated Alligator calculations
#
# from vectorta import alligator_cuda_batch, alligator_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 = alligator_cuda_batch(
# data=prices, # Single price series
# jaw_period_range=(10, 20, 1),
# jaw_offset_range=(5, 10, 1),
# teeth_period_range=(5, 10, 1),
# teeth_offset_range=(3, 7, 1),
# lips_period_range=(3, 8, 1),
# lips_offset_range=(2, 5, 1),
# device_id=0
# )
# # Returns:
# # - results['jaw']: 2D array [num_combinations x len(prices)]
# # - results['teeth']: 2D array [num_combinations x len(prices)]
# # - results['lips']: 2D array [num_combinations x len(prices)]
# # - results['params']: list of parameter combinations tested
#
# # Option 2: Many Series, One Parameter Set (portfolio processing)
# # Process multiple stocks/assets with the same Alligator parameters
# portfolio_data = np.array([...]) # Shape: [time_steps, num_assets]
#
# jaw, teeth, lips = alligator_cuda_many_series_one_param(
# data_tm=portfolio_data, # Time-major format [T, N]
# jaw_period=13, jaw_offset=8,
# teeth_period=8, teeth_offset=5,
# lips_period=5, lips_offset=3,
# device_id=0
# )
# # Returns: Three 2D arrays [time_steps, num_assets] with Alligator lines for each asset
#
# # Zero-copy variant with pre-allocated output (F32 for GPU efficiency)
# jaw_out = np.empty((time_steps, num_assets), dtype=np.float32)
# teeth_out = np.empty((time_steps, num_assets), dtype=np.float32)
# lips_out = np.empty((time_steps, num_assets), dtype=np.float32)
# alligator_cuda_many_series_one_param_into(
# data_tm_f32=portfolio_data.astype(np.float32),
# jaw_period=13, jaw_offset=8,
# teeth_period=8, teeth_offset=5,
# lips_period=5, lips_offset=3,
# jaw_out=jaw_out,
# teeth_out=teeth_out,
# lips_out=lips_out,
# device_id=0
# ) JavaScript/WASM Bindings
Basic Usage ▼
Calculate Alligator in JavaScript/TypeScript:
import { alligator_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 Alligator with specified parameters
const result = alligator_js(
prices,
13, 8, // jaw_period, jaw_offset
8, 5, // teeth_period, teeth_offset
5, 3 // lips_period, lips_offset
);
// Result contains flattened array: [jaw_values, teeth_values, lips_values]
const len = prices.length;
const jaw = result.slice(0, len);
const teeth = result.slice(len, 2 * len);
const lips = result.slice(2 * len, 3 * len);
console.log('Jaw values:', jaw);
console.log('Teeth values:', teeth);
console.log('Lips values:', lips);
// TypeScript type definitions
interface AlligatorResult {
jaw: Float64Array;
teeth: Float64Array;
lips: Float64Array;
}
// Use with async/await for better error handling
async function calculateAlligator(prices: Float64Array): Promise<AlligatorResult> {
try {
const result = alligator_js(prices, 13, 8, 8, 5, 5, 3);
const len = prices.length;
return {
jaw: result.slice(0, len),
teeth: result.slice(len, 2 * len),
lips: result.slice(2 * len, 3 * len)
};
} catch (error) {
console.error('Alligator calculation failed:', error);
throw error;
}
} Memory-Efficient Operations ▼
Use zero-copy operations for better performance with large datasets:
import { alligator_alloc, alligator_free, alligator_into, memory } from 'vectorta-wasm';
// Prepare your price data
const prices = new Float64Array([/* your data */]);
const length = prices.length;
// Allocate WASM memory for output (3 arrays for jaw, teeth, lips)
const jawPtr = alligator_alloc(length);
const teethPtr = alligator_alloc(length);
const lipsPtr = alligator_alloc(length);
// Get input data pointer in WASM memory
const inputArray = new Float64Array(memory.buffer, /* offset */, length);
inputArray.set(prices);
// Calculate Alligator directly into allocated memory (zero-copy)
alligator_into(
inputArray.byteOffset, // Input pointer
jawPtr, // Jaw output pointer
teethPtr, // Teeth output pointer
lipsPtr, // Lips output pointer
length, // Data length
13, // jaw_period
8, // jaw_offset
8, // teeth_period
5, // teeth_offset
5, // lips_period
3 // lips_offset
);
// Read results from WASM memory
const jaw = new Float64Array(memory.buffer, jawPtr, length);
const teeth = new Float64Array(memory.buffer, teethPtr, length);
const lips = new Float64Array(memory.buffer, lipsPtr, length);
// Convert to regular arrays if needed
const jawValues = Array.from(jaw);
const teethValues = Array.from(teeth);
const lipsValues = Array.from(lips);
// Important: Free allocated memory when done
alligator_free(jawPtr, length);
alligator_free(teethPtr, length);
alligator_free(lipsPtr, length);
console.log('Alligator calculated successfully'); Batch Processing ▼
Test multiple parameter combinations efficiently:
import { alligator_batch_js, alligator_batch_metadata_js } from 'vectorta-wasm';
// Your price data
const prices = new Float64Array([/* historical prices */]);
// Define parameter sweep ranges
const jawPeriodRange = { start: 10, end: 20, step: 2 }; // 10, 12, 14, 16, 18, 20
const jawOffsetRange = { start: 5, end: 10, step: 1 }; // 5, 6, 7, 8, 9, 10
const teethPeriodRange = { start: 5, end: 10, step: 1 }; // 5, 6, 7, 8, 9, 10
const teethOffsetRange = { start: 3, end: 7, step: 1 }; // 3, 4, 5, 6, 7
const lipsPeriodRange = { start: 3, end: 8, step: 1 }; // 3, 4, 5, 6, 7, 8
const lipsOffsetRange = { start: 2, end: 5, step: 1 }; // 2, 3, 4, 5
// Get metadata about parameter combinations
const metadata = alligator_batch_metadata_js(
jawPeriodRange.start, jawPeriodRange.end, jawPeriodRange.step,
jawOffsetRange.start, jawOffsetRange.end, jawOffsetRange.step,
teethPeriodRange.start, teethPeriodRange.end, teethPeriodRange.step,
teethOffsetRange.start, teethOffsetRange.end, teethOffsetRange.step,
lipsPeriodRange.start, lipsPeriodRange.end, lipsPeriodRange.step,
lipsOffsetRange.start, lipsOffsetRange.end, lipsOffsetRange.step
);
// metadata contains parameter values for each combination
// [jaw_period1, jaw_offset1, teeth_period1, teeth_offset1, lips_period1, lips_offset1,
// jaw_period2, jaw_offset2, teeth_period2, teeth_offset2, lips_period2, lips_offset2, ...]
const numCombos = metadata.length / 6;
// Calculate all combinations
const results = alligator_batch_js(
prices,
jawPeriodRange.start, jawPeriodRange.end, jawPeriodRange.step,
jawOffsetRange.start, jawOffsetRange.end, jawOffsetRange.step,
teethPeriodRange.start, teethPeriodRange.end, teethPeriodRange.step,
teethOffsetRange.start, teethOffsetRange.end, teethOffsetRange.step,
lipsPeriodRange.start, lipsPeriodRange.end, lipsPeriodRange.step,
lipsOffsetRange.start, lipsOffsetRange.end, lipsOffsetRange.step
);
// Results is a flat array: [combo1_jaw, combo1_teeth, combo1_lips, combo2_jaw, ...]
// Reshape based on your needs
const resultMatrix = [];
for (let i = 0; i < numCombos; i++) {
const offset = i * prices.length * 3;
resultMatrix.push({
params: {
jaw_period: metadata[i * 6],
jaw_offset: metadata[i * 6 + 1],
teeth_period: metadata[i * 6 + 2],
teeth_offset: metadata[i * 6 + 3],
lips_period: metadata[i * 6 + 4],
lips_offset: metadata[i * 6 + 5]
},
jaw: results.slice(offset, offset + prices.length),
teeth: results.slice(offset + prices.length, offset + 2 * prices.length),
lips: results.slice(offset + 2 * prices.length, offset + 3 * prices.length)
});
}
// Find best parameters based on trend clarity
let bestScore = 0;
let bestParams = null;
resultMatrix.forEach(({ params, jaw, teeth, lips }) => {
// Calculate average line separation as a metric
let separation = 0;
for (let i = 0; i < prices.length; i++) {
separation += Math.abs(lips[i] - jaw[i]);
}
separation /= prices.length;
if (separation > bestScore) {
bestScore = separation;
bestParams = params;
}
});
console.log('Best parameters:', bestParams); Performance Analysis
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05
Related Indicators
Average Directional Index
Technical analysis indicator
Average Directional Movement Index Rating
Technical analysis indicator
Aroon
Technical analysis indicator
Aroon Oscillator
Technical analysis indicator
Chande Momentum Oscillator
Technical analysis indicator
Directional Indicator (+DI/-DI)
Technical analysis indicator