Skip to main content

Python Integration Guide

Leverage the speed of Rust with the flexibility of Python. VectorAlpha's Python bindings provide native performance for your quantitative finance workflows while maintaining the familiar Python API.

Performance First

Our Python bindings use PyO3 for zero-overhead integration. You get the full performance of Rust's SIMD-optimized calculations with Python's ease of use.

Learn more: PyO3 Documentation

Installation

Using pip (Recommended)

# Install from PyPI
pip install vectoralpha-ta

# For GPU acceleration support
pip install vectoralpha-ta[cuda]

# For development features
pip install vectoralpha-ta[dev]

Building from Source

For latest features or custom builds, compile from source using maturin:

Learn more: Maturin Documentation

# Clone the repository
git clone https://github.com/VectorAlpha/ta-library.git
cd ta-library/python

# Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venvScriptsactivate

# Install maturin
pip install maturin

# Build and install in development mode
maturin develop --release

# Or build wheel for distribution
maturin build --release

Quick Start

Basic Usage

import vectoralpha as va
import numpy as np
import pandas as pd

# Generate sample data
dates = pd.date_range('2023-01-01', periods=1000, freq='1h')
prices = 100 + np.cumsum(np.random.randn(1000) * 0.5)
df = pd.DataFrame({'close': prices}, index=dates)

# Calculate indicators
sma_20 = va.indicators.sma(df['close'], period=20)  # &lt;span class="tooltip" data-tooltip="Simple Moving Average - average of last N periods"&gt;SMA</span&gt;
rsi_14 = va.indicators.rsi(df['close'], period=14)  # &lt;span class="tooltip" data-tooltip="Relative Strength Index - momentum oscillator measuring speed and magnitude of price changes"&gt;RSI</span&gt;
bb_upper, bb_middle, bb_lower = va.indicators.bollinger_bands(
    df['close'], period=20, std_dev=2
)  # &lt;span class="tooltip" data-tooltip="Volatility bands placed above and below a moving average"&gt;Bollinger Bands</span&gt;

# Add to DataFrame
df['SMA_20'] = sma_20
df['RSI_14'] = rsi_14
df['BB_Upper'] = bb_upper
df['BB_Lower'] = bb_lower

print(df.tail())

Working with NumPy Arrays

# VectorAlpha works seamlessly with NumPy arrays
prices_array = np.random.randn(10000).cumsum() + 100

# All indicators accept NumPy arrays
ema = va.indicators.ema(prices_array, period=12)
macd, signal, histogram = va.indicators.macd(
    prices_array, 
    fast_period=12, 
    slow_period=26, 
    signal_period=9
)  # &lt;span class="tooltip" data-tooltip="Moving Average Convergence Divergence - trend following momentum indicator"&gt;MACD</span&gt;

# Batch calculation for multiple indicators
indicators = va.batch_calculate({
    'sma_10': ('sma', {'period': 10}),
    'sma_20': ('sma', {'period': 20}),
    'rsi_14': ('rsi', {'period': 14}),
    'atr_14': ('atr', {'period': 14})  # &lt;span class="tooltip" data-tooltip="Average True Range - volatility indicator"&gt;ATR</span&gt;
}, prices_array)

for name, values in indicators.items():
    print(f"{name}: {values[-5:]}")

Advanced Features

Streaming Calculations

Process real-time data efficiently with streaming indicators:

# Create streaming indicator instance
sma_stream = va.streaming.SMA(period=20)
rsi_stream = va.streaming.RSI(period=14)

# Simulate real-time data
for price in real_time_price_feed():
    sma_value = sma_stream.update(price)
    rsi_value = rsi_stream.update(price)
    
    if rsi_value &lt; 30 and price &lt; sma_value:
        print(f"Buy signal: RSI={rsi_value:.2f}, Price below SMA")
    
    # Get current state without updating
    current_sma = sma_stream.current()
    
    # Reset if needed
    if some_condition:
        sma_stream.reset()

GPU Acceleration

Enable GPU acceleration for massive datasets:

# Check GPU availability
if va.cuda.is_available():
    print(f"CUDA available: {va.cuda.device_name()}")
    
    # Enable GPU acceleration globally
    va.set_backend('cuda')
    
    # Process large dataset on GPU
    large_prices = np.random.randn(10_000_000).cumsum() + 100
    
    # These calculations run on GPU
    with va.cuda.stream():
        sma = va.indicators.sma(large_prices, period=50)
        ema = va.indicators.ema(large_prices, period=50)
        rsi = va.indicators.rsi(large_prices, period=14)
    
    # Benchmark CPU vs GPU
    import time
    
    # CPU timing
    va.set_backend('cpu')
    start = time.time()
    cpu_result = va.indicators.sma(large_prices, period=50)
    cpu_time = time.time() - start
    
    # GPU timing
    va.set_backend('cuda')
    start = time.time()
    gpu_result = va.indicators.sma(large_prices, period=50)
    gpu_time = time.time() - start
    
    print(f"CPU time: {cpu_time:.3f}s")
    print(f"GPU time: {gpu_time:.3f}s")
    print(f"Speedup: {cpu_time/gpu_time:.1f}x")

