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.
- 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
| 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 |
- 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
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
| 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 |
| 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 |
- 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
- 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
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 →
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
# Add to mix.exs
def deps do
[
{:quant, github: "the-nerd-company/quant"}
]
endThe library includes comprehensive Python validation tests that compare results against pandas/numpy standards for mathematical accuracy.
# Run the automated setup script
./scripts/setup_python.sh
# Or use Makefile
make python-setup# 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.txtpython3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt# All tests
mix test
# Python validation tests only (requires Python setup)
mix test --include python_validation
make python-test
# Coverage report
mix coveralls.lcovprovider: 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# 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())# 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)# 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)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
)- 🎯 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
:httpcfor maximum reliability - 🔑 Flexible API Keys: Pass API keys inline or configure globally
- 📈 Analysis Ready: Perfect for Livebook, production systems, and research
🎯 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)
- ✅ 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
nilvalues for unavailable data (e.g.,market_capin historical data) - ✅ Metadata Consistency: Provider atoms converted to strings, currency normalization
- ✅ Production Tested: Working with real APIs and live data
Every provider returns these exact schemas - no exceptions:
["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", ...]["symbol", "price", "change", "change_percent", "volume", "high_24h",
"low_24h", "market_cap", "timestamp", "provider", "currency", "market_state"]["symbol", "name", "type", "exchange", "currency", "country",
"sector", "industry", "market_cap", "provider", "match_score"]# 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"# 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# 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| 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 |
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
# 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"])# 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)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
}- 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
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"
)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
endPerfect 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
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_KEYenvironment variable - Or configure in your application config
Twelve Data RuntimeError: API key is required:
- Set
TWELVE_DATA_API_KEYenvironment variable - Or configure in
config/config.exswith 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
# 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
endQuant.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 testsDefault 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.
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.