Skip to content

MeridianAlgo/Python-Packages

MeridianAlgo

PyPI version Python versions License Tests

MeridianAlgo is a Python library for quantitative finance and algorithmic trading. It covers the full stack a quant desk works with. That means portfolio optimization, risk management, derivatives pricing, backtesting, credit risk, volatility modeling, Monte Carlo simulation, portfolio insurance, machine learning for signals, execution algorithms, fixed income analytics, and market microstructure.

Every example in this file was run against a live install before it was published. If a snippet is here, it works.

Installation

pip install meridianalgo
# Optional extras, install only what you need
pip install meridianalgo[ml]           # scikit-learn, torch, statsmodels, hmmlearn
pip install meridianalgo[optimization] # cvxpy, cvxopt for convex optimization
pip install meridianalgo[volatility]   # arch for the GARCH family
pip install meridianalgo[data]         # lxml, beautifulsoup4, polygon-api-client
pip install meridianalgo[distributed]  # ray, dask for parallel work
pip install meridianalgo[all]          # everything above

Requires Python 3.10 or newer. The core library runs on numpy, pandas, and scipy alone. The extras unlock the machine learning models, convex solvers, and maximum likelihood GARCH.

Module overview

Module Key classes and functions
portfolio MeanVariance, HierarchicalRiskParity, RiskParity, BlackLitterman, KellyCriterion
portfolio.insurance CPPI, TimeInvariantCPPI
risk RiskAnalyzer, VaRCalculator, CVaRCalculator, StressTesting, RiskBudgeting
risk.scenario ScenarioAnalyzer, CorrelationScenario
credit MertonModel, CreditDefaultSwap, CreditRiskAnalyzer, ZSpreadCalculator
volatility GARCHModel, RealizedVolatility, VolatilityForecaster, VolatilityTermStructure, VolatilityRegimeDetector
monte_carlo GeometricBrownianMotion, HestonModel, JumpDiffusionModel, CIRModel, MonteCarloEngine
derivatives BlackScholes, GreeksCalculator, ImpliedVolatility, MonteCarloPricer, OptionChain
fixed_income BondPricer, YieldCurve, CreditSpreadAnalyzer
backtesting BacktestEngine, Strategy, Backtest
ml LSTMPredictor, WalkForwardValidator, FeatureEngineer, ModelSelector
execution VWAP, TWAP, POV, ImplementationShortfall
analytics PerformanceAnalyzer, BenchmarkAnalytics, ActiveShare, BrinsonAttribution
quant StatisticalArbitrage, RegimeDetector, MarketMicrostructure
signals RSI, MACD, BollingerBands, and more than forty indicators
liquidity OrderBook, SpreadAnalyzer, MarketImpact
factors FamaFrenchModel, FactorExposure

Quick start

import meridianalgo as ma

# Top level convenience metrics on a return series
sharpe = ma.calculate_sharpe_ratio(returns)
sortino = ma.calculate_sortino_ratio(returns)
calmar = ma.calculate_calmar_ratio(returns)
max_dd = ma.calculate_max_drawdown(returns)
cvar_95 = ma.calculate_expected_shortfall(returns)

# One call summary of around 28 metrics plus a formatted text report
stats = ma.summary_stats(returns)
print(ma.tearsheet(returns))

# Compare several strategies in one table and track a rolling Sharpe ratio
table = ma.compare({"strategy": returns, "benchmark": returns * 0.8})
roll = ma.rolling_sharpe(returns, window=63)

Examples

Portfolio optimization

Each optimizer takes expected returns as a pandas Series and a covariance matrix as a pandas DataFrame. Annualize both before you pass them in.

from meridianalgo import MeanVariance, HierarchicalRiskParity, RiskParity, BlackLitterman

expected_returns = returns.mean() * 252
covariance = returns.cov() * 252

