quantlite 0.7.0__tar.gz → 0.9.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. {quantlite-0.7.0/src/quantlite.egg-info → quantlite-0.9.0}/PKG-INFO +162 -1
  2. {quantlite-0.7.0 → quantlite-0.9.0}/README.md +161 -0
  3. {quantlite-0.7.0 → quantlite-0.9.0}/pyproject.toml +4 -1
  4. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/__init__.py +3 -0
  5. quantlite-0.9.0/src/quantlite/factors/__init__.py +43 -0
  6. quantlite-0.9.0/src/quantlite/factors/classical.py +288 -0
  7. quantlite-0.9.0/src/quantlite/factors/custom.py +340 -0
  8. quantlite-0.9.0/src/quantlite/factors/tail_risk.py +296 -0
  9. quantlite-0.9.0/src/quantlite/simulation/__init__.py +45 -0
  10. quantlite-0.9.0/src/quantlite/simulation/copula_mc.py +238 -0
  11. quantlite-0.9.0/src/quantlite/simulation/evt_simulation.py +304 -0
  12. quantlite-0.9.0/src/quantlite/simulation/regime_mc.py +328 -0
  13. {quantlite-0.7.0 → quantlite-0.9.0/src/quantlite.egg-info}/PKG-INFO +162 -1
  14. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite.egg-info/SOURCES.txt +14 -0
  15. quantlite-0.9.0/tests/test_factors_classical.py +208 -0
  16. quantlite-0.9.0/tests/test_factors_custom.py +205 -0
  17. quantlite-0.9.0/tests/test_factors_tail_risk.py +224 -0
  18. quantlite-0.9.0/tests/test_sim_copula.py +159 -0
  19. quantlite-0.9.0/tests/test_sim_evt.py +164 -0
  20. quantlite-0.9.0/tests/test_sim_regime.py +211 -0
  21. {quantlite-0.7.0 → quantlite-0.9.0}/LICENSE +0 -0
  22. {quantlite-0.7.0 → quantlite-0.9.0}/setup.cfg +0 -0
  23. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/antifragile/__init__.py +0 -0
  24. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/backtesting/__init__.py +0 -0
  25. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/backtesting/analysis.py +0 -0
  26. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/backtesting/engine.py +0 -0
  27. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/backtesting/legacy.py +0 -0
  28. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/backtesting/signals.py +0 -0
  29. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/contagion/__init__.py +0 -0
  30. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/core/__init__.py +0 -0
  31. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/core/types.py +0 -0
  32. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/crypto/__init__.py +0 -0
  33. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/crypto/exchange.py +0 -0
  34. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/crypto/onchain.py +0 -0
  35. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/crypto/stablecoin.py +0 -0
  36. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/data/__init__.py +0 -0
  37. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/data/base.py +0 -0
  38. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/data/cache.py +0 -0
  39. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/data/crypto.py +0 -0
  40. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/data/fred.py +0 -0
  41. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/data/local.py +0 -0
  42. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/data/registry.py +0 -0
  43. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/data/yahoo.py +0 -0
  44. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/data_generation.py +0 -0
  45. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/dependency/__init__.py +0 -0
  46. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/dependency/clustering.py +0 -0
  47. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/dependency/copulas.py +0 -0
  48. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/dependency/correlation.py +0 -0
  49. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/distributions/__init__.py +0 -0
  50. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/distributions/fat_tails.py +0 -0
  51. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/diversification/__init__.py +0 -0
  52. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/ergodicity/__init__.py +0 -0
  53. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/forensics/__init__.py +0 -0
  54. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/instruments/__init__.py +0 -0
  55. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/instruments/bond_pricing.py +0 -0
  56. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/instruments/exotic_options.py +0 -0
  57. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/instruments/option_pricing.py +0 -0
  58. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/metrics.py +0 -0
  59. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/monte_carlo.py +0 -0
  60. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/network/__init__.py +0 -0
  61. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/overfit/__init__.py +0 -0
  62. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/portfolio/__init__.py +0 -0
  63. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/portfolio/optimisation.py +0 -0
  64. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/portfolio/rebalancing.py +0 -0
  65. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/regimes/__init__.py +0 -0
  66. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/regimes/changepoint.py +0 -0
  67. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/regimes/conditional.py +0 -0
  68. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/regimes/hmm.py +0 -0
  69. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/report/__init__.py +0 -0
  70. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/report/html_renderer.py +0 -0
  71. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/report/pdf_renderer.py +0 -0
  72. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/report/sections.py +0 -0
  73. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/report/tearsheet.py +0 -0
  74. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/resample/__init__.py +0 -0
  75. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/risk/__init__.py +0 -0
  76. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/risk/evt.py +0 -0
  77. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/risk/metrics.py +0 -0
  78. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/scenarios/__init__.py +0 -0
  79. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/visualisation.py +0 -0
  80. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/viz/__init__.py +0 -0
  81. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/viz/dependency.py +0 -0
  82. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/viz/plotly_backend/__init__.py +0 -0
  83. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/viz/plotly_backend/dependency.py +0 -0
  84. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/viz/plotly_backend/portfolio.py +0 -0
  85. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/viz/plotly_backend/regimes.py +0 -0
  86. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/viz/plotly_backend/risk.py +0 -0
  87. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/viz/plotly_backend/theme.py +0 -0
  88. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/viz/portfolio.py +0 -0
  89. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/viz/regimes.py +0 -0
  90. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/viz/risk.py +0 -0
  91. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite/viz/theme.py +0 -0
  92. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite.egg-info/dependency_links.txt +0 -0
  93. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite.egg-info/requires.txt +0 -0
  94. {quantlite-0.7.0 → quantlite-0.9.0}/src/quantlite.egg-info/top_level.txt +0 -0
  95. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_analysis.py +0 -0
  96. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_antifragile.py +0 -0
  97. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_backtesting.py +0 -0
  98. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_changepoint.py +0 -0
  99. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_clustering.py +0 -0
  100. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_conditional.py +0 -0
  101. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_contagion.py +0 -0
  102. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_copulas.py +0 -0
  103. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_correlation.py +0 -0
  104. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_crypto_exchange.py +0 -0
  105. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_crypto_onchain.py +0 -0
  106. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_crypto_stablecoin.py +0 -0
  107. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_data_connectors.py +0 -0
  108. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_data_generation.py +0 -0
  109. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_diversification.py +0 -0
  110. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_engine.py +0 -0
  111. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_ergodicity.py +0 -0
  112. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_evt.py +0 -0
  113. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_fat_tails.py +0 -0
  114. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_forensics.py +0 -0
  115. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_hmm.py +0 -0
  116. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_instruments.py +0 -0
  117. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_metrics.py +0 -0
  118. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_monte_carlo.py +0 -0
  119. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_network.py +0 -0
  120. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_optimisation.py +0 -0
  121. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_overfit.py +0 -0
  122. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_plotly_viz.py +0 -0
  123. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_rebalancing.py +0 -0
  124. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_report.py +0 -0
  125. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_resample.py +0 -0
  126. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_risk_metrics.py +0 -0
  127. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_scenarios.py +0 -0
  128. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_signals.py +0 -0
  129. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_visualisation.py +0 -0
  130. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_viz.py +0 -0
  131. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_viz_dependency.py +0 -0
  132. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_viz_portfolio.py +0 -0
  133. {quantlite-0.7.0 → quantlite-0.9.0}/tests/test_viz_regimes.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantlite
