Lightweight Python backtesting library for algorithmic trading strategies
Project description
Portfolio-lib ๐
Ultra-Lightweight Python Backtesting Library for Algorithmic Trading
Authors: Rahul Ashok, Pritham Devaprasad, Siddarth S, and Anish R
Portfolio-lib is a comprehensive, ultra-lightweight backtesting framework designed for developing and testing quantitative trading strategies. With minimal dependencies and maximum performance, it provides everything you need for professional algorithmic trading research.
๐ Key Features
โก Ultra-Lightweight Architecture
- < 500KB total package size - minimal memory footprint
- Only essential dependencies: pandas, numpy, yfinance, scipy, matplotlib
- Optimized for speed and efficiency
๐ Comprehensive Technical Analysis
- 129 Technical Indicators built-in
- SMA, EMA, RSI, MACD, Bollinger Bands, Stochastic, ADX, and more
- Custom indicator support with easy extensibility
๐ Advanced Backtesting Engine
- Event-driven backtesting architecture
- Multi-asset portfolio simulation
- Commission and slippage modeling
- Real-time strategy execution
๐ Professional Analytics
- Advanced performance metrics (Sharpe, Sortino, Calmar ratios)
- Risk management tools (VaR, CVaR, Maximum Drawdown)
- Comprehensive trade analysis and reporting
- Visual performance charts and equity curves
๐ Data Integration
- yfinance integration for real market data
- Support for stocks, ETFs, forex, and cryptocurrencies
- Custom data source support
- Historical and real-time data handling
๐ฆ Installation
pip install portfolio-lib
Requirements
- Python 3.8+
- pandas >= 1.5.0
- numpy >= 1.21.0
- yfinance >= 0.2.0
- scipy >= 1.9.0
- matplotlib >= 3.5.0
๐ฏ Quick Start
Basic SMA Crossover Strategy
from portfolio_lib import BaseStrategy, Backtest, YFinanceDataFeed
class SMAStrategy(BaseStrategy):
def __init__(self):
super().__init__()
self.symbols = ['AAPL', 'MSFT']
self.start_date = '2020-01-01'
self.end_date = '2023-12-31'
self.fast_period = 10
self.slow_period = 30
def init_indicators(self):
print(f"SMA Strategy initialized for {self.symbols}")
def next(self):
for symbol in self.symbols:
prices = self.data[symbol]['Close']
if len(prices) < self.slow_period:
continue
fast_sma = prices.rolling(self.fast_period).mean().iloc[-1]
slow_sma = prices.rolling(self.slow_period).mean().iloc[-1]
position = self.position(symbol)
# Buy signal: fast SMA crosses above slow SMA
if fast_sma > slow_sma and position is None:
self.buy(symbol, 0.5) # 50% of portfolio
# Sell signal: fast SMA crosses below slow SMA
elif fast_sma < slow_sma and position is not None:
self.sell(symbol)
# Run backtest
strategy = SMAStrategy()
backtest = Backtest(strategy, initial_cash=100000)
data_feed = YFinanceDataFeed(strategy.symbols)
backtest.add_data_source(data_feed)
results = backtest.run(strategy.start_date, strategy.end_date)
print(results.summary())
RSI Mean Reversion Strategy
from portfolio_lib import BaseStrategy, TechnicalIndicators
class RSIStrategy(BaseStrategy):
def __init__(self):
super().__init__()
self.symbols = ['TSLA', 'NVDA']
self.start_date = '2021-01-01'
self.end_date = '2023-12-31'
self.rsi_period = 14
self.oversold = 30
self.overbought = 70
def next(self):
for symbol in self.symbols:
prices = self.data[symbol]['Close']
if len(prices) < self.rsi_period + 1:
continue
rsi = TechnicalIndicators.rsi(prices, self.rsi_period)
position = self.position(symbol)
# Buy when oversold
if rsi < self.oversold and position is None:
self.buy(symbol, 0.3)
# Sell when overbought
elif rsi > self.overbought and position is not None:
self.sell(symbol)
๐ Core Components
๐ง BaseStrategy
Base class for all trading strategies with built-in portfolio management:
class MyStrategy(BaseStrategy):
def init_indicators(self):
# Initialize your indicators here
pass
def next(self):
# Your strategy logic for each bar
# Access data: self.data[symbol]['Close']
# Place orders: self.buy(symbol, size) / self.sell(symbol)
# Check positions: self.position(symbol)
pass
๐ฐ Portfolio Management
Automatic portfolio tracking with position management:
# Portfolio automatically tracks:
# - Cash balance
# - Active positions
# - Trade history
# - Equity curve
# - Performance metrics
portfolio = results.portfolio
print(f"Total Equity: ${portfolio.total_equity:,.2f}")
print(f"Cash: ${portfolio.cash:,.2f}")
print(f"Positions: {len(portfolio.positions)}")
๐ Technical Indicators
81+ built-in technical indicators:
from portfolio_lib import TechnicalIndicators
# Moving averages
sma = TechnicalIndicators.sma(prices, period=20)
ema = TechnicalIndicators.ema(prices, period=20)
wma = TechnicalIndicators.wma(prices, period=20)
# Oscillators
rsi = TechnicalIndicators.rsi(prices, period=14)
stoch = TechnicalIndicators.stochastic(high, low, close)
williams_r = TechnicalIndicators.williams_r(high, low, close)
# Trend indicators
macd = TechnicalIndicators.macd(prices)
adx = TechnicalIndicators.adx(high, low, close)
aroon = TechnicalIndicators.aroon(high, low)
# Volatility indicators
bb = TechnicalIndicators.bollinger_bands(prices)
atr = TechnicalIndicators.atr(high, low, close)
๐ Performance Analytics
Comprehensive performance and risk metrics:
metrics = results.metrics
# Returns and performance
print(f"Total Return: {metrics.total_return:.2f}%")
print(f"Annualized Return: {metrics.annualized_return:.2f}%")
print(f"Volatility: {metrics.volatility:.2f}%")
# Risk metrics
print(f"Sharpe Ratio: {metrics.sharpe_ratio:.2f}")
print(f"Sortino Ratio: {metrics.sortino_ratio:.2f}")
print(f"Maximum Drawdown: {metrics.max_drawdown:.2f}%")
# Trading metrics
print(f"Win Rate: {metrics.win_rate:.2f}%")
print(f"Profit Factor: {metrics.profit_factor:.2f}")
print(f"Total Trades: {len(metrics.trades)}")
๐๏ธ Built-in Strategies
Portfolio-lib includes professionally implemented strategies ready to use:
from portfolio_lib import (
SMAStrategy, EMAStrategy, RSIStrategy, MACDStrategy,
BollingerBandsStrategy, MeanReversionStrategy, MomentumStrategy
)
# Use built-in strategies directly
strategy = RSIStrategy(symbols=['AAPL'], rsi_period=14)
backtest = Backtest(strategy, initial_cash=100000)
๐ ๏ธ Advanced Features
Multi-Asset Portfolio
class DiversifiedStrategy(BaseStrategy):
def __init__(self):
super().__init__()
self.stocks = ['AAPL', 'MSFT', 'GOOGL']
self.etfs = ['SPY', 'QQQ', 'IWM']
self.symbols = self.stocks + self.etfs
Risk Management
from portfolio_lib import RiskMetrics
# Portfolio risk analysis
risk = RiskMetrics(portfolio)
var_95 = risk.value_at_risk(confidence=0.95)
cvar_95 = risk.conditional_var(confidence=0.95)
Custom Data Sources
class CustomDataFeed(DataFeed):
def fetch_data(self, symbols, start_date, end_date):
# Implement your custom data fetching logic
return data_dict
๐ Performance Metrics
Portfolio-lib calculates 20+ professional metrics:
| Returns | Risk | Trading |
|---|---|---|
| Total Return | Sharpe Ratio | Win Rate |
| Annualized Return | Sortino Ratio | Profit Factor |
| CAGR | Calmar Ratio | Total Trades |
| Alpha | Maximum Drawdown | Average Trade |
| Beta | Volatility | Best/Worst Trade |
๐ง Configuration
Strategy Parameters
class ConfigurableStrategy(BaseStrategy):
def __init__(self, fast_ma=10, slow_ma=30, position_size=0.5):
super().__init__()
self.fast_ma = fast_ma
self.slow_ma = slow_ma
self.position_size = position_size
Backtest Settings
backtest = Backtest(
strategy=strategy,
initial_cash=100000,
commission=0.001, # 0.1% commission
slippage=0.0005 # 0.05% slippage
)
๐ Why Portfolio-lib?
๐โโ๏ธ Speed & Efficiency
- Ultra-lightweight: < 500KB package size
- Minimal dependencies: Only essential libraries
- Optimized algorithms: Maximum performance per operation
- Memory efficient: Minimal RAM usage
๐ Professional Features
- 81+ technical indicators with professional implementations
- Advanced risk metrics including VaR, CVaR, drawdown analysis
- Multi-asset support for stocks, ETFs, forex, crypto
- Real market data integration via yfinance
๐ก๏ธ Production Ready
- Thoroughly tested with comprehensive unit tests
- Well documented with clear examples and API reference
- Active maintenance by experienced quant developers
- Community support and regular updates
๐ Research Focused
- Academic rigor with proper statistical implementations
- Publication ready results and charts
- Extensible architecture for custom strategies
- Professional reporting with detailed analytics
๐ Examples & Tutorials
Complete Example: Momentum Strategy
import pandas as pd
from portfolio_lib import BaseStrategy, Backtest, YFinanceDataFeed, TechnicalIndicators
class MomentumStrategy(BaseStrategy):
def __init__(self):
super().__init__()
self.symbols = ['AAPL', 'MSFT', 'GOOGL', 'AMZN']
self.start_date = '2020-01-01'
self.end_date = '2023-12-31'
self.lookback = 20
self.top_n = 2
def init_indicators(self):
print("Momentum Strategy: Buy top performing stocks")
def next(self):
if len(self.data[self.symbols[0]]) < self.lookback:
return
# Calculate momentum for each symbol
momentum_scores = {}
for symbol in self.symbols:
prices = self.data[symbol]['Close']
momentum = (prices.iloc[-1] / prices.iloc[-self.lookback] - 1) * 100
momentum_scores[symbol] = momentum
# Sort by momentum
sorted_symbols = sorted(momentum_scores.items(),
key=lambda x: x[1], reverse=True)
# Close positions not in top N
for symbol in self.symbols:
position = self.position(symbol)
if position and symbol not in [s[0] for s in sorted_symbols[:self.top_n]]:
self.sell(symbol)
# Open positions in top N
for symbol, score in sorted_symbols[:self.top_n]:
position = self.position(symbol)
if not position:
self.buy(symbol, 1.0 / self.top_n)
# Run the strategy
strategy = MomentumStrategy()
backtest = Backtest(strategy, initial_cash=100000)
data_feed = YFinanceDataFeed(strategy.symbols)
backtest.add_data_source(data_feed)
results = backtest.run(strategy.start_date, strategy.end_date)
# Display comprehensive results
print("๐ MOMENTUM STRATEGY RESULTS")
print("=" * 40)
print(results.summary())
# Additional analysis
print("\\n๐ DETAILED METRICS")
print(f"Number of trades: {len(results.portfolio.trades)}")
print(f"Average position size: {100/strategy.top_n:.1f}%")
print(f"Portfolio volatility: {results.metrics.volatility:.2f}%")
print(f"Best trade return: {max([t.net_value for t in results.portfolio.trades]):,.2f}")
๐ค Contributing
Portfolio-lib is developed by Rahul Ashok, Pritham Devaprasad, Siddarth S, and Anish R.
We welcome contributions! Please see our contributing guidelines for details on:
- Code standards and style
- Testing requirements
- Documentation guidelines
- Issue reporting
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐โโ๏ธ Support
- Email: abcrahul111@gmail.com
๐ Star History
If you find Portfolio-lib useful, please give it a star! โญ
Built with โค๏ธ by Rahul Ashok, Pritham Devaprasad, Siddarth S, and Anish R
Portfolio-lib: Where lightweight meets powerful in algorithmic trading.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file portfolio_lib-1.1.0.tar.gz.
File metadata
- Download URL: portfolio_lib-1.1.0.tar.gz
- Upload date:
- Size: 47.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b424233f4552a01f1308f2f77a2bb6ca0162696fbf34f3fa8c8520db4d11745c
|
|
| MD5 |
c3fd28f0b3a3fb351dbb4997d6e62197
|
|
| BLAKE2b-256 |
0457b74dbb12fd163dd0a471e7f54efc289e721d1fd98ea96d3f3c86c994cec1
|
File details
Details for the file portfolio_lib-1.1.0-py3-none-any.whl.
File metadata
- Download URL: portfolio_lib-1.1.0-py3-none-any.whl
- Upload date:
- Size: 34.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1a633d33b96377ec6fef45c418e8fe55269b146fbb2dd556d124f07f116584d7
|
|
| MD5 |
4fcc98e7827ccf6c41ddc858ef8ed05f
|
|
| BLAKE2b-256 |
27fdd635c63b4866a8688a76605673309bcffeb8ac74fd009d64cf5c1f355f3c
|