max_sharpe = MeanVariance().optimize(expected_returns, covariance, objective="max_sharpe")
min_vol = MeanVariance().optimize(expected_returns, covariance, objective="min_volatility")
hrp = HierarchicalRiskParity().optimize(expected_returns, covariance, returns_data=returns)
rp = RiskParity().optimize(expected_returns, covariance)
bl = BlackLitterman().optimize(expected_returns, covariance)

print(max_sharpe.weights.sort_values(ascending=False))
print(f"Max sharpe ratio {max_sharpe.sharpe_ratio:.4f}")
print(f"Min variance vol {min_vol.volatility:.4f}")

Each call returns an OptimizationResult with weights, expected_return, volatility, sharpe_ratio, and a success flag.

Kelly criterion position sizing

from meridianalgo import KellyCriterion

kc = KellyCriterion(fraction=0.5)  # half kelly

f = kc.single_asset(win_prob=0.55, win_loss_ratio=1.0)   # discrete binary bet
weights = kc.optimize(returns)                            # continuous multi asset
f_moments = kc.from_moments(expected_return=0.12, volatility=0.18)
g = kc.growth_rate(expected_return=0.12, volatility=0.18) # long run growth rate

print(f"Kelly fraction {f:.2%}")
print(weights.sort_values(ascending=False))

Value at risk and stress testing

from meridianalgo import RiskAnalyzer, ScenarioAnalyzer, CorrelationScenario

risk = RiskAnalyzer(portfolio_returns)
var_95 = risk.value_at_risk(confidence=0.95, method="historical")
var_99 = risk.value_at_risk(confidence=0.99, method="cornish_fisher")
cvar_95 = risk.conditional_var(confidence=0.95)

print(f"Historical VaR 95 percent {var_95:.2%}")
print(f"Cornish Fisher VaR 99 percent {var_99:.2%}")
print(f"CVaR 95 percent {cvar_95:.2%}")

# Correlated scenario generation, all inputs are pandas
gen = CorrelationScenario(mean_returns, correlation_matrix, volatilities, weights)
scenarios = gen.generate(n_scenarios=100_000, stress_correlation=True, stress_factor=0.5)
print(f"Stressed 99 percent VaR {scenarios['var_99']:.2%}")

Credit risk

from meridianalgo import MertonModel, CreditDefaultSwap, CreditRiskAnalyzer, ZSpreadCalculator
import pandas as pd

# Merton structural model, equity as a call option on firm assets
model = MertonModel(
    equity_value=500e6, equity_volatility=0.35,
    debt_face_value=800e6, time_to_maturity=1.0, risk_free_rate=0.05,
)
result = model.calibrate()
print(f"Distance to default {result['distance_to_default']:.4f}")
print(f"Default probability {result['default_probability']:.2%}")

# CDS fair spread and a bootstrapped hazard curve
cds = CreditDefaultSwap(hazard_rate=0.02, recovery_rate=0.40, maturity=5.0)
print(f"CDS fair spread {cds.price().fair_spread * 10000:.1f} bps")
curve = CreditDefaultSwap.bootstrap_hazard_curve(
    maturities=[1, 3, 5, 7, 10], spreads=[0.0080, 0.0120, 0.0150, 0.0170, 0.0200],
)

# Portfolio expected loss
exposures = pd.DataFrame({
    "pd": [0.010, 0.025, 0.050, 0.005],
    "lgd": [0.45, 0.40, 0.60, 0.35],
    "ead": [2e6, 1.5e6, 0.5e6, 3e6],
})
el = CreditRiskAnalyzer().portfolio_expected_loss(exposures)
print(f"Portfolio expected loss {el['total_el']:,.0f}")

# Z spread from a price
calc = ZSpreadCalculator(
    cash_flows=[6, 6, 6, 6, 106], times=[1, 2, 3, 4, 5],
    risk_free_rates=[0.035, 0.038, 0.040, 0.042, 0.044],
)
print(f"Z spread {calc.z_spread(market_price=97.5) * 10000:.1f} bps")

