# Quant
[](https://coveralls.io/github/the-nerd-company/quant?branch=main)
[](https://github.com/the-nerd-company/quant/actions)
[](https://elixir-lang.org)
[](https://erlang.org)
[](https://creativecommons.org/licenses/by-nc/4.0/)
[](https://livebook.dev/run?url=https%3A%2F%2Fraw.githubusercontent.com%2Fthe-nerd-company%2Fquant%2Frefs%2Fheads%2Fmain%2Fexamples%2Fbacktest_examples.livemd)
> **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:**
```elixir
# 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:**
```elixir
# 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**:
```elixir
# 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 โ](docs/STANDARDIZATION.md)**
## **๐ STANDARDIZATION SUCCESS STORY**
**Problem Solved:** Financial data providers return inconsistent schemas, making cross-provider analysis painful.
**Before Quant.Explorer:**
```elixir
# 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:**
```elixir
# 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
```elixir
# 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)
```bash
# Run the automated setup script
./scripts/setup_python.sh
# Or use Makefile
make python-setup
```
#### Manual UV Installation
```bash
# 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)
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
### Running Tests
```bash
# 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.
```elixir
# โ
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")
```
```elixir
# Add to mix.exs
def deps do
[
{:quant, github: "the-nerd-company/quant"}
]
end
```
### Standardized API - Universal Parameters
```elixir
# 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
```elixir
# 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
```elixir
# 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")
```
```elixir
# Multiple symbols at once
{:ok, df} = Quant.Explorer.fetch(["AAPL", "MSFT", "GOOGL"], provider: :yahoo_finance, period: "1mo")
```
```elixir
# 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)
```
```elixir
# 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:**
```elixir
# 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:**
```elixir
# 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**)
```elixir
["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**)
```elixir
["symbol", "price", "change", "change_percent", "volume", "high_24h",
"low_24h", "market_cap", "timestamp", "provider", "currency", "market_state"]
```
### Search Results (**11 columns exactly**)
```elixir
["symbol", "name", "type", "exchange", "currency", "country",
"sector", "industry", "market_cap", "provider", "match_score"]
```
## **How Standardization Works** ๐ง
### **Parameter Translation Engine**
```elixir
# 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**
```elixir
# 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**
```elixir
# 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:
```elixir
# 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
```elixir
# 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
```elixir
# 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:
```bash
export ALPHA_VANTAGE_API_KEY="your_api_key_here"
export TWELVE_DATA_API_KEY="your_api_key_here"
```
Or in your application config:
```elixir
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:
```elixir
# 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:
```elixir
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:
```elixir
# 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..."}}`:**
- You're using the default "demo" API key
- Get a free API key at <https://www.alphavantage.co/support/#api-key>
- Set `ALPHA_VANTAGE_API_KEY` environment variable
- Or configure in your application config
**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
```elixir
# 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**:
```bash
# 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](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.