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.
@@ -0,0 +1,15 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ .uv/
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ .mypy_cache/
11
+ .DS_Store
12
+ uv.lock
13
+
14
+ # Generated at build time from history/ and latest/ CSVs.
15
+ src/index_constitution/_data/
@@ -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)