3
- Version: 0.7.0
3
+ Version: 0.9.0
4
4
  Summary: A fat-tail-native quantitative finance toolkit: EVT, risk metrics, and honest modelling for markets that bite.
5
5
  Author-email: Prasant Sudhakaran <code@prasant.net>
6
6
  License: MIT License
@@ -713,6 +713,167 @@ Same Stephen Few theme, same muted palette, but with hover info, zoom, and nativ
713
713
  | `quantlite.crypto.stablecoin` | Depeg probability, peg deviation tracking, recovery time, reserve risk scoring |
714
714
  | `quantlite.crypto.exchange` | Exchange concentration (HHI), wallet risk, proof of reserves, liquidity risk, slippage |
715
715
  | `quantlite.crypto.onchain` | Wallet exposure, TVL tracking, DeFi dependency graphs, smart contract risk scoring |
716
+ | `quantlite.factors.classical` | Fama-French three/five-factor, Carhart four-factor, factor attribution, factor summary |
717
+ | `quantlite.factors.custom` | CustomFactor, significance testing, correlation matrix, factor portfolios, decay analysis |
718
+ | `quantlite.factors.tail_risk` | CVaR decomposition, regime factor exposure, crowding score, tail factor beta |
719
+ | `quantlite.simulation.evt_simulation` | EVT tail simulation, parametric tail simulation, historical bootstrap EVT, scenario fan |
720
+ | `quantlite.simulation.copula_mc` | Gaussian copula MC, t-copula MC, stress correlation MC, joint tail probability |
721
+ | `quantlite.simulation.regime_mc` | Regime-switching simulation, stress test scenarios, reverse stress test, simulation summary |
722
+
723
+ ## v0.9: Fat-Tail Monte Carlo
724
+
725
+ Three simulation families that go beyond naive Monte Carlo. Standard MC assumes returns are Gaussian and independent. QuantLite's fat-tail MC uses EVT for realistic tails, copulas for joint dependence, and regime switching for structural breaks.
726
+
727
+ ### EVT Tail Simulation
728
+
729
+ Generate scenarios with GPD-fitted tails that respect the true shape of financial returns.
730
+
731
+ ```python
732
+ import numpy as np
733
+ from quantlite.simulation import evt_tail_simulation, scenario_fan
734
+
735
+ rng = np.random.default_rng(42)
736
+ returns = np.concatenate([
737
+ rng.normal(0.0003, 0.01, 900),
738
+ rng.standard_t(3, 100) * 0.03,
739
+ ])
740
+
741
+ # EVT-based scenario generation
742
+ simulated = evt_tail_simulation(returns, n_scenarios=20000, seed=42)
743
+ print(f"Historical 1st pctl: {np.percentile(returns, 1):.4f}")
744
+ print(f"Simulated 1st pctl: {np.percentile(simulated, 1):.4f}")
745
+
746
+ # Fan chart across multiple horizons
747
+ fan = scenario_fan(returns, horizons=[1, 5, 21, 63, 252])
748
+ for h in fan["horizons"]:
749
+ p5, p95 = fan["fans"][h]["5"], fan["fans"][h]["95"]
750
+ print(f" {h:>3}d: [{p5:+.2%}, {p95:+.2%}]")
751
+ ```
752
+
753
+ ![EVT Tail Simulation](docs/images/evt_tail_simulation.png)
754
+
755
+ ![Scenario Fan](docs/images/scenario_fan.png)
756
+
757
+ ### Copula Monte Carlo
758
+
759
+ Multivariate simulation that preserves fat-tailed marginals and captures tail dependence.
760
+
761
+ ```python
762
+ import numpy as np
763
+ from quantlite.simulation import t_copula_mc, joint_tail_probability
764
+
765
+ rng = np.random.default_rng(42)
766
+ fund_a = np.concatenate([rng.normal(0.0005, 0.012, 900), rng.standard_t(3, 100) * 0.03])
767
+ fund_b = np.concatenate([rng.normal(0.0003, 0.015, 900), rng.standard_t(4, 100) * 0.025])
768
+ corr = np.array([[1.0, 0.6], [0.6, 1.0]])
769
+
770
+ # t-copula captures tail dependence that Gaussian copula misses
771
+ simulated = t_copula_mc([fund_a, fund_b], corr, df=4, n_scenarios=50000)
772
+
773
+ result = joint_tail_probability(simulated, thresholds=[-0.03, -0.03])
774
+ print(f"Joint crash probability: {result['joint_probability']:.4f}")
775
+ print(f"Marginal probabilities: {result['marginal_probabilities']}")
776
+ ```
777
+
778
+ ![Copula Comparison](docs/images/copula_comparison.png)
779
+
780
+ ![Stressed Correlations](docs/images/stressed_correlations.png)
781
+
782
+ ### Regime-Switching Simulation
783
+
784
+ Paths that switch between calm, volatile, and crisis regimes via a Markov chain.
785
+
786
+ ```python
787
+ import numpy as np
788
+ from quantlite.simulation import (
789
+ regime_switching_simulation,
790
+ reverse_stress_test,
791
+ simulation_summary,
792
+ )
793
+
794
+ regimes = [
795
+ {"mu": 0.0004, "sigma": 0.008}, # Calm
796
+ {"mu": 0.0001, "sigma": 0.020}, # Volatile
797
+ {"mu": -0.002, "sigma": 0.035}, # Crisis
798
+ ]
799
+ transition = np.array([
800
+ [0.95, 0.04, 0.01],
801
+ [0.10, 0.80, 0.10],
802
+ [0.05, 0.15, 0.80],
803
+ ])
804
+
805
+ sim = regime_switching_simulation(regimes, transition, n_steps=252, n_scenarios=5000)
806
+ stats = simulation_summary(sim["returns"])
807
+ print(f"VaR 95%: {stats['var']['95%']:.2%}")
808
+ print(f"CVaR 95%: {stats['cvar']['95%']:.2%}")
809
+ print(f"P(loss > 20%): {stats['probability_of_ruin']['20%']:.2%}")
810
+ ```
811
+
812
+ ![Regime Simulation](docs/images/regime_simulation.png)
813
+
814
+ ![Reverse Stress Test](docs/images/reverse_stress_test.png)
815
+
816
+ See [docs/simulation_evt.md](docs/simulation_evt.md), [docs/simulation_copula.md](docs/simulation_copula.md), and [docs/simulation_regime.md](docs/simulation_regime.md) for the full API reference.
817
+
818
+ ## v0.8: Factor Models
819
+
820
+ Three modules for comprehensive factor analysis: classical academic models, custom factor tools, and tail-risk-aware factor decomposition.
821
+
822
+ ### Classical Factor Models
823
+
824
+ Decompose returns into systematic factor exposures and genuine alpha.
825
+
826
+ ```python
827
+ from quantlite.factors import fama_french_three, factor_summary
828
+
829
+ # Fama-French three-factor regression
830
+ result = fama_french_three(fund_returns, market, smb, hml)
831
+ print(f"Alpha: {result['alpha']:.5f} (t={result['t_stats']['alpha']:.2f})")
832
+ print(f"Market beta: {result['betas']['market']:.3f}")
833
+ print(f"R-squared: {result['r_squared']:.3f}")
834
+ ```
835
+
836
+ ![Factor Betas](docs/images/factor_betas.png)
837
+
838
+ ### Custom Factor Tools
839
+
840
+ Build, test, and analyse proprietary factors.
841
+
842
+ ```python
843
+ from quantlite.factors import CustomFactor, factor_portfolio, factor_decay
844
+
845
+ # Test factor decay
846
+ decay = factor_decay(returns, momentum_signal, max_lag=20)
847
+ print(f"Half-life: {decay['half_life']:.1f} periods")
848
+
849
+ # Build long-short portfolios
850
+ result = factor_portfolio(stock_returns, factor_values, n_quantiles=5)
851
+ print(f"Long-short spread: {result['spread'] * 252:.2%} annualised")
852
+ ```
853
+
854
+ ![Factor Quintiles](docs/images/factor_quintiles.png)
855
+
856
+ ### Tail Risk Factor Analysis
857
+
858
+ Understand how factor exposures behave in the tails and across regimes.
859
+
860
+ ```python
861
+ from quantlite.factors import tail_factor_beta, factor_crowding_score
862
+
863
+ # Tail betas: how exposures amplify in crises
864
+ result = tail_factor_beta(returns, [market, value], ["Market", "Value"])
865
+ for name in ["Market", "Value"]:
866
+ print(f"{name}: full={result['full_betas'][name]:.2f}, "
867
+ f"tail={result['tail_betas'][name]:.2f}")
868
+
869
+ # Factor crowding detection
870
+ crowd = factor_crowding_score([value_rets, momentum_rets])
871
+ print(f"Crowding score: {crowd['current_score']:.3f}")
872
+ ```
873
+
874
+ ![Factor Crowding](docs/images/factor_crowding.png)
875
+
876
+ See [docs/factors_classical.md](docs/factors_classical.md), [docs/factors_custom.md](docs/factors_custom.md), and [docs/factors_tail_risk.md](docs/factors_tail_risk.md) for the full API reference.
716
877
 
