Skip to content

the-nerd-company/quant

Repository files navigation

Quant

Coverage Status CI Elixir OTP License

Run in Livebook

High-performance standardized financial data API for Elixir with Explorer DataFrames

Fetch financial data from multiple providers with universal parameters and identical output schemas for seamless analysis and maximum performance.

Key Features

🎯 Universal API Design

  • Standardized Interface: Same parameters work across ALL providers
  • Identical Schemas: Every DataFrame has exactly 12 columns regardless of provider
  • Cross-Asset Ready: Stocks, crypto, forex all use unified structure
  • Provider Agnostic: Switch providers without changing your analysis code

📊 Mathematical Indicators (Python-Validated)

Indicator Name Accuracy vs Python Key Features
RSI Relative Strength Index 100% (0.0% diff) Wilder's smoothing method
DEMA Double Exponential MA 99.96% (0.04% diff) Enhanced responsiveness
HMA Hull Moving Average 100% (0.0% diff) Reduced lag, 4-step algorithm
KAMA Kaufman Adaptive MA 100% (0.0% diff) Market condition adaptation
TEMA Triple Exponential MA 99.9988% (0.0016 diff) Maximum responsiveness
WMA Weighted Moving Average 100% (0.0% diff) Linear weight distribution

🎯 Trading Strategies & Backtesting

  • Strategy Framework: Modular strategy composition with indicators
  • Backtesting Engine: Portfolio performance analysis with metrics
  • Signal Generation: Buy/sell signals from multiple indicators
  • Composite Strategies: Combine multiple strategies for advanced analysis
  • Volatility Strategies: Bollinger Bands and mean reversion systems

🔧 Parameter Optimization (vectorbt-like)

Systematic parameter tuning with vectorbt-equivalent functionality:

# Get historical data
{:ok, df} = Quant.Explorer.history("AAPL", provider: :yahoo_finance, period: "1y")

# Define parameter ranges (like vectorbt.simulate_all_params())
param_ranges = %{
  fast_period: 5..20,     # SMA fast period range
  slow_period: 20..50     # SMA slow period range  
}

# Run optimization across all combinations - equivalent to vectorbt
{:ok, results} = Quant.Strategy.Optimization.run_combinations(df, :sma_crossover, param_ranges)

# Find best parameters (equivalent to results.idxmax())
best_params = Quant.Strategy.Optimization.find_best_params(results, :total_return)
# => %{fast_period: 12, slow_period: 26, total_return: 0.2847}

🚀 Advanced Features:

Feature Description Performance Use Case
Parallel Processing Multi-core parameter testing 4x faster on 4-core Large parameter spaces
Streaming Results Memory-efficient processing Constant memory usage 1000+ combinations
Walk-Forward Analysis Out-of-sample validation Prevents overfitting Robust parameter selection
CSV/JSON Export Results export & analysis Full precision Research & reporting
Performance Benchmarking Optimization profiling Scaling analysis System optimization

🎯 Production-Ready Optimization:

# Parallel processing for speed (uses all CPU cores)
{:ok, results} = Quant.Strategy.Optimization.run_combinations_parallel(
  df, :sma_crossover, param_ranges, 
  concurrency: System.schedulers_online()
)

# Walk-forward optimization for robustness
{:ok, wf_results} = Quant.Strategy.Optimization.walk_forward_optimization(
  df, :sma_crossover, param_ranges,
  window_size: 252,  # 1 year training
  step_size: 63      # Quarterly reoptimization
)

# Memory-efficient streaming for large parameter spaces
results_stream = Quant.Strategy.Optimization.run_combinations_stream(
  df, :sma_crossover, %{period: 5..100}, chunk_size: 20
)

# Export results for analysis
:ok = Quant.Strategy.Optimization.Export.to_csv(results, "optimization_results.csv")
:ok = Quant.Strategy.Optimization.Export.to_json(results, "results.json", precision: 6)

📊 Comprehensive Analysis Tools:

  • Parameter Correlation: Find relationships between parameters and performance
  • Performance Metrics: Total return, Sharpe ratio, max drawdown, win rate
  • Ranking & Filtering: Sort by any metric, filter by constraints
  • Statistical Summary: Mean, std dev, percentiles of parameter performance
  • Cross-Validation: Walk-forward, expanding window validation methods

