Quantitative portfolio construction and backtesting framework built on Polars and CVXPY.
Atium provides a modular pipeline for alpha-driven portfolio optimization: define data providers, build a risk model, optimize weights, apply trading constraints, and backtest with transaction costs.
pip install atiumConstruct an optimal portfolio for a single date using mean-variance optimization with trading constraints.
from atium.risk_model import FactorRiskModel
from atium.optimizer import MVO
from atium.objectives import MaxUtilityWithTargetActiveRisk
from atium.optimizer_constraints import LongOnly, FullyInvested
from atium.trade_generator import TradeGenerator
from atium.trading_constraints import MaxPositionCount, MinPositionSize
import datetime as dt
date_ = dt.date(2026, 2, 13)
# Build a factor risk model
risk_model = FactorRiskModel(
factor_loadings=factor_loadings_provider.get(date_),
factor_covariances=factor_covariances_provider.get(date_),
idio_vol=idio_vol_provider.get(date_)
)
# Optimize portfolio weights
optimizer = MVO(
objective=MaxUtilityWithTargetActiveRisk(target_active_risk=.05),
constraints=[LongOnly(), FullyInvested()]
)
weights = optimizer.optimize(
date_=date_,
alphas=alphas_provider.get(date_),
benchmark_weights=benchmark_provider.get(date_),
risk_model=risk_model,
)
# Apply trading constraints
trade_generator = TradeGenerator(
constraints=[MinPositionSize(dollars=1), MaxPositionCount(max_positions=10)]
)
constrained_weights = trade_generator.apply(weights=weights, capital=100_000)Run a backtest with weekly rebalancing, transaction costs, and trading constraints.
from atium.risk_model import FactorRiskModelConstructor
from atium.optimizer import MVO
from atium.objectives import MaxUtilityWithTargetActiveRisk
from atium.optimizer_constraints import LongOnly, FullyInvested
from atium.trade_generator import TradeGenerator
from atium.trading_constraints import MaxPositionCount, MinPositionSize
from atium.backtester import Backtester
from atium.strategy import OptimizationStrategy
from atium.costs import LinearCost
import datetime as dt
start = dt.date(2026, 1, 2)
end = dt.date(2026, 2, 13)
# Build risk model constructor (provides a risk model for each rebalance date)
risk_model_constructor = FactorRiskModelConstructor(
factor_loadings=factor_loadings_provider,
factor_covariances=factor_covariances_provider,
idio_vol=idio_vol_provider
)
# Define strategy
strategy = OptimizationStrategy(
alpha_provider=alphas_provider,
benchmark_weights_provider=benchmark_provider,
risk_model_constructor=risk_model_constructor,
optimizer=MVO(
objective=MaxUtilityWithTargetActiveRisk(target_active_risk=.05),
constraints=[LongOnly(), FullyInvested()]
),
)
# Run backtest
backtester = Backtester()
results = backtester.run(
start=start,
end=end,
rebalance_frequency='weekly',
initial_capital=100_000,
calendar=calendar_provider,
returns=returns_provider,
benchmark=benchmark_provider,
strategy=strategy,
cost_model=LinearCost(bps=5),
trade_generator=TradeGenerator(
constraints=[MinPositionSize(dollars=1), MaxPositionCount(max_positions=10)]
)
)
print(results.summary())
results.plot_equity_curve('equity_curve.png')| Module | Description |
|---|---|
| Data Providers | Calendar, Returns, Alphas, Factor Loadings, Factor Covariances, Idio-Vol, Benchmark Weights |
| Risk Model | Factor risk model estimation and construction |
| Optimizer | Mean-variance optimization (MVO) with pluggable objectives |
| Objectives | MaxUtilityWithTargetActiveRisk and others |
| Optimizer Constraints | LongOnly, FullyInvested, etc. |
| Trade Generator | Post-optimization trading constraints (MaxPositionCount, MinPositionSize) |
| Strategy | OptimizationStrategy, QuantileStrategy |
| Cost Model | NoCost, LinearCost |
| Backtester | Time-series backtesting with configurable rebalance frequency |
- Signal Combinator
- Equal
- Inverse Volatility
- Fama-MacBeth
- Elastic Net