Mesa Sine Wave (MSW)
period = 5 Overview
The Mesa Sine Wave indicator transforms price data into two oscillating waves that reveal hidden market cycles by projecting price movements onto sine and cosine components, creating a bounded oscillator that swings smoothly between -1 and 1. The primary sine wave captures the dominant cycle in price action, while the companion lead wave advances 45 degrees ahead in phase, providing early warning of potential turning points before they occur in the main oscillator. When the lead wave crosses above the sine wave near cycle lows, it signals an impending upturn, whereas crosses below near peaks warn of coming declines. This indicator excels in ranging markets where prices exhibit regular cyclical behavior, helping traders time entries and exits at cycle extremes rather than chasing moves after they've begun. Unlike traditional oscillators that simply measure momentum, MSW actively extracts the periodic component from price data, making it particularly valuable for identifying the rhythm and frequency of market swings.
Implementation Examples
Compute MSW in a few lines:
use vectorta::indicators::msw::{msw, MswInput, MswParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// From a price slice (default: period=5)
let prices = vec![100.0, 101.0, 102.0, 101.5, 103.0, 104.0];
let input = MswInput::from_slice(&prices, MswParams { period: Some(5) });
let out = msw(&input)?; // out.sine, out.lead
// From Candles with default params (source="close", period=5)
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = MswInput::with_default_candles(&candles);
let out = msw(&input)?;
// Access the values
for (s, l) in out.sine.iter().zip(out.lead.iter()) {
println!("sine={}, lead={}", s, l);
} API Reference
Input Methods ▼
// From price slice
MswInput::from_slice(&[f64], MswParams) -> MswInput
// From candles with custom source
MswInput::from_candles(&Candles, &str, MswParams) -> MswInput
// With defaults from candles (source = "close", period=5)
MswInput::with_default_candles(&Candles) -> MswInput Parameters Structure ▼
pub struct MswParams {
pub period: Option<usize>, // Default: 5
} Output Structure ▼
pub struct MswOutput {
pub sine: Vec<f64>, // bounded in [-1, 1]; NaN during warmup
pub lead: Vec<f64>, // phase-advanced by 45°; NaN during warmup
} Validation, Warmup & NaNs ▼
period > 0; otherwiseMswError::InvalidPeriod.period ≤ data.len(); otherwiseMswError::InvalidPeriod.- There must be at least
periodvalid points after the first finite value; elseMswError::NotEnoughValidData. - If all inputs are
NaN, returnsMswError::AllValuesNaN. - Warmup: outputs are
NaNuntil indexfirst + period − 1(first defined values).
Error Handling ▼
use vectorta::indicators::msw::{msw, MswError};
match msw(&input) {
Ok(out) => process(out.sine, out.lead),
Err(MswError::EmptyData) => eprintln!("Input data is empty"),
Err(MswError::InvalidPeriod { period, data_len }) =>
eprintln!("Invalid period {} for length {}", period, data_len),
Err(MswError::NotEnoughValidData { needed, valid }) =>
eprintln!("Need {} valid points, only {} found", needed, valid),
Err(MswError::AllValuesNaN) => eprintln!("All input values are NaN"),
} Python Bindings
Basic Usage ▼
Calculate MSW using NumPy arrays (default: period=5):
import numpy as np
from vectorta import msw
prices = np.array([100.0, 101.0, 102.0, 101.5, 103.0, 104.0], dtype=float)
# Returns two arrays: (sine, lead)
sine, lead = msw(prices, period=5)
print(sine.shape, lead.shape) Streaming Real-time Updates ▼
Process ticks incrementally with the streaming API:
from vectorta import MswStream
stream = MswStream(period=5)
for price in price_feed:
res = stream.update(price)
if res is not None:
sine, lead = res
handle_cycle(sine, lead) Batch Parameter Optimization ▼
Sweep period values efficiently:
import numpy as np
from vectorta import msw_batch
prices = np.array([...], dtype=float)
res = msw_batch(prices, period_range=(5, 30, 5), kernel="auto")
print(res["sine"].shape, res["lead"].shape) # (num_periods, len(prices))
print(res["periods"]) # tested periods CUDA Acceleration ▼
CUDA support for MSW is coming soon. The API will mirror other CUDA-enabled indicators.
JavaScript/WASM Bindings
Basic Usage ▼
Calculate MSW in JavaScript/TypeScript:
import { msw_js } from 'vectorta-wasm';
const prices = new Float64Array([100, 101, 102, 101.5, 103, 104]);
// Returns object { values: Float64Array(2*n), rows: 2, cols: n }
const res = msw_js(prices, 5);
const { values, rows, cols } = res;
// First row is sine, second row is lead
const sine = values.slice(0, cols);
const lead = values.slice(cols, 2 * cols);
console.log('MSW sine:', sine);
console.log('MSW lead:', lead); Memory‑Efficient Operations ▼
Use zero‑copy helpers for large arrays:
import { msw_alloc, msw_free, msw_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* your data */]);
const n = prices.length;
// Allocate WASM memory
const inPtr = msw_alloc(n);
const sinePtr = msw_alloc(n);
const leadPtr = msw_alloc(n);
// Copy input into WASM memory
new Float64Array(memory.buffer, inPtr, n).set(prices);
// Compute directly into output buffers: (in_ptr, sine_ptr, lead_ptr, len, period)
msw_into(inPtr, sinePtr, leadPtr, n, 5);
// Read results (slice to copy out)
const sine = new Float64Array(memory.buffer, sinePtr, n).slice();
const lead = new Float64Array(memory.buffer, leadPtr, n).slice();
// Free WASM buffers
msw_free(inPtr, n);
msw_free(sinePtr, n);
msw_free(leadPtr, n); Batch Processing ▼
Sweep periods efficiently with a config or explicit ranges:
import { msw_batch, msw_batch_js, msw_batch_metadata_js } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
// Config object API
const config = { period_range: [5, 30, 5] };
const flat = msw_batch(prices, config); // { values, rows: 2*combos, cols }
// Explicit ranges API
const meta = msw_batch_metadata_js(5, 30, 5); // periods tested
const structured = msw_batch_js(prices, 5, 30, 5); // { sine, lead, combos, rows, cols } Performance Analysis
Across sizes, Rust CPU runs about 5.11× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05