Volatility modeling

RealizedVolatility accepts OHLCV columns in any capitalization, so open or Open or OPEN all work.

from meridianalgo import (
    GARCHModel, RealizedVolatility, VolatilityForecaster,
    VolatilityTermStructure, VolatilityRegimeDetector,
)

rv = RealizedVolatility(ohlcv)
est = rv.all_estimators(window=21)
print(est[["close_to_close_vol", "parkinson_vol", "yang_zhang_vol"]].iloc[-1])

garch = GARCHModel(daily_returns, model_type="garch", p=1, q=1)
fit = garch.fit()
print(f"Persistence {fit.persistence:.4f}, half life {fit.half_life:.1f} days")

vts = VolatilityTermStructure(daily_returns)
vts.build(horizons=[5, 10, 21, 63, 126, 252])
print(f"Term structure slope {vts.slope():.4f}")

regimes = VolatilityRegimeDetector(daily_returns).classify()
print(regimes.value_counts())

Monte Carlo simulation

from meridianalgo import (
    GeometricBrownianMotion, HestonModel, JumpDiffusionModel, CIRModel, MonteCarloEngine,
)

gbm = GeometricBrownianMotion(mu=0.08, sigma=0.20)
res = gbm.simulate(S0=100, T=1.0, n_paths=100_000, n_steps=252, antithetic=True)
print(f"Mean {res.mean:.2f}, 5th pct {res.percentile_5:.2f}, 95th pct {res.percentile_95:.2f}")

call = gbm.call_price(S0=100, K=105, T=0.25, r=0.05, n_paths=200_000)
print(f"MC call {call['price']:.4f}, std error {call['std_error']:.4f}")

heston = HestonModel(mu=0.05, v0=0.04, kappa=2.0, theta=0.04, xi=0.30, rho=-0.70)
jdm = JumpDiffusionModel(mu=0.05, sigma=0.15, lam=0.10, mu_jump=-0.03, sigma_jump=0.06)
cir = CIRModel(r0=0.03, kappa=0.80, theta=0.04, sigma=0.06)

engine = MonteCarloEngine(model="heston")
engine.configure(mu=0.05, v0=0.04, kappa=2.0, theta=0.04, xi=0.30, rho=-0.7)
engine.simulate(S0=100, T=1.0, n_paths=100_000)
put = engine.price_option(K=95, r=0.05, T=1.0, option_type="put")
print(f"Heston put {put['price']:.4f}")

Portfolio insurance

from meridianalgo import CPPI, TimeInvariantCPPI

cppi = CPPI(multiplier=3.0, floor_pct=0.80, safe_rate=0.04, rebalance_frequency=1)
result = cppi.run(equity_returns, initial_value=1_000_000)
print(f"Total return {result.total_return:.2%}, max drawdown {result.max_drawdown:.2%}")
print(f"Floor breaches {result.floor_breaches}")

# Sweep multiplier and floor combinations
sensitivity = cppi.sensitivity_analysis(
    equity_returns, multipliers=[1.0, 2.0, 3.0, 4.0, 5.0], floor_pcts=[0.70, 0.80, 0.90],
)

# TIPP, where the floor ratchets up with new portfolio peaks
tipp = TimeInvariantCPPI(multiplier=3.0, floor_pct=0.80)
tipp_result = tipp.run(equity_returns, initial_value=1_000_000)

Derivatives pricing

from meridianalgo import BlackScholes, ImpliedVolatility

call = BlackScholes(S=100, K=105, T=0.25, r=0.05, sigma=0.20, option_type="call")
put = BlackScholes(S=100, K=105, T=0.25, r=0.05, sigma=0.20, option_type="put")
print(f"Call {call['price']:.4f}, delta {call['delta']:.4f}, vega {call['vega']:.4f}")
print(f"Put  {put['price']:.4f}, delta {put['delta']:.4f}")