717
878
  ## v0.4: The Taleb Stack
718
879
 
@@ -632,6 +632,167 @@ Same Stephen Few theme, same muted palette, but with hover info, zoom, and nativ
632
632
  | `quantlite.crypto.stablecoin` | Depeg probability, peg deviation tracking, recovery time, reserve risk scoring |
633
633
  | `quantlite.crypto.exchange` | Exchange concentration (HHI), wallet risk, proof of reserves, liquidity risk, slippage |
634
634
  | `quantlite.crypto.onchain` | Wallet exposure, TVL tracking, DeFi dependency graphs, smart contract risk scoring |
635
+ | `quantlite.factors.classical` | Fama-French three/five-factor, Carhart four-factor, factor attribution, factor summary |
636
+ | `quantlite.factors.custom` | CustomFactor, significance testing, correlation matrix, factor portfolios, decay analysis |
637
+ | `quantlite.factors.tail_risk` | CVaR decomposition, regime factor exposure, crowding score, tail factor beta |
638
+ | `quantlite.simulation.evt_simulation` | EVT tail simulation, parametric tail simulation, historical bootstrap EVT, scenario fan |
639
+ | `quantlite.simulation.copula_mc` | Gaussian copula MC, t-copula MC, stress correlation MC, joint tail probability |
640
+ | `quantlite.simulation.regime_mc` | Regime-switching simulation, stress test scenarios, reverse stress test, simulation summary |
641
+
642
+ ## v0.9: Fat-Tail Monte Carlo
643
+
644
+ Three simulation families that go beyond naive Monte Carlo. Standard MC assumes returns are Gaussian and independent. QuantLite's fat-tail MC uses EVT for realistic tails, copulas for joint dependence, and regime switching for structural breaks.
645
+
646
+ ### EVT Tail Simulation
647
+
648
+ Generate scenarios with GPD-fitted tails that respect the true shape of financial returns.
649
+
650
+ ```python
651
+ import numpy as np
652
+ from quantlite.simulation import evt_tail_simulation, scenario_fan
653
+
654
+ rng = np.random.default_rng(42)
655
+ returns = np.concatenate([
656
+ rng.normal(0.0003, 0.01, 900),
657
+ rng.standard_t(3, 100) * 0.03,
658
+ ])
659
+
660
+ # EVT-based scenario generation
661
+ simulated = evt_tail_simulation(returns, n_scenarios=20000, seed=42)
662
+ print(f"Historical 1st pctl: {np.percentile(returns, 1):.4f}")
663
+ print(f"Simulated 1st pctl: {np.percentile(simulated, 1):.4f}")
664
+
665
+ # Fan chart across multiple horizons
666
+ fan = scenario_fan(returns, horizons=[1, 5, 21, 63, 252])
667
+ for h in fan["horizons"]:
668
+ p5, p95 = fan["fans"][h]["5"], fan["fans"][h]["95"]
669
+ print(f" {h:>3}d: [{p5:+.2%}, {p95:+.2%}]")
670
+ ```
671
+
672
+ ![EVT Tail Simulation](docs/images/evt_tail_simulation.png)
673
+
674
+ ![Scenario Fan](docs/images/scenario_fan.png)
675
+
676
+ ### Copula Monte Carlo
677
+
678
+ Multivariate simulation that preserves fat-tailed marginals and captures tail dependence.
679
+
680
+ ```python
681
+ import numpy as np
682
+ from quantlite.simulation import t_copula_mc, joint_tail_probability
683
+
684
+ rng = np.random.default_rng(42)
685
+ fund_a = np.concatenate([rng.normal(0.0005, 0.012, 900), rng.standard_t(3, 100) * 0.03])
686
+ fund_b = np.concatenate([rng.normal(0.0003, 0.015, 900), rng.standard_t(4, 100) * 0.025])
687
+ corr = np.array([[1.0, 0.6], [0.6, 1.0]])
688
+
689
+ # t-copula captures tail dependence that Gaussian copula misses
690
+ simulated = t_copula_mc([fund_a, fund_b], corr, df=4, n_scenarios=50000)
691
+
692
+ result = joint_tail_probability(simulated, thresholds=[-0.03, -0.03])
693
+ print(f"Joint crash probability: {result['joint_probability']:.4f}")
694
+ print(f"Marginal probabilities: {result['marginal_probabilities']}")
695
+ ```
696
+
697
+ ![Copula Comparison](docs/images/copula_comparison.png)
698
+
699
+ ![Stressed Correlations](docs/images/stressed_correlations.png)
700
+
701
+ ### Regime-Switching Simulation
702
+
703
+ Paths that switch between calm, volatile, and crisis regimes via a Markov chain.
704
+
705
+ ```python
706
+ import numpy as np
707
+ from quantlite.simulation import (
708
+ regime_switching_simulation,
709
+ reverse_stress_test,
710
+ simulation_summary,
711
+ )
712
+
713
+ regimes = [
714
+ {"mu": 0.0004, "sigma": 0.008}, # Calm
715
+ {"mu": 0.0001, "sigma": 0.020}, # Volatile
716
+ {"mu": -0.002, "sigma": 0.035}, # Crisis
717
+ ]
718
+ transition = np.array([
719
+ [0.95, 0.04, 0.01],
720
+ [0.10, 0.80, 0.10],
721
+ [0.05, 0.15, 0.80],
722
+ ])
723
+
724
+ sim = regime_switching_simulation(regimes, transition, n_steps=252, n_scenarios=5000)
725
+ stats = simulation_summary(sim["returns"])
726
+ print(f"VaR 95%: {stats['var']['95%']:.2%}")
727
+ print(f"CVaR 95%: {stats['cvar']['95%']:.2%}")
728
+ print(f"P(loss > 20%): {stats['probability_of_ruin']['20%']:.2%}")
729
+ ```
730
+
731
+ ![Regime Simulation](docs/images/regime_simulation.png)
732
+
733
+ ![Reverse Stress Test](docs/images/reverse_stress_test.png)
734
+
735
+ See [docs/simulation_evt.md](docs/simulation_evt.md), [docs/simulation_copula.md](docs/simulation_copula.md), and [docs/simulation_regime.md](docs/simulation_regime.md) for the full API reference.
736
+
737
+ ## v0.8: Factor Models
738
+
739
+ Three modules for comprehensive factor analysis: classical academic models, custom factor tools, and tail-risk-aware factor decomposition.
740
+
741
+ ### Classical Factor Models
742
+
743
+ Decompose returns into systematic factor exposures and genuine alpha.
744
+
745
+ ```python
746
+ from quantlite.factors import fama_french_three, factor_summary
747
+
748
+ # Fama-French three-factor regression
749
+ result = fama_french_three(fund_returns, market, smb, hml)
750
+ print(f"Alpha: {result['alpha']:.5f} (t={result['t_stats']['alpha']:.2f})")
751
+ print(f"Market beta: {result['betas']['market']:.3f}")
752
+ print(f"R-squared: {result['r_squared']:.3f}")
753
+ ```
754
+
755
+ ![Factor Betas](docs/images/factor_betas.png)
756
+
757
+ ### Custom Factor Tools
758
+
759
+ Build, test, and analyse proprietary factors.
760
+
761
+ ```python
762
+ from quantlite.factors import CustomFactor, factor_portfolio, factor_decay
763
+
764
+ # Test factor decay
765
+ decay = factor_decay(returns, momentum_signal, max_lag=20)
766
+ print(f"Half-life: {decay['half_life']:.1f} periods")
767
+
768
+ # Build long-short portfolios
769
+ result = factor_portfolio(stock_returns, factor_values, n_quantiles=5)
770
+ print(f"Long-short spread: {result['spread'] * 252:.2%} annualised")
771
+ ```
772
+
773
+ ![Factor Quintiles](docs/images/factor_quintiles.png)
774
+
775
+ ### Tail Risk Factor Analysis
776
+
777
+ Understand how factor exposures behave in the tails and across regimes.
778
+
779
+ ```python
780
+ from quantlite.factors import tail_factor_beta, factor_crowding_score
781
+
782
+ # Tail betas: how exposures amplify in crises
783
+ result = tail_factor_beta(returns, [market, value], ["Market", "Value"])
784
+ for name in ["Market", "Value"]:
785
+ print(f"{name}: full={result['full_betas'][name]:.2f}, "
786
+ f"tail={result['tail_betas'][name]:.2f}")
787
+
788
+ # Factor crowding detection
789
+ crowd = factor_crowding_score([value_rets, momentum_rets])
790
+ print(f"Crowding score: {crowd['current_score']:.3f}")
791
+ ```
792
+
793
+ ![Factor Crowding](docs/images/factor_crowding.png)
794
+
795
+ See [docs/factors_classical.md](docs/factors_classical.md), [docs/factors_custom.md](docs/factors_custom.md), and [docs/factors_tail_risk.md](docs/factors_tail_risk.md) for the full API reference.
635
796
 