🧪 Python Cross-Validation Framework

Validation Type Description Coverage Results
Mathematical Accuracy Final value comparison vs pandas/numpy All 6 indicators 99.96%+ accuracy
Algorithm Verification Step-by-step calculation comparison Core algorithms Perfect methodology match
Behavioral Testing Responsiveness and trend adaptation Market scenarios Expected behavior confirmed
Methodology Confirmation Correct implementation verification Industry standards Wilder's RSI, Hull algorithm
Test Suite Comprehensive cross-language validation Python validation 100% pass rate

🌐 Multi-Provider Support

Provider Data Types API Key Cost Key Features
Yahoo Finance Stocks, Crypto, Options ❌ No 🆓 Free Historical data, real-time quotes, company info
Alpha Vantage Stocks, Forex ✅ Required 💰 Freemium Premium intraday data, fundamentals
Binance Cryptocurrency ❌ No 🆓 Free Real-time crypto data, all trading pairs
CoinGecko Cryptocurrency ❌ No 🆓 Free Market data, historical prices, market cap
Twelve Data Stocks, Forex, Crypto ✅ Required 💰 Premium High-frequency data, global markets

Performance & Reliability

  • Explorer/Polars Backend: Optimized for high-throughput analysis
  • NX Mathematical Computing: High-performance numerical operations
  • Zero External HTTP Deps: Uses built-in Erlang :httpc
  • Advanced Rate Limiting: ETS/Redis backends with provider-specific patterns
  • Streaming Support: Handle large datasets efficiently
  • Comprehensive Test Coverage: Full validation suite with cross-language verification

🛡️ Production Ready

  • Type Safety: Full Dialyzer specifications
  • Error Handling: Comprehensive error types and graceful degradation
  • Flexible Configuration: Environment variables, runtime config, inline API keys
  • Livebook Ready: Perfect for data science and research workflows

🎯 Standardized API - Built for Performance

Quant.Explorer provides a completely standardized interface across all financial data providers with identical 12-column output schemas:

# Universal parameters work with ALL providers - identical output schemas!
{:ok, yahoo_df} = Quant.Explorer.history("AAPL", 
  provider: :yahoo_finance, interval: "1d", period: "1y")

{:ok, binance_df} = Quant.Explorer.history("BTCUSDT",
  provider: :binance, interval: "1d", period: "1y")

# Both DataFrames have IDENTICAL 12-column schemas!
#Explorer.DataFrame<
#  Polars[365 x 12]  # ✅ Always exactly 12 columns
#  ["symbol", "timestamp", "open", "high", "low", "close", "volume",
#   "adj_close", "market_cap", "provider", "currency", "timezone"]

# Seamless high-performance cross-asset analysis
DataFrame.concat_rows(yahoo_df, binance_df)
|> DataFrame.group_by("provider") 
|> DataFrame.summarise(avg_price: mean(close), total_volume: sum(volume))

✅ ACHIEVED: Complete Schema Standardization Across All Providers
✅ TESTED: Works with Yahoo Finance, Binance, Alpha Vantage, CoinGecko, Twelve Data
✅ VALIDATED: Cross-asset analysis (stocks + crypto) in unified DataFrames

📖 Complete Standardization Guide →

🚀 STANDARDIZATION SUCCESS STORY

Problem Solved: Financial data providers return inconsistent schemas, making cross-provider analysis painful.

Before Quant.Explorer:

