quantmine 0.2.0__py3-none-any.whl

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.
@@ -0,0 +1,222 @@
1
+ Metadata-Version: 2.4
2
+ Name: quantmine
3
+ Version: 0.2.0
4
+ Summary: Equity factor research library with honest statistics: Newey-West IC tests, multiple-testing control, point-in-time universe, turnover-based costs, Carhart attribution
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.13
8
+ Requires-Dist: numpy>=2.4
9
+ Requires-Dist: pandas>=3.0
10
+ Requires-Dist: pyarrow>=24.0
11
+ Requires-Dist: pyyaml>=6.0
12
+ Requires-Dist: scipy>=1.17
13
+ Requires-Dist: statsmodels>=0.14
14
+ Provides-Extra: data
15
+ Requires-Dist: beautifulsoup4>=4.14; extra == 'data'
16
+ Requires-Dist: curl-cffi>=0.15; extra == 'data'
17
+ Requires-Dist: pandas-datareader>=0.11; extra == 'data'
18
+ Requires-Dist: yfinance>=1.4; extra == 'data'
19
+ Provides-Extra: viz
20
+ Requires-Dist: plotly>=6.8; extra == 'viz'
21
+ Description-Content-Type: text/markdown
22
+
23
+ # quantmine
24
+
25
+ An equity factor research library built around one principle: **statistical
26
+ honesty**. Every step that commonly inflates backtest results — survivorship
27
+ bias, overlapping-return autocorrelation, multiple testing, look-ahead in
28
+ orthogonalization, unrealistic transaction costs — is explicitly addressed,
29
+ and conclusions are reported with their uncertainty, not just their point
30
+ estimates.
31
+
32
+ The repo doubles as a full S&P 500 research case study: the library
33
+ (`quantmine/`), the daily Airflow pipeline (`pipelines/`), and the findings
34
+ below were produced by the same code you can `pip install`.
35
+
36
+ ## Install
37
+
38
+ ```bash
39
+ pip install quantmine # library only
40
+ pip install "quantmine[data]" # + yfinance download stack
41
+ ```
42
+
43
+ For development (repo checkout, Python ≥ 3.13, [uv](https://docs.astral.sh/uv/)):
44
+
45
+ ```bash
46
+ uv sync
47
+ python -m pytest test
48
+ ```
49
+
50
+ ## Quick start
51
+
52
+ Bring your own price data — any wide DataFrame (index = trading days,
53
+ columns = tickers) works; nothing is hard-wired to yfinance or the S&P 500:
54
+
55
+ ```python
56
+ import pandas as pd
57
+ import quantmine as qf
58
+
59
+ # 1) Wrap your data (or use qf.ParquetSource / qf.YFinanceSource)
60
+ data = qf.MarketData(close=close_df, volume=volume_df)
61
+
62
+ # 2) Register a custom factor — built-in factors register automatically
63
+ @qf.factor_register("my_reversal")
64
+ def my_reversal(close: pd.DataFrame, tickers: list) -> pd.DataFrame:
65
+ return -close[tickers].pct_change(5)
66
+
67
+ # 3) Compute all registered factors (dependencies resolve automatically)
68
+ pool = qf.build_param_pool(data, day=5, halflife=10, period=20)
69
+ failed, factors = qf.calculate_all_factors(pool)
70
+
71
+ # 4) Cross-sectional IC with Newey-West t-stats and multiple-testing control
72
+ fwd = qf.forward_return(data.close, periods=[1, 5, 20])
73
+ cs_ic = qf.CS_Information_Correlation(factors, fwd, output_path="cs_ic.parquet")
74
+ report = qf.multiple_testing(qf.newey_west_summary(cs_ic))
75
+
76
+ # 5) Quantile backtest on a point-in-time universe, turnover-based costs
77
+ universe = qf.MembershipTableSource(membership_df) # or qf.StaticUniverse([...])
78
+ results, history = qf.quantile_backtest(universe, factors, ["my_reversal"], fwd)
79
+ daily = qf.expand_all_to_daily_returns(history, data.close)
80
+
81
+ # 6) Carhart four-factor attribution of the long-short returns (daily, HAC)
82
+ french = qf.load_french_factors("ff3_daily.csv", "momentum_daily.csv")
83
+ model = qf.carhart_attribution(daily[("my_reversal", 20)]["long_short"], french)
84
+ ```
85
+
86
+ ### Extension points
87
+
88
+ | Protocol / hook | Purpose | Ships with |
89
+ |---|---|---|
90
+ | `DataSource.load(...) -> MarketData` | plug in any price/volume source | `ParquetSource`, `CSVSource`, `ExcelSource`, `YFinanceSource` |
91
+ | `ConstituentsSource.get_constituents(date) -> set` | point-in-time universe from any provider | `MembershipTableSource` (interval table), `StaticUniverse` |
92
+ | `@factor_register(name)` | add factors; params injected by name, factor-on-factor dependencies resolved | 8 built-in factors |
93
+ | `config.example.yaml` | every pipeline parameter as validated dataclasses via `qf.load_configs` | defaults documented in-file |
94
+
95
+ ## Headline result (S&P 500 case study)
96
+
97
+ The 20-day average volume factor (`TwentyDayAvgVol`) is the only candidate
98
+ that survives the full testing gauntlet:
99
+
100
+ | Stage | Result |
101
+ |---|---|
102
+ | Train IC (2015–2023, Newey-West) | t = 3.78 (20d holding), passes Bonferroni & Benjamini-Hochberg across all 18 factor × horizon tests |
103
+ | Out-of-sample quintiles (2024–2026) | Monotonic (Spearman 0.9); long-short gross ~14 %/yr (Sharpe ~1.5), ~1.4 Sharpe net of turnover-based costs |
104
+ | Carhart 4-factor attribution (daily, HAC, net of costs) | Market beta 0.24 (significant), large-cap tilt (SMB −0.13); momentum & value loadings insignificant |
105
+ | Net alpha | ~10 %/yr net of costs (t = 1.78, p ≈ 0.07, n = 603 daily obs) — economically meaningful, **marginally short of the 5 % significance bar** on 2.4 years of out-of-sample data |
106
+
107
+ The honest conclusion: the factor's IC is robustly significant in-sample under
108
+ conservative testing; its out-of-sample net alpha is economically meaningful
109
+ but does not clear conventional significance. Live verification over a longer
110
+ window is required — and that is exactly what a research report should say.
111
+ (A low-power period-level regression, n ≈ 30, says nothing either way —
112
+ p ≈ 0.38 with a confidence interval wide enough to hold any conclusion. Test
113
+ power and test bookkeeping move the verdict as much as the signal does.)
114
+
115
+ The remaining seven candidate factors (momentum, short-term reversal,
116
+ volatility, downside volatility, volume-price correlation, …) fail the
117
+ corrected significance tests. Documenting *why* they fail is part of the
118
+ point.
119
+
120
+ ## Methodology highlights
121
+
122
+ - **Survivorship-bias correction** — the universe is rebuilt from historical
123
+ S&P 500 membership (764 tickers over 2015–2026); 569 were recoverable via
124
+ yfinance, and the residual gap is disclosed rather than hidden.
125
+ - **Point-in-time universe** — each backtest cross-section only contains
126
+ stocks that were actually index members on that date.
127
+ - **Newey-West IC tests** — daily ICs on overlapping k-day forward returns are
128
+ autocorrelated; plain `t = IR·√n` overstates significance several-fold. NW
129
+ (Bartlett kernel, lag = 2(k−1)) uses all daily observations while correcting
130
+ the standard error. A down-sampled IID test is kept as a robustness control.
131
+ - **Multiple-testing control** — Bonferroni and Benjamini-Hochberg across all
132
+ factor × holding-period combinations.
133
+ - **Train/test split with embargo** — factors are selected and the
134
+ orthogonalization is fit on 2015–2023 only; a gap of one month before the
135
+ test window prevents overlapping forward returns from leaking across the
136
+ split.
137
+ - **Expanding-window orthogonalization** — correlated factors are residualized
138
+ with betas estimated on data available up to each date (no full-sample
139
+ look-ahead).
140
+ - **Turnover-based transaction costs** — costs are charged on actual
141
+ membership turnover per rebalance, not on a flat 100 %-turnover assumption.
142
+ - **Sanity checks** — factor displacement and cross-sectional shuffling tests
143
+ confirm the backtest machinery itself is not the source of the returns.
144
+ - **Tested** — the research chain is covered by a unit + golden-value test
145
+ suite (`test/`), including hand-computed backtest fixtures, determinism
146
+ checks, and point-in-time universe edge cases.
147
+
148
+ ## Pipeline
149
+
150
+ ```
151
+ yfinance (batch download, retry, blacklist, checkpoints)
152
+ │ quantmine/data_acquisition.py · pipelines/task_1.py
153
+
154
+ cleaning & merge (ffill, dedup) Airflow DAG: pipelines/DAG_pipeline.py
155
+ │ pipelines/task_2.py
156
+
157
+ factor computation (registry-driven, vectorized pandas)
158
+ │ quantmine/factor_mining.py · pipelines/task_3.py
159
+
160
+ IC testing: cross-sectional & time-series IC, NW t, BH/Bonferroni,
161
+ train/test split, orthogonalization quantmine/ic_calculator.py
162
+
163
+ quintile backtest: PIT universe, monotonicity, turnover costs,
164
+ displacement/shuffle sanity tests quantmine/back_testing.py
165
+
166
+ Carhart 4-factor attribution (daily, HAC) quantmine/factor_attribution.py
167
+ ```
168
+
169
+ Repository layout:
170
+
171
+ ```
172
+ quantmine/ research library (importable package)
173
+ pipelines/ Airflow DAG + daily CLI tasks
174
+ test/ pytest suite (unit + golden-value)
175
+ config.example.yaml all pipeline parameters, documented defaults
176
+ ```
177
+
178
+ ## Reproducing the case study
179
+
180
+ **Market data is not included** (Yahoo Finance terms of service do not permit
181
+ redistribution). To reproduce:
182
+
183
+ 1. Historical S&P 500 membership: provide a CSV with `ticker`, `start_date`,
184
+ `end_date` columns and point `SP500_MEMBERSHIP_CSV` at it.
185
+ 2. Prices/volumes: `python pipelines/task_1.py --date <ds> --batch manual`
186
+ downloads in batches with checkpointing, then `pipelines/task_2.py` cleans
187
+ and merges.
188
+ 3. Fama-French factors: download the daily FF3 and momentum CSVs from the
189
+ [Ken French Data Library](https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html)
190
+ into `tmp/ff3/`.
191
+ 4. Run the research chain: `python pipelines/task_3.py ...` for factors, then
192
+ the IC → backtest → attribution steps as in the quick start (or
193
+ `python -m quantmine.ic_calculator` for the packaged train/test workflow).
194
+
195
+ For the Airflow DAG, set `QUANT_PROJECT_ROOT` and `QUANT_PYTHON_BIN` (see
196
+ `DAG_pipeline.py` docstring) and copy `airflow.cfg.example` keys into your own
197
+ config — never commit a real `airflow.cfg`.
198
+
199
+ ## Known limitations
200
+
201
+ - ~195 of 764 historical members could not be recovered from yfinance (mostly
202
+ true delistings/acquisitions), so a residual survivorship bias remains and
203
+ likely flatters the results slightly.
204
+ - The out-of-sample window (2024–2026) covers a single market regime.
205
+ - The long-short portfolio carries a significant 0.24 market beta; a
206
+ beta-hedged variant is on the roadmap.
207
+ - Transaction cost model is a flat per-turnover rate; no market-impact or
208
+ borrow-cost modeling.
209
+
210
+ ## Roadmap
211
+
212
+ - [ ] Migrate storage from parquet files to PostgreSQL/DuckDB
213
+ - [ ] REST API + MCP server exposing the research chain as agent-callable tools
214
+ - [ ] RAG-based automated research reports (ChromaDB + LLM)
215
+ - [ ] Extend the Airflow DAG to cover IC testing → backtest → reporting
216
+ - [ ] Rebuild the analytics dashboard (frontend rewrite in progress)
217
+ - [ ] Scale the data layer (full US market) with PySpark
218
+ - [ ] Beta-hedged long-short variant; GARCH volatility targeting
219
+
220
+ ## License
221
+
222
+ MIT
@@ -0,0 +1,14 @@
1
+ quantmine/__init__.py,sha256=jxKZ1GXRmvLT5ib3gdpifXl5B-f5S1-gEbuWtK3asFY,3352
2
+ quantmine/back_testing.py,sha256=4kpyJjnp9FsAxSYhgPRWUf5r2auhMNJuDQJFYOwTiC4,17344
3
+ quantmine/config.py,sha256=zBLyvfrvFgmMG8HRaIuJee2Bzt0WCvGhBo1jEiF-xU4,3596
4
+ quantmine/data_acquisition.py,sha256=KWc0ecjx6rDUvFdxb3UE14RI5fNHhKEbxg6LChQAlxA,13040
5
+ quantmine/datareader.py,sha256=soQg7IPWZlkkPnNqsS_eC2UHyGE_0b5VCirCxnKKKPU,4932
6
+ quantmine/factor_attribution.py,sha256=YuWLJVeJbkymTUugBzcI8IMgs7LYn9h570FXPQXWwTg,2967
7
+ quantmine/factor_mining.py,sha256=c4A7vANKLyXXwfyBXSmT_iwWfWGm5PpeTTM4miA__E0,7396
8
+ quantmine/factor_register.py,sha256=6ok5hz8sJ3nDTzZ3t9I-dRDGjf0uWRU7PllKFWmHApE,2706
9
+ quantmine/ic_calculator.py,sha256=i3LbgUAo8qKA50w_VyyJfbzZQlYPgnccgxOtd9cRSAg,24302
10
+ quantmine/load_config.py,sha256=NESNgRhvaSTDzvM-9Cdc5-5pyAPTitIgwNPFjDzfLXo,734
11
+ quantmine-0.2.0.dist-info/METADATA,sha256=b91o1yKSeA7PM2t36GgvxcA_R25q6BnnG99ZSMWQ_R8,10289
12
+ quantmine-0.2.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
13
+ quantmine-0.2.0.dist-info/licenses/LICENSE,sha256=85eZoHh_6k3x8ldYseHu6oNP-hYd4z-FFjjTbc9oTl0,1091
14
+ quantmine-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 b00831205-web
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.