Custom Indicators

Create custom indicators by combining existing ones or writing Rust extensions:

# Python-based custom indicator
def custom_momentum_indicator(prices, short_period=10, long_period=30):
    """
    Custom momentum indicator combining multiple signals
    """
    # Use VectorAlpha's optimized calculations
    sma_short = va.indicators.sma(prices, short_period)
    sma_long = va.indicators.sma(prices, long_period)
    rsi = va.indicators.rsi(prices, 14)
    
    # Calculate momentum score
    momentum = np.zeros_like(prices)
    momentum[long_period:] = (
        (sma_short[long_period:] - sma_long[long_period:]) / sma_long[long_period:] * 100
    )
    
    # Adjust by RSI
    momentum *= (rsi / 50)  # Scale by RSI strength
    
    return momentum

# For maximum performance, implement in Rust
# See our Rust extension guide for details

Integration Examples

Pandas Integration

# Efficient pandas integration
def add_technical_indicators(df):
    """Add multiple technical indicators to a DataFrame"""
    
    # Use vectorized operations
    high = df['high'].values
    low = df['low'].values
    close = df['close'].values
    volume = df['volume'].values
    
    # Calculate all indicators
    indicators = va.calculate_all({
        'high': high,
        'low': low,
        'close': close,
        'volume': volume
    }, indicators=[
        'sma_20',
        'ema_12',
        'rsi_14',
        'macd',
        'bollinger_bands',
        'atr_14',
        'obv',  # &lt;span class="tooltip" data-tooltip="On-Balance Volume - momentum indicator using volume flow"&gt;OBV</span&gt;
        'vwap'  # &lt;span class="tooltip" data-tooltip="Volume Weighted Average Price - average price weighted by volume"&gt;VWAP</span&gt;
    ])
    
    # Add to DataFrame
    for name, values in indicators.items():
        if isinstance(values, tuple):  # Handle multi-output indicators
            for i, sub_name in enumerate(['_upper', '_middle', '_lower']):
                df[f'{name}{sub_name}'] = values[i]
        else:
            df[name] = values
    
    return df

# Apply to your data
df = pd.read_csv('historical_data.csv', parse_dates=['timestamp'])
df = add_technical_indicators(df)

Real-time Strategy

class MomentumStrategy:
    def __init__(self, symbol):
        self.symbol = symbol
        self.sma_fast = va.streaming.SMA(10)
        self.sma_slow = va.streaming.SMA(30)
        self.rsi = va.streaming.RSI(14)
        self.position = 0
        
    def on_tick(self, price, volume):
        # Update indicators
        fast_ma = self.sma_fast.update(price)
        slow_ma = self.sma_slow.update(price)
        rsi_value = self.rsi.update(price)
        
        # Skip if not enough data
        if slow_ma is None:
            return
        
        # Generate signals
        if self.position == 0:  # No position
            if fast_ma &gt; slow_ma and rsi_value &gt; 50:
                self.buy(price)
            elif fast_ma &lt; slow_ma and rsi_value &lt; 50:
                self.sell(price)
        elif self.position &gt; 0:  # Long position
            if fast_ma &lt; slow_ma or rsi_value &gt; 70:
                self.close_position(price)
        else:  # Short position
            if fast_ma &gt; slow_ma or rsi_value &lt; 30:
                self.close_position(price)
    
    def buy(self, price):
        print(f"BUY {self.symbol} at {price}")
        self.position = 1
        
    def sell(self, price):
        print(f"SELL {self.symbol} at {price}")
        self.position = -1
        
    def close_position(self, price):
        action = "CLOSE LONG" if self.position &gt; 0 else "CLOSE SHORT"
        print(f"{action} {self.symbol} at {price}")
        self.position = 0

Performance Tips

Best Practices for Maximum Performance

  • Use NumPy arrays: Pass NumPy arrays instead of lists for 10x faster processing
  • Batch operations: Calculate multiple indicators in one call to minimize overhead
  • Reuse instances: For streaming data, reuse indicator instances instead of creating new ones
  • GPU for large data: Use GPU acceleration for datasets with >1M data points

Error Handling

import vectoralpha as va
from vectoralpha.exceptions import (
    InvalidPeriodError,
    InsufficientDataError,
    CudaNotAvailableError  # &lt;span class="tooltip" data-tooltip="Exception raised when CUDA GPU acceleration is not available"&gt;CUDA availability error</span&gt;
)

try:
    # Validate inputs
    if len(prices) &lt; 20:
        raise InsufficientDataError("Need at least 20 data points")
    
    # Calculate with error handling
    result = va.indicators.sma(prices, period=20)
    
except InvalidPeriodError as e:
    print(f"Invalid period specified: {e}")
except InsufficientDataError as e:
    print(f"Not enough data: {e}")
except CudaNotAvailableError:
    print("CUDA not available, falling back to CPU")
    va.set_backend('cpu')
    result = va.indicators.sma(prices, period=20)

Next Steps