# Binance: 16 inconsistent columns  
[\"symbol\", \"open_time\", \"close_time\", \"quote_volume\", \"taker_buy_volume\", ...]

# Yahoo Finance: 7 different columns
[\"Date\", \"Open\", \"High\", \"Low\", \"Close\", \"Adj Close\", \"Volume\"]

# Result: Impossible to combine data sources! 😞

After Quant.Explorer:

# ALL providers: Identical 12-column schema  
[\"symbol\", \"timestamp\", \"open\", \"high\", \"low\", \"close\", \"volume\", 
 \"adj_close\", \"market_cap\", \"provider\", \"currency\", \"timezone\"]

# Result: Seamless cross-asset analysis! 🎉
combined_df = DataFrame.concat_rows([binance_btc, yahoo_aapl, alpha_msft])

📊 Standardization Stats:

  • 5 Providers Standardized: Yahoo Finance, Binance, Alpha Vantage, CoinGecko, Twelve Data
  • 100% Schema Consistency: Every DataFrame has identical structure
  • 50+ Parameter Translations: Universal parameters work with all providers
  • Cross-Asset Ready: Stocks, crypto, forex all compatible
  • Production Tested: Real APIs, live data, 1000+ data points validated

Installation & Setup

Elixir Library

# Add to mix.exs
def deps do
  [
    {:quant, github: "the-nerd-company/quant"}
  ]
end

Python Dependencies (For Cross-Language Validation)

The library includes comprehensive Python validation tests that compare results against pandas/numpy standards for mathematical accuracy.

Quick Setup with UV (Recommended)

# Run the automated setup script
./scripts/setup_python.sh

# Or use Makefile
make python-setup

Manual UV Installation

# Install UV (much faster than pip)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install dependencies
uv pip install --system -e .
# or
uv pip install --system -r requirements.txt

Traditional pip (Legacy)

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Running Tests

# All tests
mix test

# Python validation tests only (requires Python setup)
mix test --include python_validation
make python-test

# Coverage report
mix coveralls.lcov

Quick Start

⚠️ Important: Provider Must Be Explicit All functions require an explicit provider: parameter. There are no default providers to avoid confusion about which API is being called.

# ✅ Correct - explicit provider
{:ok, df} = Quant.Explorer.history("AAPL", provider: :yahoo_finance, period: "1y")

# ❌ Error - will return {:error, :provider_required}  
{:ok, df} = Quant.Explorer.history("AAPL", period: "1y")
# Add to mix.exs
def deps do
  [
    {:quant, github: "the-nerd-company/quant"}
  ]
end

Standardized API - Universal Parameters

# Universal parameters work with ALL providers - perfect for analysis!

# Stock data - Yahoo Finance (free, no API key)
{:ok, df} = Quant.Explorer.history("AAPL", 
  provider: :yahoo_finance, interval: "1d", period: "1y")

# Stock data - Alpha Vantage (premium, requires API key)
{:ok, df} = Quant.Explorer.history("AAPL",
  provider: :alpha_vantage, interval: "1d", period: "1y", api_key: "your_key")

# Crypto data - Binance (free, no API key)
{:ok, df} = Quant.Explorer.history("BTCUSDT",
  provider: :binance, interval: "1d", period: "1y")

# Crypto data - CoinGecko (free, no API key)
{:ok, df} = Quant.Explorer.history("bitcoin", 
  provider: :coin_gecko, interval: "1d", period: "1y", currency: "usd")

# Stock data - Twelve Data (premium, requires API key)  
{:ok, df} = Quant.Explorer.history("AAPL",
  provider: :twelve_data, interval: "1d", period: "1y", api_key: "your_key")

# ALL DataFrames have IDENTICAL schemas - combine for analysis!
all_data = [yahoo_df, alpha_df, binance_df, coingecko_df, twelve_df]
|> Enum.reduce(&DataFrame.concat_rows/2)
|> DataFrame.group_by("provider") 
|> DataFrame.summarise(avg_price: mean(close), data_points: count())

Universal Parameters - Work with ANY Provider

# Standard intervals (auto-translated per provider)
intervals = ["1m", "5m", "15m", "30m", "1h", "1d", "1w", "1mo"]

# Standard periods (auto-translated per provider)
periods = ["1d", "5d", "1mo", "3mo", "6mo", "1y", "2y", "5y", "10y", "max"]

# Standard currencies (crypto providers)
currencies = ["usd", "eur", "btc", "eth"]

# Real-time quotes with universal parameters
{:ok, df} = Quant.Explorer.quote(["AAPL", "MSFT"], provider: :yahoo_finance)
{:ok, df} = Quant.Explorer.quote(["BTCUSDT", "ETHUSDT"], provider: :binance)
{:ok, df} = Quant.Explorer.quote("AAPL", provider: :alpha_vantage, api_key: "key")

# Symbol search with universal parameters
{:ok, df} = Quant.Explorer.search("Apple", provider: :yahoo_finance)  
{:ok, df} = Quant.Explorer.search("Bitcoin", provider: :coin_gecko)
{:ok, df} = Quant.Explorer.search("Microsoft", provider: :alpha_vantage, api_key: "key")

# Company info
{:ok, info} = Quant.Explorer.info("AAPL", provider: :yahoo_finance)
{:ok, info} = Quant.Explorer.info("bitcoin", provider: :coin_gecko)

Backward Compatibility

# fetch/2 is now an alias for history/2 - same standardized output
{:ok, df} = Quant.Explorer.fetch("AAPL", provider: :yahoo_finance, interval: "1d", period: "1y")
# Identical to:
{:ok, df} = Quant.Explorer.history("AAPL", provider: :yahoo_finance, interval: "1d", period: "1y")
# Multiple symbols at once
{:ok, df} = Quant.Explorer.fetch(["AAPL", "MSFT", "GOOGL"], provider: :yahoo_finance, period: "1mo")
# Real-time quotes

{:ok, df} = Quant.Explorer.quote(["AAPL", "MSFT"], provider: :yahoo_finance)
{:ok, df} = Quant.Explorer.quote(["BTCUSDT", "ETHUSDT"], provider: :binance)
{:ok, df} = Quant.Explorer.quote(["bitcoin", "ethereum"], provider: :coin_gecko)
{:ok, df} = Quant.Explorer.quote("AAPL", provider: :alpha_vantage)
{:ok, df} = Quant.Explorer.quote("AAPL", provider: :twelve_data)
# Symbol search

{:ok, df} = Quant.Explorer.search("Apple", provider: :yahoo_finance)
{:ok, df} = Quant.Explorer.search("BTC", provider: :binance)
{:ok, df} = Quant.Explorer.search("bitcoin", provider: :coin_gecko)
{:ok, df} = Quant.Explorer.search("Microsoft", provider: :alpha_vantage)
{:ok, df} = Quant.Explorer.search("Apple", provider: :twelve_data)

Parameter Optimization Quick Start

vectorbt-like parameter optimization for systematic strategy tuning:

# 1. Get historical data
{:ok, df} = Quant.Explorer.history("AAPL", provider: :yahoo_finance, period: "1y")

# 2. Define parameter ranges to test
param_ranges = %{
  fast_period: 5..15,    # Test fast SMA periods 5-15
  slow_period: 20..30    # Test slow SMA periods 20-30
}

# 3. Run optimization (tests all combinations)
{:ok, results} = Quant.Strategy.Optimization.run_combinations(df, :sma_crossover, param_ranges)

# 4. Find best parameters
best = Quant.Strategy.Optimization.find_best_params(results, :total_return)
# => %{fast_period: 8, slow_period: 24, total_return: 0.187, sharpe_ratio: 1.43}

# 5. Export results for analysis
:ok = Quant.Strategy.Optimization.Export.to_csv(results, "optimization_results.csv")

🚀 Advanced optimization features:

# Parallel processing (4x faster)
{:ok, results} = Quant.Strategy.Optimization.run_combinations_parallel(
  df, :sma_crossover, param_ranges, concurrency: 4
)

# Walk-forward optimization (prevents overfitting)
{:ok, wf_results} = Quant.Strategy.Optimization.walk_forward_optimization(
  df, :sma_crossover, param_ranges, window_size: 252, step_size: 63
)

# Memory-efficient streaming (for large parameter spaces)  
results_stream = Quant.Strategy.Optimization.run_combinations_stream(
  df, :sma_crossover, %{period: 5..100}, chunk_size: 20
)

Features

  • 🎯 Standardized Interface: Universal parameters and identical schemas across ALL providers
  • ⚡ High Performance: Built on Explorer's Polars backend with optimized data transformations
  • 🔄 Multi-Provider: Yahoo Finance, Alpha Vantage, Binance, CoinGecko, Twelve Data
  • 💰 Crypto Support: Native cryptocurrency data with standardized schemas
  • 📊 Seamless Analysis: Combine data from multiple providers effortlessly
  • 🔧 Parameter Optimization: vectorbt-like functionality for systematic strategy tuning
  • 🚀 Parallel Processing: Multi-core optimization with walk-forward validation
  • 🎯 Advanced Rate Limiting: Weighted rate limiting per provider with ETS/Redis backends
  • 🛠️ Zero External Dependencies: Uses built-in Erlang :httpc for maximum reliability
  • 🔑 Flexible API Keys: Pass API keys inline or configure globally
  • 📈 Analysis Ready: Perfect for Livebook, production systems, and research

Standardization Benefits - PRODUCTION READY

🎯 Universal Parameters: interval: "1d" works with ALL providers - TESTED & VERIFIED
📊 Identical Schemas: All DataFrames have exactly 12 columns regardless of provider
Automatic Translation: Provider-specific formats handled internally (Binance "1h" ↔ Yahoo "1h" ↔ Alpha Vantage "60min")
🔍 Rich Metadata: Provider, currency, and timezone columns for complete traceability
🛡️ Type Safety: Strong typing and validation throughout the standardization pipeline
🚀 Performance: Optimized transformations for high-throughput analysis (tested with 1000+ data points)

Standardization Achievements:

  • Schema Filtering: Eliminated provider-specific columns (Binance: 16→12 columns)
  • Universal Columns: All providers return identical column names and types
  • Cross-Asset Ready: Stocks, crypto, forex all use same schema for seamless analysis
  • Null Handling: Consistent nil values for unavailable data (e.g., market_cap in historical data)
  • Metadata Consistency: Provider atoms converted to strings, currency normalization
  • Production Tested: Working with real APIs and live data

Identical Output Schemas - GUARANTEED 🎯

Every provider returns these exact schemas - no exceptions:

Historical Data (12 columns exactly)

["symbol", "timestamp", "open", "high", "low", "close", "volume", 
 "adj_close", "market_cap", "provider", "currency", "timezone"]

# Real example from ANY provider:
#Explorer.DataFrame<
#  Polars[100 x 12]  # Always exactly 12 columns
#  symbol string ["BTCUSDT", "AAPL", ...]
#  timestamp datetime[μs, Etc/UTC] [2025-09-21 19:00:00.000000Z, ...]
#  open f64 [115530.89, 150.25, ...]
#  close f64 [115480.05, 151.30, ...]
#  market_cap null/f64 [nil, 2.5e12, ...]  # nil for crypto historical, populated for stocks
#  provider string ["binance", "yahoo_finance", ...]

Quote Data (12 columns exactly)

["symbol", "price", "change", "change_percent", "volume", "high_24h", 
 "low_24h", "market_cap", "timestamp", "provider", "currency", "market_state"]

Search Results (11 columns exactly)

["symbol", "name", "type", "exchange", "currency", "country", 
 "sector", "industry", "market_cap", "provider", "match_score"]

How Standardization Works 🔧

Parameter Translation Engine

# Your input: Universal parameters
Quant.Explorer.history("AAPL", provider: :alpha_vantage, interval: "1h")

# Automatic translation:
# Quant.Explorer    → Alpha Vantage API
# "1h"          → "60min"
# "1d"          → "daily" 
# "1w"          → "weekly"

Schema Standardization Pipeline

# 1. Raw provider data (varies by provider)
Binance: ["symbol", "open_time", "close_time", "quote_volume", ...] # 16 columns
Yahoo:   ["Date", "Open", "High", "Adj Close", ...]                # 7 columns

# 2. Standardization engine processes:
# - Normalizes column names: "open_time" → "timestamp"
# - Filters provider-specific columns: removes "close_time", "quote_volume"
# - Adds missing columns: ensures "market_cap" exists (nil if not available)
# - Adds metadata: "provider", "currency", "timezone"

# 3. Final output (IDENTICAL across all providers):
["symbol", "timestamp", "open", "high", "low", "close", "volume", 
 "adj_close", "market_cap", "provider", "currency", "timezone"]  # Always 12

Cross-Asset Consistency

# Stocks: market_cap from company data, adj_close properly calculated
# Crypto: market_cap = nil (honest about availability), adj_close = close
# All:    Universal OHLCV structure enables cross-asset analysis

📊 Supported Data & Endpoints

Provider Historical Real-time Quotes Symbol Search Company Info Options Data Crypto Support
Yahoo Finance ✅ All periods ✅ Multi-symbol ✅ Full search ✅ Fundamentals ✅ Options chains ✅ Major pairs
Alpha Vantage ✅ Premium data ✅ Real-time ✅ Symbol lookup ✅ Company data ❌ Not available ❌ Stocks only
Binance ✅ All intervals ✅ 24hr stats ✅ Pair search ❌ Crypto only ❌ Not applicable ✅ All pairs
CoinGecko ✅ Historical ✅ Live prices ✅ Coin search ✅ Market data ❌ Not applicable ✅ Full coverage
Twelve Data ✅ Global markets ✅ Real-time ✅ Advanced search ✅ Fundamentals ❌ Not available ✅ Major pairs

Cryptocurrency Support

Get crypto data from Binance with full support for:

# Bitcoin historical data
{:ok, df} = Quant.Explorer.fetch("BTCUSDT", provider: :binance, interval: "1h", limit: 100)

# Multiple crypto pairs
{:ok, df} = Quant.Explorer.quote(["BTCUSDT", "ETHUSDT", "ADAUSDT", "DOTUSDT"], provider: :binance)

# Search crypto pairs
{:ok, df} = Quant.Explorer.search("ETH", provider: :binance)

# All available trading pairs
{:ok, df} = Quant.Explorer.Providers.Binance.get_all_symbols()

# Custom time ranges for crypto analysis
{:ok, df} = Quant.Explorer.Providers.Binance.history_range("BTCUSDT", "5m", start_time, end_time)

Supported Binance intervals: 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M

Advanced Usage

# Stream large datasets
stream = Quant.Explorer.Providers.YahooFinance.history_stream("AAPL", period: "max")
df = stream |> Enum.to_list() |> List.first()

# Custom date ranges
{:ok, df} = Quant.Explorer.fetch("AAPL", 
  start_date: ~D[2023-01-01], 
  end_date: ~D[2023-12-31],
  interval: "1d"
)

# Options chain
{:ok, options} = Quant.Explorer.Providers.YahooFinance.options("AAPL")

# Alpha Vantage premium data (requires API key)
{:ok, df} = Quant.Explorer.Providers.AlphaVantage.history("MSFT", interval: "5min", outputsize: "full")
{:ok, df} = Quant.Explorer.Providers.AlphaVantage.quote("MSFT")
{:ok, df} = Quant.Explorer.Providers.AlphaVantage.search("Apple")

# Crypto klines with custom intervals
{:ok, df} = Quant.Explorer.Providers.Binance.history("BTCUSDT", interval: "15m", limit: 500)

# All crypto trading pairs
{:ok, df} = Quant.Explorer.Providers.Binance.get_all_symbols()

# Crypto 24hr statistics
{:ok, df} = Quant.Explorer.Providers.Binance.quote(["BTCUSDT", "ETHUSDT", "ADAUSDT"])

Parameter Optimization - Advanced Examples

# Complex multi-parameter optimization
{:ok, df} = Quant.Explorer.history("AAPL", provider: :yahoo_finance, period: "2y")

# Test RSI + Bollinger Bands strategy
param_ranges = %{
  rsi_period: 10..20,
  rsi_overbought: 70..80, 
  rsi_oversold: 20..30,
  bb_period: 15..25,
  bb_std_dev: 1.5..2.5
}

# Parallel optimization across all combinations
{:ok, results} = Quant.Strategy.Optimization.run_combinations_parallel(
  df, :rsi_bollinger, param_ranges, 
  concurrency: System.schedulers_online(),
  initial_capital: 10_000.0,
  commission: 0.001
)

# Analyze parameter correlations
correlations = Quant.Strategy.Optimization.Results.parameter_correlation(
  results, :total_return, [:rsi_period, :bb_period]
)

# Walk-forward optimization for robustness
{:ok, wf_results} = Quant.Strategy.Optimization.walk_forward_optimization(
  df, :rsi_bollinger, param_ranges,
  window_size: 252,  # 1 year training window
  step_size: 21,     # Monthly reoptimization
  min_trades: 10     # Require minimum trades
)

# Export comprehensive results
:ok = Quant.Strategy.Optimization.Export.to_csv(results, "full_optimization.csv", 
  delimiter: ",", precision: 4)

:ok = Quant.Strategy.Optimization.Export.to_json(wf_results, "walkforward_results.json")

# Generate summary report
:ok = Quant.Strategy.Optimization.Export.summary(results, "optimization_summary.txt",
  include_correlations: true, top_n: 10)

# Memory-efficient streaming for very large parameter spaces
large_ranges = %{
  fast_period: 5..50,      # 46 values
  slow_period: 51..200,    # 150 values  
  signal_period: 5..20     # 16 values
}
# Total: 46 * 150 * 16 = 110,400 combinations!

# Process in chunks to avoid memory issues
results_stream = Quant.Strategy.Optimization.run_combinations_stream(
  df, :triple_sma, large_ranges, chunk_size: 1000
)

# Process results as they come in
best_so_far = results_stream
|> Stream.map(fn {:ok, chunk_df} ->
  chunk_df
  |> DataFrame.filter(col("total_return") > 0.1)  # Filter profitable combinations
  |> DataFrame.slice_head(10)  # Keep top 10 per chunk
end)
|> Stream.reject(&(DataFrame.n_rows(&1) == 0))  # Skip empty chunks
|> Enum.reduce(fn chunk, acc -> 
  DataFrame.concat_rows([acc, chunk])
  |> DataFrame.sort_by(desc(col("total_return")))  
  |> DataFrame.slice_head(50)  # Keep top 50 overall
end)

Configuration

Alpha Vantage API Key

To use Alpha Vantage (premium financial data), set your API key:

export ALPHA_VANTAGE_API_KEY="your_api_key_here"
export TWELVE_DATA_API_KEY="your_api_key_here"

Or in your application config:

config :quant,
  api_keys: %{
    alpha_vantage: "your_api_key_here",
    twelve_data: "your_api_key_here"
    # coin_gecko: "your_pro_api_key"  # Optional for CoinGecko Pro
  }

⚠️ Alpha Vantage Free Tier Limitations:

  • 5 requests per minute, 500 requests per day
  • Some symbols may not be available in free tier
  • Premium endpoints require paid subscription
  • Use popular symbols like "AAPL", "MSFT", "GOOGL" for better results

API Keys in Function Calls

For Livebook, multi-client applications, or dynamic API key management, you can pass API keys directly in function calls instead of configuring them globally:

# Pass API keys directly (great for Livebook!)
{:ok, df} = Quant.Explorer.fetch("AAPL", 
  provider: :alpha_vantage,
  api_key: "your_alpha_vantage_key"
)

{:ok, df} = Quant.Explorer.quote("AAPL",
  provider: :twelve_data, 
  api_key: "your_twelve_data_key"
)

{:ok, df} = Quant.Explorer.search("Apple",
  provider: :alpha_vantage,
  api_key: "your_api_key"
)

# Works with all provider functions
{:ok, info} = Quant.Explorer.info("AAPL",
  provider: :twelve_data,
  api_key: "your_api_key" 
)

Multi-Client Scenarios

This is particularly useful when serving multiple clients with different API keys:

defmodule TradingService do
  def get_stock_data(symbol, client_id) do
    api_key = get_api_key_for_client(client_id)
    
    Quant.Explorer.fetch(symbol,
      provider: :alpha_vantage,
      api_key: api_key,
      interval: "daily"
    )
  end
  
  defp get_api_key_for_client(client_id) do
    # Fetch from database, environment, etc.
    MyApp.Repo.get_client_api_key(client_id)
  end
end

Livebook Examples

Perfect for data science and research in Livebook:

# Cell 1: Setup
Mix.install([{:quant, github: "the-nerd-company/quant"}])

# Cell 2: Get data with inline API key
api_key = "your_alpha_vantage_api_key"

{:ok, aapl} = Quant.Explorer.fetch("AAPL", 
  provider: :alpha_vantage,
  api_key: api_key,
  interval: "daily",
  outputsize: "compact"
)

{:ok, msft} = Quant.Explorer.fetch("MSFT",
  provider: :twelve_data, 
  api_key: "your_twelve_data_key",
  interval: "1day",
  outputsize: 50
)

# Cell 3: Analyze with Explorer
Explorer.DataFrame.describe(aapl)

Benefits of inline API keys:

  • ✅ No global configuration needed
  • ✅ Perfect for Livebook notebooks
  • ✅ Support multiple clients/keys
  • ✅ Override config on a per-call basis
  • ✅ Better for testing different keys

Troubleshooting

Common API Issues

Alpha Vantage {:error, :symbol_not_found}:

  • Free tier has limited symbol coverage
  • Try popular symbols: "AAPL", "MSFT", "GOOGL", "TSLA"
  • Verify your API key is valid (not "demo" key)
  • Check rate limits (5 requests/minute for free tier)

Alpha Vantage {:error, {:api_key_error, "Demo API key detected..."}}:

Twelve Data RuntimeError: API key is required:

  • Set TWELVE_DATA_API_KEY environment variable
  • Or configure in config/config.exs with your API key

CoinGecko slow responses:

  • Free tier has 10-30 calls/minute limit
  • Consider upgrading to Pro tier for higher limits

Rate limiting errors:

  • Each provider has different rate limits
  • Free tiers are more restrictive than paid plans
  • Wait between requests or implement backoff logic

Error Handling Examples

# Handle API errors gracefully
case Quant.Explorer.quote("AAPL", provider: :alpha_vantage) do
  {:ok, df} -> 
    IO.puts("Got data!")
    df
  
  {:error, :provider_required} ->
    IO.puts("Provider must be specified explicitly - no defaults!")
    
  {:error, :symbol_not_found} -> 
    IO.puts("Symbol not found - try a different symbol")
    
  {:error, {:api_key_error, msg}} -> 
    IO.puts("API key issue: #{msg}")
    # Common message: "Demo API key detected. Please get a free API key at https://www.alphavantage.co/support/#api-key"
    
  {:error, :rate_limited} -> 
    IO.puts("Rate limited - wait and try again")
    
  {:error, reason} -> 
    IO.puts("Other error: #{inspect(reason)}")
end

# Fallback to different providers
def get_quote(symbol) do
  case Quant.Explorer.quote(symbol, provider: :yahoo_finance) do
    {:ok, df} -> {:ok, df}
    {:error, _} -> 
      # Try Alpha Vantage as fallback
      Quant.Explorer.quote(symbol, provider: :alpha_vantage)
  end
end

Testing

Quant.Explorer includes both fast mocked tests and integration tests:

# Run default tests (mocked, fast, no API calls)
mix test                              # ~0.3s, all mocked tests

# Run integration tests (real API calls, slower)
mix test --include integration        # Real HTTP requests to APIs

# Run specific test type
mix test --only mocked               # Only mocked tests  
mix test --only integration          # Only real API tests

Default behavior:

  • Mocked tests run by default - Fast, reliable, no external dependencies
  • Integration tests excluded by default - Require API keys and internet

See TESTING.md for detailed testing documentation.

License

This project is licensed under CC BY-NC 4.0, which means:

You can:

  • Use for personal projects, research, and education
  • Share, copy, and redistribute the code
  • Modify and build upon the code
  • Use in academic and non-profit contexts

You cannot:

  • Use for commercial purposes without permission
  • Sell products or services based on this code
  • Use in commercial trading systems or financial products

This ensures the library remains free for the community while protecting against unauthorized commercial exploitation.

About

Quantitative analysis library for Elixir and Explorer

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages