Présentation
QuantFinance est une bibliothèque Python complète pour la finance quantitative. Elle couvre le pricing d'instruments financiers, la gestion des risques, l'optimisation de portefeuille et le backtesting de stratégies.
Pricing
- Black-Scholes
- Binomial Tree
- Monte Carlo
- Options exotiques
- Obligations
Risque
- VaR (4 méthodes)
- CVaR / ES
- Sharpe, Sortino, Calmar
- Max Drawdown
- Stress Testing
Portefeuille
- Markowitz
- Risk Parity
- Black-Litterman
- HRP
- Max Diversification
Backtesting
- MA Crossover
- Buy & Hold
- Momentum
- Coûts de transaction
Utilitaires
- Yahoo Finance
- Données synthétiques
- RSI, MACD, Bollinger
- Rééquilibrage
Installation
pip install quantfinance
git clone https://github.com/Mafoya1er/quantfinance.git cd quantfinance pip install -e .
pip install quantfinance[data] # Analyse de données pip install quantfinance[dev] # Développement pip install quantfinance[all] # Tout installer
Démarrage rapide
from quantfinance.pricing.options importBlackScholes from quantfinance.portfolio.optimization importPortfolioOptimizer from quantfinance.risk.var importVaRCalculator from quantfinance.utils.data importDataLoader # Pricing d'une option call bs = BlackScholes(S=100, K=105, T=1, r=0.05, sigma=0.25, option_type='call') print(f"Prix: {bs.price():.2f}, Delta: {bs.delta():.4f}") # Optimisation de portefeuille prices = DataLoader.generate_synthetic_prices(n_assets=5, n_days=756) returns = prices.pct_change().dropna() optimizer = PortfolioOptimizer(returns, risk_free_rate=0.02) result = optimizer.maximize_sharpe() print(f"Sharpe: {result['sharpe_ratio']:.3f}") # Value at Risk var_95 = VaRCalculator.historical_var(returns.iloc[:, 0], 0.95) print(f"VaR 95%: {var_95:.2%}")
quantfinance.pricing
Module de pricing d'options (vanille et exotiques) et d'obligations.
| Paramètre | Type | Description |
|---|---|---|
| S | float | Prix spot du sous-jacent |
| K | float | Prix d'exercice (strike) |
| T | float | Maturité en années |
| r | float | Taux sans risque annualisé |
| sigma | float | Volatilité annualisée |
| option_type | str | 'call' ou 'put' |
from quantfinance.pricing.options importBlackScholes # Option call européenne bs_call = BlackScholes(S=100, K=105, T=1, r=0.05, sigma=0.25, option_type='call') # Option put européenne bs_put = BlackScholes(S=100, K=95, T=0.5, r=0.03, sigma=0.20, option_type='put')
Calcule le prix théorique de l'option selon Black-Scholes.
prix = bs_call.price() print(f"Prix de l'option: {prix:.2f}") # ex: 10.45
Sensibilité du prix au prix du sous-jacent. Entre 0 et 1 pour un call, entre -1 et 0 pour un put.
print(f"Delta: {bs_call.delta():.4f}") # ex: 0.4523 print(f"Delta put: {bs_put.delta():.4f}") # ex: -0.3871
Convexité — taux de variation du delta par rapport au prix du sous-jacent. Toujours positif.
print(f"Gamma: {bs_call.gamma():.6f}") # ex: 0.018432
Sensibilité du prix à la volatilité. Exprimé pour une variation de 1% de sigma.
print(f"Vega: {bs_call.vega():.4f}") # ex: 0.3841
Décroissance temporelle — perte de valeur par jour écoulé. Généralement négatif.
print(f"Theta: {bs_call.theta():.4f}") # ex: -0.0152 (perte de 1.52 cts/jour)
Sensibilité au taux sans risque.
print(f"Rho: {bs_call.rho():.4f}") # ex: 0.2910
Calcule la volatilité implicite par la méthode de Newton-Raphson à partir du prix de marché observé.
| Paramètre | Type | Description |
|---|---|---|
| market_price | float | Prix de marché observé de l'option |
market_price = 8.50 implied_vol = bs_call.implied_volatility(market_price) print(f"Volatilité implicite: {implied_vol:.2%}") # ex: 21.34%
| Paramètre | Type | Description |
|---|---|---|
| n_steps | int | Nombre de pas dans l'arbre (défaut : 100) |
| american | bool | True pour activer l'exercice anticipé |
from quantfinance.pricing.options importBinomialTree # Option américaine put (exercice anticipé possible) bt = BinomialTree(S=100, K=105, T=1, r=0.05, sigma=0.25, n_steps=200, option_type='put', american=True) print(f"Prix option américaine: {bt.price():.2f}") # Comparaison européenne vs américaine bt_eu = BinomialTree(S=100, K=105, T=1, r=0.05, sigma=0.25, american=False) print(f"Prime d'exercice anticipé: {bt.price() - bt_eu.price():.2f}")
Prix standard par simulation de trajectoires du sous-jacent.
from quantfinance.pricing.options importMonteCarlo mc = MonteCarlo(S=100, K=105, T=1, r=0.05, sigma=0.25, n_simulations=50000) print(f"Prix MC: {mc.price():.2f}")
Prix d'une option asiatique basé sur la moyenne du sous-jacent sur la durée de vie.
# Moyenne arithmétique (standard) prix_asiatique = mc.asian_price(averaging='arithmetic') print(f"Option asiatique: {prix_asiatique:.2f}") # Moyenne géométrique prix_geo = mc.asian_price(averaging='geometric') print(f"Option asiatique géo: {prix_geo:.2f}")
Prix d'une option à barrière — s'active ou se désactive si le sous-jacent touche la barrière.
| barrier_type | Type | Description |
|---|---|---|
| 'up-out' | str | L'option disparaît si S dépasse la barrière |
| 'up-in' | str | L'option s'active si S dépasse la barrière |
| 'down-out' | str | L'option disparaît si S tombe sous la barrière |
| 'down-in' | str | L'option s'active si S tombe sous la barrière |
prix_barriere = mc.barrier_price(barrier=120, barrier_type='up-out') print(f"Option à barrière up-out: {prix_barriere:.2f}")
from quantfinance.pricing.bonds importBond # Obligation 1000€, coupon 5%, maturité 10 ans, semi-annuel bond = Bond(face_value=1000, coupon_rate=0.05, maturity=10, frequency=2)
Prix théorique de l'obligation pour un taux de rendement donné.
prix = bond.price(ytm=0.04) print(f"Prix: {prix:.2f}€") # > 1000 car YTM < coupon
Yield to Maturity — rendement actuariel jusqu'à maturité.
ytm = bond.ytm(market_price=980) print(f"YTM: {ytm:.2%}") # ex: 5.24%
Mesures de sensibilité aux taux d'intérêt.
ytm = 0.045 print(f"Duration Macaulay: {bond.duration(ytm):.2f} ans") print(f"Duration modifiée: {bond.modified_duration(ytm):.2f}") print(f"Convexité: {bond.convexity(ytm):.2f}")
quantfinance.risk
Module de mesure et d'analyse des risques de marché.
VaR historique non paramétrique — quantile empirique des pertes observées.
from quantfinance.risk.var importVaRCalculator var_95 = VaRCalculator.historical_var(returns, confidence=0.95) var_99 = VaRCalculator.historical_var(returns, confidence=0.99) print(f"VaR 95%: {var_95:.2%}") print(f"VaR 99%: {var_99:.2%}")
VaR paramétrique sous hypothèse de normalité des rendements.
var_param = VaRCalculator.parametric_var(returns, confidence=0.95) print(f"VaR paramétrique 95%: {var_param:.2%}")
VaR avec pondération exponentielle — donne plus de poids aux observations récentes (modèle RiskMetrics).
# lambda_ = 0.94 est le standard RiskMetrics pour données journalières var_ewma = VaRCalculator.ewma_var(returns, confidence=0.95, lambda_=0.94) print(f"VaR EWMA 95%: {var_ewma:.2%}")
VaR par simulation Monte Carlo de trajectoires futures.
var_mc = VaRCalculator.monte_carlo_var(returns, confidence=0.95, n_sim=100000) print(f"VaR Monte Carlo 95%: {var_mc:.2%}")
CVaR / Expected Shortfall — perte moyenne dans les scénarios pires que la VaR. Mesure cohérente du risque.
es_95 = VaRCalculator.expected_shortfall(returns, confidence=0.95) print(f"CVaR 95%: {es_95:.2%}") # toujours >= VaR # Comparaison des 4 méthodes for method, val in [ ("Historique", VaRCalculator.historical_var(returns, 0.95)), ("Paramétrique", VaRCalculator.parametric_var(returns, 0.95)), ("EWMA", VaRCalculator.ewma_var(returns, 0.95)), ("Monte Carlo", VaRCalculator.monte_carlo_var(returns, 0.95)), ]: print(f"{method:14s}: {val:.2%}")
Ratio rendement/risque annualisé. Mesure le rendement excédentaire par unité de volatilité totale.
from quantfinance.risk.metrics importRiskMetrics sharpe = RiskMetrics.sharpe_ratio(returns, rf=0.02) print(f"Sharpe: {sharpe:.3f}") # > 1 = bon, > 2 = excellent
Comme Sharpe mais ne pénalise que la volatilité négative (downside deviation).
sortino = RiskMetrics.sortino_ratio(returns, rf=0.02) print(f"Sortino: {sortino:.3f}")
Rendement annualisé divisé par le drawdown maximum. Mesure la récupération après perte.
calmar = RiskMetrics.calmar_ratio(returns) print(f"Calmar: {calmar:.3f}")
Perte maximale depuis un pic précédent, exprimée en pourcentage.
mdd = RiskMetrics.max_drawdown(returns) print(f"Max Drawdown: {mdd:.2%}") # ex: -23.45%
Alpha annualisé divisé par le tracking error — mesure la valeur ajoutée par rapport à un benchmark.
ir = RiskMetrics.information_ratio(portfolio_returns, benchmark_returns) print(f"Information Ratio: {ir:.3f}")
from quantfinance.risk.metrics importPerformanceAnalyzer analyzer = PerformanceAnalyzer(returns, risk_free_rate=0.02)
Tableau complet de toutes les métriques de performance et de risque.
summary = analyzer.summary_statistics() print(summary) # Rendement annualisé : 12.34% # Volatilité annualisée : 8.92% # Ratio de Sharpe : 1.382 # Max Drawdown : -15.23% # VaR 95% : -1.45% # CVaR 95% : -2.10%
Métriques calculées sur une fenêtre glissante — utile pour suivre l'évolution dans le temps.
# Fenêtre de 252 jours (1 an) rolling = analyzer.rolling_metrics(window=252) print(rolling[['sharpe', 'volatility']].tail())
Graphique de la performance cumulée et des drawdowns.
import matplotlib.pyplot as plt fig = analyzer.plot_performance() plt.show()
Applique des scénarios de crises historiques (2008, COVID-19, etc.) au portefeuille.
from quantfinance.risk.stress importStressTesting results = StressTesting.historical_scenarios(returns) print(results) # Crise 2008 : -38.2% # COVID 2020 : -12.4% # Dot-com 2000 : -25.1%
Applique des chocs personnalisés sur les facteurs de risque.
# Scénario : choc de -30% sur les actions, +200bps sur les taux shocks = {'equity': -0.30, 'rates': 0.02} pnl = StressTesting.custom_scenario(returns, shocks) print(f"P&L sous stress: {pnl:.2%}")
quantfinance.portfolio
Module d'optimisation de portefeuille, d'allocation d'actifs et de backtesting.
Initialise l'optimiseur avec les rendements historiques et le taux sans risque.
from quantfinance.portfolio.optimization importPortfolioOptimizer optimizer = PortfolioOptimizer(returns_df, risk_free_rate=0.03)
Crée un portefeuille équipondéré (poids égaux pour chaque actif).
result = optimizer.equal_weight() print("Poids:", result['weights']) print("Rendement:", result['return'])
Minimise la volatilité du portefeuille — portefeuille à variance minimale.
result = optimizer.minimize_volatility() print(f"Volatilité minimale: {result['volatility']:.2%}") print(f"Rendement associé: {result['return']:.2%}") print(result['weights'])
Maximise le ratio de Sharpe — point tangent de la frontière efficiente.
result = optimizer.maximize_sharpe() print(f"Sharpe max: {result['sharpe_ratio']:.3f}") print(f"Rendement: {result['return']:.2%}") print(f"Volatilité: {result['volatility']:.2%}")
Maximise le rendement sous contrainte de volatilité cible.
result = optimizer.maximize_return(target_volatility=0.18) print(f"Rendement max (vol=18%): {result['return']:.2%}")
Portefeuille de parité de risque — chaque actif contribue également au risque total.
result = optimizer.risk_parity() print("Contribution au risque:", result['risk_contribution']) print("Poids:", result['weights'])
from quantfinance.portfolio.optimization importEfficientFrontier frontier = EfficientFrontier(optimizer)
Calcule les portefeuilles optimaux sur la frontière efficiente.
frontier_data = frontier.calculate_frontier(n_points=50) print(frontier_data.head()) # columns: return, volatility, sharpe_ratio, weights...
Trace la frontière efficiente avec les actifs individuels et le portefeuille optimal.
import matplotlib.pyplot as plt fig = frontier.plot(show_assets=True, show_optimal=True) plt.show()
from quantfinance.portfolio.optimization importAssetAllocator allocator = AssetAllocator(returns_df)
Allocation HRP — utilise la hiérarchie des corrélations pour diversifier sans inversion de matrice.
weights = allocator.hierarchical_risk_parity() print("Poids HRP:", weights)
Minimise la corrélation moyenne entre les actifs du portefeuille.
weights = allocator.minimum_correlation() print("Poids min corr:", weights)
Maximise le ratio de diversification — rapport volatilité pondérée / volatilité portefeuille.
weights = allocator.maximum_diversification() print("Poids max div:", weights)
from quantfinance.portfolio.rebalancing importRebalancer rebalancer = Rebalancer(target_weights, prices_df, initial_capital=100000, transaction_cost=0.001)
Rééquilibre le portefeuille à intervalles fixes. Fréquences : 'daily', 'weekly', 'monthly', 'quarterly', 'yearly'.
results = rebalancer.periodic_rebalancing(frequency='quarterly') print(results.head())
Rééquilibre uniquement quand un poids dévie de plus de threshold par rapport à la cible.
# Rééquilibre si déviation > 3% results = rebalancer.threshold_rebalancing(threshold=0.03) print(results.head())
from quantfinance.portfolio.backtesting importBacktester, MovingAverageCrossover strategy = MovingAverageCrossover(short_window=20, long_window=50) backtester = Backtester(prices_df, strategy, initial_capital=10000, commission=0.0005)
Exécute le backtest et retourne les métriques de performance.
results = backtester.run() print(f"Rendement total: {results['Total Return']:.2%}") print(f"Ratio de Sharpe: {results['Sharpe Ratio']:.3f}") print(f"Max Drawdown: {results['Max Drawdown']:.2%}") print(f"Win Rate: {results['Win Rate']:.1%}")
Trace la courbe de capital, les signaux de trading et les drawdowns.
import matplotlib.pyplot as plt fig = backtester.plot_results() plt.show()
Achète au début et conserve jusqu'à la fin. Sert de benchmark de référence.
from quantfinance.portfolio.backtesting importBuyAndHoldStrategy strategy = BuyAndHoldStrategy() signals = strategy.generate_signals(prices_df) print(signals.head()) # Toujours 1 (long)
Signal d'achat quand la MA courte croise la MA longue à la hausse, et de vente à la baisse.
from quantfinance.portfolio.backtesting importMovingAverageCrossover strategy = MovingAverageCrossover(short_window=10, long_window=30) signals = strategy.generate_signals(prices_df) print(signals.head()) # 1 = long, -1 = short, 0 = neutre # Backtest complet bt = Backtester(prices_df, strategy, initial_capital=50000) results = bt.run() print(f"Rendement: {results['Total Return']:.2%}")
quantfinance.utils
Utilitaires pour le chargement de données et le calcul d'indicateurs techniques.
Charge un fichier CSV local de prix ou de rendements.
from quantfinance.utils.data importDataLoader prices = DataLoader.load_csv('data/prices.csv') print(prices.head())
Télécharge les données historiques depuis Yahoo Finance.
prices = DataLoader.load_yahoo( tickers=['AAPL', 'MSFT', 'GOOGL', 'AMZN'], start='2020-01-01', end='2024-01-01' ) returns = prices.pct_change().dropna() print(returns.describe())
Génère des prix synthétiques par mouvement brownien géométrique (GBM).
# 5 actifs sur 3 ans de données journalières prices = DataLoader.generate_synthetic_prices(n_assets=5, n_days=252*3) returns = prices.pct_change().dropna()
Génère des données OHLCV (Open, High, Low, Close, Volume) pour le backtesting.
data = DataLoader.generate_ohlcv_data(n_days=500) print(data.columns.tolist()) # ['Open', 'High', 'Low', 'Close', 'Volume']
Nettoie les données financières : valeurs manquantes, outliers, données incohérentes.
raw_data = DataLoader.load_csv('data/raw_prices.csv') clean = DataLoader.clean_data(raw_data) print(f"Lignes supprimées: {len(raw_data) - len(clean)}")
Moyennes mobiles simple (SMA) et exponentielle (EMA).
from quantfinance.utils.indicators importTechnicalIndicators close = prices['Close'] sma_20 = TechnicalIndicators.sma(close, window=20) ema_50 = TechnicalIndicators.ema(close, window=50) # Signal de croisement signal = (sma_20 > ema_50).astype(int)
Relative Strength Index — oscillateur entre 0 et 100. Suracheté > 70, survendu < 30.
rsi = TechnicalIndicators.rsi(close, window=14) print(f"RSI actuel: {rsi.iloc[-1]:.1f}") survendu = rsi[rsi <30] surachete = rsi[rsi >70]
MACD (12,26,9) — retourne la ligne MACD, la ligne signal et l'histogramme.
macd = TechnicalIndicators.macd(close) print(macd['macd'].tail()) print(macd['signal'].tail()) print(macd['histogram'].tail())
Bandes de Bollinger (±2 écarts-types autour de la SMA).
bands = TechnicalIndicators.bollinger_bands(close, window=20) print(f"Bande haute: {bands['upper'].iloc[-1]:.2f}") print(f"Bande centrale: {bands['middle'].iloc[-1]:.2f}") print(f"Bande basse: {bands['lower'].iloc[-1]:.2f}")
Formules mathématiques
Les équations fondamentales implémentées dans QuantFinance.
Black-Scholes
Les Grecques
Value at Risk
EWMA — RiskMetrics
Ratios de performance
Optimisation de Markowitz
Duration & Convexité (Obligations)
Comparaison des méthodes
Pricing d'options
| Méthode | Options américaines | Options exotiques | Vitesse | Précision | Recommandé pour |
|---|---|---|---|---|---|
| BlackScholes | Européennes seul. | Exacte | Options européennes vanille, calcul des grecques | ||
| BinomialTree | Exercice anticipé | Converge | Options américaines, options avec dividendes discrets | ||
| MonteCarlo | Avec LSM | Path-dependent | Stochastique | Options asiatiques, barrières, structures complexes |
Calcul de VaR
| Méthode | Hypothèse | Queues épaisses | Données requises | Vitesse | Recommandé quand |
|---|---|---|---|---|---|
| historical_var | Aucune | Capturées | 500+ jours | Distribution non-normale, données historiques abondantes | |
| parametric_var | Normalité des rendements | Sous-estimées | 30+ jours | Calcul rapide, portefeuilles bien diversifiés | |
| ewma_var | Normalité + vol. variable | Sous-estimées | 100+ jours | Volatilité qui change dans le temps (λ = 0.94) | |
| monte_carlo_var | GBM ou modèle custom | Configurables | Paramètres | Précision maximale, portefeuilles non-linéaires |
Optimisation de portefeuille
| Méthode | Inversion matrice | Robustesse | Grands univers | Complexité | Recommandé quand |
|---|---|---|---|---|---|
| equal_weight | Nulle | Benchmark simple, manque de données | |||
| minimize_volatility | Faible | Minimiser le risque absolu, profil défensif | |||
| maximize_sharpe | Moyenne | Rendement/risque optimal, rendements prévisibles | |||
| risk_parity | Moyenne | Égaliser la contribution au risque de chaque actif | |||
| hierarchical_risk_parity | Élevée | Grands univers, instabilité numérique, fonds alternatifs |
Stratégies de backtesting
| Stratégie | Type | Paramètres | Marchés favorables | Risque sur-optimisation |
|---|---|---|---|---|
| BuyAndHold | Passive | Aucun | Tendances longues | Nul |
| MovingAverageCrossover | Tendance | short_window, long_window | Marchés directionnels | Élevé (2 params) |
Exemples complets
Des workflows de bout en bout combinant plusieurs modules.
from quantfinance.pricing.options importBlackScholes, BinomialTree, MonteCarlo # Paramètres communs params = dict(S=100, K=105, T=1, r=0.05, sigma=0.25, option_type='call') # Comparaison des 3 modèles bs = BlackScholes(**params) bt = BinomialTree(**params, n_steps=500) mc = MonteCarlo(**params, n_simulations=100000) print(" Comparaison des prix ") print(f"Black-Scholes : {bs.price():.4f}") print(f"Binomial Tree : {bt.price():.4f}") print(f"Monte Carlo : {mc.price():.4f}") # Toutes les grecques d'un coup print(" Grecques ") for name, val in {'Delta': bs.delta(), 'Gamma': bs.gamma(), 'Vega': bs.vega(), 'Theta': bs.theta(), 'Rho': bs.rho()}.items(): print(f" {name:6s}: {val:.6f}") # Volatilité implicite depuis un prix de marché impl_vol = bs.implied_volatility(market_price=9.50) print(f" Vol. implicite: {impl_vol:.2%}") # Smile de volatilité print(" Smile de volatilité ") for K in [85, 90, 95, 100, 105, 110, 115]: b = BlackScholes(S=100, K=K, T=1, r=0.05, sigma=0.25) print(f" K={K:3d}: prix={b.price():.2f} delta={b.delta():.3f}")
from quantfinance.utils.data importDataLoader from quantfinance.portfolio.optimization importPortfolioOptimizer, EfficientFrontier from quantfinance.risk.var importVaRCalculator from quantfinance.risk.metrics importRiskMetrics, PerformanceAnalyzer # 1. Données prices = DataLoader.generate_synthetic_prices(n_assets=6, n_days=756) returns = prices.pct_change().dropna() # 2. Comparer les 4 stratégies d'optimisation opt = PortfolioOptimizer(returns, risk_free_rate=0.02) strategies = { 'Équipondéré': opt.equal_weight(), 'Min Volatilité': opt.minimize_volatility(), 'Max Sharpe': opt.maximize_sharpe(), 'Risk Parity': opt.risk_parity(), } print(f"{'Stratégie':20s} {'Rendement':>10s} {'Volatilité':>12s} {'Sharpe':>8s}") for name, res in strategies.items(): print(f"{name:20s} {res['return']:>10.2%} {res['volatility']:>12.2%} {res['sharpe_ratio']:>8.3f}") # 3. Analyse de risque sur le meilleur portefeuille w = strategies['Max Sharpe']['weights'] port_ret = (returns * w).sum(axis=1) print(" Risque (Max Sharpe) ") print(f"VaR 95% Historique : {VaRCalculator.historical_var(port_ret, 0.95):.2%}") print(f"VaR 95% Paramétrique: {VaRCalculator.parametric_var(port_ret, 0.95):.2%}") print(f"CVaR 95% : {VaRCalculator.expected_shortfall(port_ret, 0.95):.2%}") # 4. Rapport complet analyzer = PerformanceAnalyzer(port_ret, risk_free_rate=0.02) print(" Performance ") print(analyzer.summary_statistics())
from quantfinance.utils.data importDataLoader from quantfinance.utils.indicators importTechnicalIndicators from quantfinance.portfolio.backtesting importBacktester, MovingAverageCrossover, BuyAndHoldStrategy # Données OHLCV sur 3 ans data = DataLoader.generate_ohlcv_data(n_days=756) close = data['Close'] # Indicateurs techniques pour analyse préalable rsi = TechnicalIndicators.rsi(close) macd = TechnicalIndicators.macd(close) bands = TechnicalIndicators.bollinger_bands(close) print(f"RSI: {rsi.iloc[-1]:.1f} | MACD: {macd['macd'].iloc[-1]:.4f}") print(f"Bollinger: [{bands['lower'].iloc[-1]:.2f} — {bands['upper'].iloc[-1]:.2f}]") # Comparer plusieurs combinaisons de MA print(f" {'Stratégie':18s} {'Rendement':>10s} {'Sharpe':>8s} {'Max DD':>8s}") for short, long in [(10, 30), (20, 50), (50, 200)]: bt = Backtester(data, MovingAverageCrossover(short, long), initial_capital=10000, commission=0.001) res = bt.run() print(f"MA({short},{long}){' ':10s} {res['Total Return']:>10.2%} {res['Sharpe Ratio']:>8.3f} {res['Max Drawdown']:>8.2%}") # Benchmark Buy & Hold bh = Backtester(data, BuyAndHoldStrategy(), initial_capital=10000) res = bh.run() print(f"Buy & Hold {res['Total Return']:>10.2%} {res['Sharpe Ratio']:>8.3f} {res['Max Drawdown']:>8.2%}")
from quantfinance.utils.data importDataLoader from quantfinance.portfolio.optimization importPortfolioOptimizer from quantfinance.portfolio.rebalancing importRebalancer from quantfinance.risk.stress importStressTesting # Setup prices = DataLoader.generate_synthetic_prices(n_assets=4, n_days=756) returns = prices.pct_change().dropna() opt = PortfolioOptimizer(returns, risk_free_rate=0.02) weights = opt.maximize_sharpe()['weights'] # Stress testing sur crises historiques print(" Scénarios historiques ") scenarios = StressTesting.historical_scenarios(returns) print(scenarios) # Scénario personnalisé : crash actions + hausse taux shocks = {'equity': -0.35, 'rates': 0.025, 'credit': 0.015} pnl = StressTesting.custom_scenario(returns, shocks) print(f" Scénario crise 2008 amplifié: {pnl:.2%}") # Rééquilibrage périodique vs par seuil rebalancer = Rebalancer(weights, prices, initial_capital=100000, transaction_cost=0.001) res_monthly = rebalancer.periodic_rebalancing(frequency='monthly') res_threshold = rebalancer.threshold_rebalancing(threshold=0.05) print(f" Rééquilibrage mensuel — transactions: {len(res_monthly)}") print(f"Rééquilibrage seuil 5% — transactions: {len(res_threshold)}")
Tests
# Tous les tests pytest # Avec rapport de couverture HTML pytest --cov=quantfinance --cov-report=html # Tests rapides uniquement pytest -m "not slow" # Un module spécifique pytest tests/test_pricing.py -v
Guide de contribution
- Fork le dépôt sur GitHub
- Créez une branche :
git checkout -b feature/ma-fonctionnalite - Implémentez avec des tests unitaires
- Committez :
git commit -m 'feat: description' - Pushez :
git push origin feature/ma-fonctionnalite - Ouvrez une Pull Request sur GitHub