iv = ImpliedVolatility(market_price=3.50, S=100, K=105, T=0.25, r=0.05, option_type="call")
print(f"Implied volatility {iv:.4f}")

Fixed income

BondPricer().price_bond returns price, duration, and modified duration in one call.

from meridianalgo import BondPricer, YieldCurve

pricer = BondPricer()
bond = pricer.price_bond(
    face_value=1000, coupon_rate=0.05, yield_to_maturity=0.06,
    years_to_maturity=10, frequency=2,
)
print(f"Price {bond['price']:.4f}")
print(f"Duration {bond['duration']:.4f}")
print(f"Modified duration {bond['modified_duration']:.4f}")

curve = YieldCurve()
for maturity, rate in [(0.25, 0.04), (1, 0.045), (2, 0.048), (5, 0.052), (10, 0.055), (30, 0.058)]:
    curve.add_point(maturity, rate)
curve.build_curve(method="nelson_siegel")
print(f"7 year rate interpolated {curve.get_yield(7):.4f}")
print(f"5y5y forward rate {curve.get_forward_rate(5, 10):.4f}")

Performance and benchmark analytics

from meridianalgo import PerformanceAnalyzer, BenchmarkAnalytics, ActiveShare, BrinsonAttribution

analyzer = PerformanceAnalyzer(portfolio_returns, benchmark=spy_returns, risk_free_rate=0.05)
metrics = analyzer.calculate_all_metrics()

analytics = BenchmarkAnalytics(
    portfolio_returns=portfolio_returns, benchmark_returns=spy_returns, risk_free_rate=0.05,
)
m = analytics.active_metrics()
print(f"Active return {m.active_return:.2%}, tracking error {m.tracking_error:.2%}")
print(f"Information ratio {m.information_ratio:.3f}, beta {m.beta:.3f}")

active_share = ActiveShare.compute(portfolio_weights, benchmark_weights)
print(f"Active share {active_share:.2%}, {ActiveShare.categorize(active_share)}")

attribution = BrinsonAttribution(
    portfolio_weights=sector_w_port, benchmark_weights=sector_w_bench,
    portfolio_returns=sector_r_port, benchmark_returns=sector_r_bench,
).compute()
print(f"Total active return {attribution.total_active_return:.4f}")

Execution algorithms

The schedulers are built with the order size and a time window, then driven slice by slice as the market moves.

from meridianalgo import VWAP, TWAP, POV

vwap = VWAP(total_quantity=10_000, start_time="09:30", end_time="16:00")
twap = TWAP(total_quantity=10_000, duration_minutes=60, slice_interval_minutes=5)
pov = POV(total_quantity=10_000, target_pov=0.10)

slice_order = vwap.execute_slice(
    current_time=now, market_volume=500_000, market_price=100.0, max_participation=0.1,
)

Technical indicators

More than forty indicators ship as plain functions on numpy and pandas. They need no extras.

import meridianalgo as ma

rsi = ma.RSI(prices, period=14)
macd = ma.MACD(prices)
upper, mid, lower = ma.BollingerBands(prices, period=20)
atr = ma.ATR(high, low, close, period=14)

Statistical arbitrage

import meridianalgo as ma

stat_arb = ma.StatisticalArbitrage(prices)
zscore = stat_arb.calculate_zscore(window=21)            # rolling spread z score
result = stat_arb.calculate_cointegration(prices["KO"], prices["PEP"])  # needs the ml extra

The cointegration test relies on statsmodels, so install the ml extra to use it. The z score helper runs on the core install.

Backtesting

The backtesting engine is event driven. It processes market, signal, order, and fill events through a portfolio and order manager rather than a single run call.

from meridianalgo import BacktestEngine

engine = BacktestEngine(initial_capital=100_000, commission=0.001, slippage=0.0005)
# feed market data, submit orders, and read metrics through the event API
metrics = engine.get_performance_metrics()

Machine learning

The machine learning models need the ml extra. With it installed you get LSTM and GRU predictors, walk forward cross validation, and feature engineering.

