index-constitution 0.1.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.
- index_constitution-0.1.0/.gitignore +15 -0
- index_constitution-0.1.0/LICENSE +21 -0
- index_constitution-0.1.0/PKG-INFO +103 -0
- index_constitution-0.1.0/README.md +62 -0
- index_constitution-0.1.0/README.zh.md +37 -0
- index_constitution-0.1.0/build_data.py +51 -0
- index_constitution-0.1.0/hatch_build.py +31 -0
- index_constitution-0.1.0/history/csi300.csv +1207 -0
- index_constitution-0.1.0/history/nasdaq100.csv +313 -0
- index_constitution-0.1.0/history/sp500.csv +895 -0
- index_constitution-0.1.0/latest/csi300.csv +301 -0
- index_constitution-0.1.0/latest/nasdaq100.csv +102 -0
- index_constitution-0.1.0/latest/sp500.csv +504 -0
- index_constitution-0.1.0/pyproject.toml +55 -0
- index_constitution-0.1.0/src/index_constitution/__init__.py +96 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 index-constitution contributors
|
|
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
|
|
13
|
+
all 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
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: index-constitution
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Point-in-time and current constituents for major stock indices (CSI 300, S&P 500, NASDAQ-100), packaged as pandas DataFrames.
|
|
5
|
+
Project-URL: Homepage, https://github.com/unliftedq/index-constitution
|
|
6
|
+
Project-URL: Repository, https://github.com/unliftedq/index-constitution
|
|
7
|
+
Author: index-constitution contributors
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2026 index-constitution contributors
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in
|
|
20
|
+
all copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
28
|
+
THE SOFTWARE.
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Keywords: backtesting,constituents,csi300,finance,index,nasdaq100,sp500,stocks
|
|
31
|
+
Classifier: Development Status :: 4 - Beta
|
|
32
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
33
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
34
|
+
Classifier: Operating System :: OS Independent
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
37
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
38
|
+
Requires-Python: >=3.9
|
|
39
|
+
Requires-Dist: pandas>=1.5
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
# Index Constitution
|
|
43
|
+
|
|
44
|
+
[中文](README.zh.md)
|
|
45
|
+
|
|
46
|
+
## Purpose
|
|
47
|
+
|
|
48
|
+
This repository was created to make it easier to train quantitative models on major stock indices. Reliable historical index composition data (constituent additions and removals over time) is notoriously hard to obtain — vendors often charge for it, official sources are scattered across PDFs and announcements, and free APIs rarely expose point-in-time membership. Without this data, backtests suffer from survivorship bias and lookahead bias.
|
|
49
|
+
|
|
50
|
+
This repo collects and normalizes that information into plain CSV files so it can be consumed directly by research and modeling pipelines.
|
|
51
|
+
|
|
52
|
+
## Datasets
|
|
53
|
+
|
|
54
|
+
| Index | Description | Source |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| CSI 300 | Top 300 A-share stocks listed on the Shanghai and Shenzhen exchanges | Official announcements from China Securities Index Co. (csindex.com.cn) |
|
|
57
|
+
| S&P 500 | 500 leading large-cap U.S. companies listed on U.S. exchanges | [Wikipedia: List of S&P 500 companies](https://en.wikipedia.org/wiki/List_of_S%26P_500_companies) |
|
|
58
|
+
| NASDAQ-100 | 100 largest non-financial companies listed on the Nasdaq Stock Market | [Wikipedia: NASDAQ-100](https://en.wikipedia.org/wiki/Nasdaq-100) |
|
|
59
|
+
|
|
60
|
+
## Structure
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
src/index_constitution/_data/
|
|
64
|
+
history/
|
|
65
|
+
csi300.csv
|
|
66
|
+
nasdaq100.csv
|
|
67
|
+
sp500.csv
|
|
68
|
+
latest/
|
|
69
|
+
csi300.csv
|
|
70
|
+
nasdaq100.csv
|
|
71
|
+
sp500.csv
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Python package
|
|
75
|
+
|
|
76
|
+
This repo also ships a small Python library that embeds the CSVs and exposes
|
|
77
|
+
them as pandas DataFrames.
|
|
78
|
+
|
|
79
|
+
Install:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pip install index-constitution
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Usage:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
import index_constitution as ic
|
|
89
|
+
|
|
90
|
+
ic.list_indices() # ['csi300', 'sp500', 'nasdaq100']
|
|
91
|
+
|
|
92
|
+
ic.latest("sp500") # current S&P 500 members
|
|
93
|
+
ic.history("csi300") # full CSI 300 history with opt-in/opt-out
|
|
94
|
+
ic.constituents_at("sp500", "2015-06-30") # point-in-time membership
|
|
95
|
+
ic.is_member("sp500", "AAPL", "2020-01-02") # True
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Use Cases
|
|
99
|
+
|
|
100
|
+
- Check the current constituents of an index
|
|
101
|
+
- Reconstruct point-in-time index membership for backtesting
|
|
102
|
+
- Avoid survivorship bias when training quantitative models
|
|
103
|
+
- Keep a consistent structure for adding more indices later
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Index Constitution
|
|
2
|
+
|
|
3
|
+
[中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
This repository was created to make it easier to train quantitative models on major stock indices. Reliable historical index composition data (constituent additions and removals over time) is notoriously hard to obtain — vendors often charge for it, official sources are scattered across PDFs and announcements, and free APIs rarely expose point-in-time membership. Without this data, backtests suffer from survivorship bias and lookahead bias.
|
|
8
|
+
|
|
9
|
+
This repo collects and normalizes that information into plain CSV files so it can be consumed directly by research and modeling pipelines.
|
|
10
|
+
|
|
11
|
+
## Datasets
|
|
12
|
+
|
|
13
|
+
| Index | Description | Source |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| CSI 300 | Top 300 A-share stocks listed on the Shanghai and Shenzhen exchanges | Official announcements from China Securities Index Co. (csindex.com.cn) |
|
|
16
|
+
| S&P 500 | 500 leading large-cap U.S. companies listed on U.S. exchanges | [Wikipedia: List of S&P 500 companies](https://en.wikipedia.org/wiki/List_of_S%26P_500_companies) |
|
|
17
|
+
| NASDAQ-100 | 100 largest non-financial companies listed on the Nasdaq Stock Market | [Wikipedia: NASDAQ-100](https://en.wikipedia.org/wiki/Nasdaq-100) |
|
|
18
|
+
|
|
19
|
+
## Structure
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
src/index_constitution/_data/
|
|
23
|
+
history/
|
|
24
|
+
csi300.csv
|
|
25
|
+
nasdaq100.csv
|
|
26
|
+
sp500.csv
|
|
27
|
+
latest/
|
|
28
|
+
csi300.csv
|
|
29
|
+
nasdaq100.csv
|
|
30
|
+
sp500.csv
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Python package
|
|
34
|
+
|
|
35
|
+
This repo also ships a small Python library that embeds the CSVs and exposes
|
|
36
|
+
them as pandas DataFrames.
|
|
37
|
+
|
|
38
|
+
Install:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install index-constitution
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Usage:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
import index_constitution as ic
|
|
48
|
+
|
|
49
|
+
ic.list_indices() # ['csi300', 'sp500', 'nasdaq100']
|
|
50
|
+
|
|
51
|
+
ic.latest("sp500") # current S&P 500 members
|
|
52
|
+
ic.history("csi300") # full CSI 300 history with opt-in/opt-out
|
|
53
|
+
ic.constituents_at("sp500", "2015-06-30") # point-in-time membership
|
|
54
|
+
ic.is_member("sp500", "AAPL", "2020-01-02") # True
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Use Cases
|
|
58
|
+
|
|
59
|
+
- Check the current constituents of an index
|
|
60
|
+
- Reconstruct point-in-time index membership for backtesting
|
|
61
|
+
- Avoid survivorship bias when training quantitative models
|
|
62
|
+
- Keep a consistent structure for adding more indices later
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Index Constitution
|
|
2
|
+
|
|
3
|
+
[English](README.md)
|
|
4
|
+
|
|
5
|
+
## 项目目的
|
|
6
|
+
|
|
7
|
+
本仓库的初衷是为训练量化模型提供方便、可靠的指数成分股数据。可靠的指数历史仓位(即各时点的成分纳入与剔除记录)通常很难获取——商业数据厂商往往收费昂贵,官方来源分散在各类 PDF 和公告中,免费 API 也极少提供按时点回溯的成分股名单。缺少这类数据,量化回测就容易受到幸存者偏差和前视偏差的影响。
|
|
8
|
+
|
|
9
|
+
本仓库将这些信息整理为统一格式的 CSV 文件,方便研究和建模流程直接使用。
|
|
10
|
+
|
|
11
|
+
## 数据说明
|
|
12
|
+
|
|
13
|
+
| 指数 | 说明 | 来源 |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| 沪深 300 | 沪深两市规模最大、流动性最好的 300 只 A 股 | 中证指数有限公司官方公告(csindex.com.cn) |
|
|
16
|
+
| 标普 500 | 美股市场 500 家大型上市公司 | [维基百科:List of S&P 500 companies](https://en.wikipedia.org/wiki/List_of_S%26P_500_companies) |
|
|
17
|
+
| 纳斯达克 100 | 纳斯达克交易所 100 家最大的非金融上市公司 | [维基百科:NASDAQ-100](https://en.wikipedia.org/wiki/Nasdaq-100) |
|
|
18
|
+
|
|
19
|
+
## 目录结构
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
history/
|
|
23
|
+
csi300.csv
|
|
24
|
+
nasdaq100.csv
|
|
25
|
+
sp500.csv
|
|
26
|
+
latest/
|
|
27
|
+
csi300.csv
|
|
28
|
+
nasdaq100.csv
|
|
29
|
+
sp500.csv
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 使用场景
|
|
33
|
+
|
|
34
|
+
- 查询主要股指的当前成分股名单
|
|
35
|
+
- 还原任意时点的指数成分,用于量化回测
|
|
36
|
+
- 在训练量化模型时规避幸存者偏差
|
|
37
|
+
- 为后续扩展更多指数成分数据提供统一结构
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Convert top-level CSVs into pickled DataFrames embedded in the package.
|
|
2
|
+
|
|
3
|
+
Used both by the Hatch build hook (during ``uv build`` / ``pip install``) and
|
|
4
|
+
by the test suite (via ``conftest.py``) to materialize ``_data/*.pkl`` files
|
|
5
|
+
inside the installed package.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
import pandas as pd
|
|
13
|
+
|
|
14
|
+
INDICES = ("csi300", "sp500", "nasdaq100")
|
|
15
|
+
FLAVORS = ("latest", "history")
|
|
16
|
+
PKL_PROTOCOL = 4 # readable by Python 3.4+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _load_csv(csv_path: Path) -> pd.DataFrame:
|
|
20
|
+
df = pd.read_csv(csv_path)
|
|
21
|
+
for col in ("opt-in", "opt-out"):
|
|
22
|
+
if col in df.columns:
|
|
23
|
+
df[col] = pd.to_datetime(df[col], errors="coerce")
|
|
24
|
+
return df
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def build_pickles(project_root: Path, out_dir: Path) -> list[Path]:
|
|
28
|
+
"""Read CSVs from ``project_root/{flavor}/{index}.csv`` and write pickles
|
|
29
|
+
to ``out_dir/{flavor}/{index}.pkl``. Returns the list of written paths.
|
|
30
|
+
"""
|
|
31
|
+
written: list[Path] = []
|
|
32
|
+
for flavor in FLAVORS:
|
|
33
|
+
flavor_out = out_dir / flavor
|
|
34
|
+
flavor_out.mkdir(parents=True, exist_ok=True)
|
|
35
|
+
for index in INDICES:
|
|
36
|
+
csv_path = project_root / flavor / f"{index}.csv"
|
|
37
|
+
if not csv_path.exists():
|
|
38
|
+
raise FileNotFoundError(f"Missing source CSV: {csv_path}")
|
|
39
|
+
df = _load_csv(csv_path)
|
|
40
|
+
pkl_path = flavor_out / f"{index}.pkl"
|
|
41
|
+
df.to_pickle(pkl_path, protocol=PKL_PROTOCOL)
|
|
42
|
+
written.append(pkl_path)
|
|
43
|
+
return written
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if __name__ == "__main__":
|
|
47
|
+
root = Path(__file__).resolve().parent
|
|
48
|
+
out = root / "src" / "index_constitution" / "_data"
|
|
49
|
+
paths = build_pickles(root, out)
|
|
50
|
+
for p in paths:
|
|
51
|
+
print(p.relative_to(root))
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Hatch custom build hook: regenerate embedded pickle data from top-level CSVs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PickleDataBuildHook(BuildHookInterface):
|
|
12
|
+
PLUGIN_NAME = "pickle-data"
|
|
13
|
+
|
|
14
|
+
def initialize(self, version: str, build_data: dict) -> None: # noqa: D401
|
|
15
|
+
root = Path(self.root)
|
|
16
|
+
# Make build_data.py importable without polluting sys.path globally.
|
|
17
|
+
sys.path.insert(0, str(root))
|
|
18
|
+
try:
|
|
19
|
+
from build_data import build_pickles # type: ignore
|
|
20
|
+
finally:
|
|
21
|
+
sys.path.pop(0)
|
|
22
|
+
|
|
23
|
+
out_dir = root / "src" / "index_constitution" / "_data"
|
|
24
|
+
written = build_pickles(root, out_dir)
|
|
25
|
+
|
|
26
|
+
# Force-include each generated pickle into the wheel under the package.
|
|
27
|
+
force_include = build_data.setdefault("force_include", {})
|
|
28
|
+
pkg_prefix = Path("index_constitution") / "_data"
|
|
29
|
+
for pkl in written:
|
|
30
|
+
rel = pkl.relative_to(out_dir)
|
|
31
|
+
force_include[str(pkl)] = str(pkg_prefix / rel)
|