636
797
  ## v0.4: The Taleb Stack
637
798
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "quantlite"
7
- version = "0.7.0"
7
+ version = "0.9.0"
8
8
  description = "A fat-tail-native quantitative finance toolkit: EVT, risk metrics, and honest modelling for markets that bite."
9
9
  requires-python = ">=3.9"
10
10
  license = { file = "LICENSE" }
@@ -73,3 +73,6 @@ python_version = "3.10"
73
73
  warn_return_any = true
74
74
  warn_unused_configs = true
75
75
  disallow_untyped_defs = false
76
+
77
+ [tool.pytest.ini_options]
78
+ testpaths = ["tests"]
@@ -77,6 +77,8 @@ __all__ = [
77
77
  "diversification",
78
78
  # Crypto-native risk
79
79
  "crypto",
80
+ # Fat-tail Monte Carlo simulation
81
+ "simulation",
80
82
  ]
81
83
 
82
84
  from . import ( # noqa: E402
@@ -90,4 +92,5 @@ from . import ( # noqa: E402
90
92
  overfit,
91
93
  resample,
92
94
  scenarios,
95
+ simulation,
93
96
  )
@@ -0,0 +1,43 @@
1
+ """Factor models: classical, custom, and tail risk factor analysis.
2
+
3
+ Provides tools for multi-factor attribution, custom factor construction,
4
+ factor significance testing, and tail-risk-aware factor decomposition.
5
+ """
6
+
7
+ from quantlite.factors.classical import (
8
+ carhart_four,
9
+ factor_attribution,
10
+ factor_summary,
11
+ fama_french_five,
12
+ fama_french_three,
13
+ )
14
+ from quantlite.factors.custom import (
15
+ CustomFactor,
16
+ factor_correlation_matrix,
17
+ factor_decay,
18
+ factor_portfolio,
19
+ test_factor_significance,
20
+ )
21
+ from quantlite.factors.tail_risk import (
22
+ factor_crowding_score,
23
+ factor_cvar_decomposition,
24
+ regime_factor_exposure,
25
+ tail_factor_beta,
26
+ )
27
+
28
+ __all__ = [
29
+ "fama_french_three",
30
+ "fama_french_five",
31
+ "carhart_four",
32
+ "factor_attribution",
33
+ "factor_summary",
34
+ "CustomFactor",
35
+ "test_factor_significance",
36
+ "factor_correlation_matrix",
37
+ "factor_portfolio",
38
+ "factor_decay",
39
+ "factor_cvar_decomposition",
40
+ "regime_factor_exposure",
41
+ "factor_crowding_score",
42
+ "tail_factor_beta",
43
+ ]