from meridianalgo.ml import FeatureEngineer, WalkForwardValidator
from sklearn.ensemble import RandomForestClassifier

features = FeatureEngineer().create_features(
    prices, features=["returns", "rsi", "macd", "volume_ratio", "volatility", "momentum"],
)
labels = (returns.shift(-1) > 0).astype(int)

results = WalkForwardValidator().validate(
    features, labels,
    model=RandomForestClassifier(n_estimators=200, random_state=42),
    train_window=252, test_window=21,
)
print(f"Average accuracy {results['accuracy'].mean():.2%}")

Command line

meridianalgo version          # show installed version
meridianalgo info             # show module availability and loaded extras
meridianalgo demo             # run a portfolio optimization demo
meridianalgo metrics AAPL --period 2y   # compute metrics for a ticker

If the meridianalgo command is not found, your Python scripts directory is not on your PATH (common outside an activated virtualenv). Either add it to PATH, or use the equivalent module form, which always works:

python -m meridianalgo version
python -m meridianalgo info
python -m meridianalgo demo
python -m meridianalgo metrics AAPL --period 2y

Performance

Measured on the test stack described in the test results document, on a 6 asset, 1000 day synthetic set.

Operation Detail Time
Mean variance max sharpe 6 assets 3.8 ms
Hierarchical risk parity 6 assets 12.3 ms
Black Scholes price and greeks single option 0.5 ms
Merton model calibration single firm 1.7 ms
GBM simulation 100k paths, 252 steps around 0.3 s
Heston simulation 5k paths, 252 steps 40.7 ms
GARCH fit 1000 observations 77.2 ms
Realized volatility, five estimators 1000 days 4.1 ms
Full performance metrics 1000 days 3.6 ms

For the full methodology and the complete pass and fail breakdown see docs/TEST_RESULTS.md.

Architecture

meridianalgo/
├── portfolio/          mean variance, HRP, Black Litterman, Kelly, CPPI
├── risk/               VaR, CVaR, stress testing, scenario analysis
├── credit/             Merton model, CDS, Z spread, expected loss
├── volatility/         GARCH, realized vol with five estimators, HAR RV, regimes
├── monte_carlo/        GBM, Heston, jump diffusion, CIR, variance reduction
├── derivatives/        Black Scholes, greeks, implied vol, exotics
├── fixed_income/       bond pricing, yield curves, credit spreads
├── analytics/          performance metrics, benchmark attribution
├── backtesting/        event driven engine, order management, slippage
├── ml/                 LSTM and GRU, walk forward CV, feature engineering
├── execution/          VWAP, TWAP, POV, implementation shortfall
├── quant/              stat arb, pairs trading, regime detection, HFT
├── signals/            RSI, MACD, Bollinger Bands, forty plus indicators
├── liquidity/          order book, bid ask spread, market impact
├── factors/            Fama French, PCA, alpha generation
├── data/               yfinance, Polygon, streaming, storage
└── utils/              logging, validation, visualization

Optional dependencies

Extra Packages Enables
ml scikit-learn, torch, statsmodels, hmmlearn LSTM models, walk forward CV, HMM regime, cointegration
optimization cvxpy, cvxopt convex portfolio optimization, CVaR minimization
volatility arch GARCH, EGARCH, GJR GARCH by maximum likelihood
data lxml, beautifulsoup4, polygon-api-client Polygon data, web scraping
distributed ray, dask parallel backtesting and optimization
all everything above the full feature set

Documentation

Contributing

See CONTRIBUTING.md. Pull requests are welcome.

License

MIT License. See LICENSE.

Disclaimer

This software is for research and educational use. Trading financial instruments carries a substantial risk of loss. Past performance does not guarantee future results. The authors accept no responsibility for financial losses that arise from use of this software.

About

To view our Python packages, run the command pip install meridianalgo in your terminal, or you can access our files here:

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Contributors

Languages