index-constitution 0.1.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,96 @@
1
+ """Index Constitution: point-in-time constituents for major stock indices.
2
+
3
+ Embedded datasets:
4
+
5
+ - ``csi300`` — CSI 300 (Shanghai/Shenzhen)
6
+ - ``sp500`` — S&P 500
7
+ - ``nasdaq100`` — NASDAQ-100
8
+
9
+ Two flavors per index:
10
+
11
+ - ``latest`` — current members (columns: ``symbol``, ``name``, ``opt-in``)
12
+ - ``history`` — full history (columns: ``symbol``, ``name``, ``opt-in``,
13
+ ``opt-out``; an empty ``opt-out`` means still a member)
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from datetime import date, datetime
19
+ from importlib.resources import files
20
+ from typing import Iterable, Literal, Union
21
+
22
+ import pandas as pd
23
+
24
+ __all__ = [
25
+ "INDICES",
26
+ "list_indices",
27
+ "load",
28
+ "latest",
29
+ "history",
30
+ "constituents_at",
31
+ "is_member",
32
+ "__version__",
33
+ ]
34
+
35
+ __version__ = "0.1.0"
36
+
37
+ INDICES: tuple[str, ...] = ("csi300", "sp500", "nasdaq100")
38
+
39
+ Flavor = Literal["latest", "history"]
40
+ DateLike = Union[str, date, datetime, pd.Timestamp]
41
+
42
+
43
+ def list_indices() -> list[str]:
44
+ """Return the names of all embedded indices."""
45
+ return list(INDICES)
46
+
47
+
48
+ def _resource_path(flavor: Flavor, index: str):
49
+ if index not in INDICES:
50
+ raise ValueError(
51
+ f"Unknown index {index!r}. Available: {', '.join(INDICES)}"
52
+ )
53
+ if flavor not in ("latest", "history"):
54
+ raise ValueError(f"flavor must be 'latest' or 'history', got {flavor!r}")
55
+ return files(__package__).joinpath("_data", flavor, f"{index}.pkl")
56
+
57
+
58
+ def load(index: str, flavor: Flavor = "latest") -> pd.DataFrame:
59
+ """Load an embedded dataset as a pandas DataFrame.
60
+
61
+ Data is stored as pickled DataFrames for fast load times; date columns
62
+ are already parsed to ``datetime64[ns]``.
63
+ """
64
+ path = _resource_path(flavor, index)
65
+ with path.open("rb") as fh:
66
+ return pd.read_pickle(fh)
67
+
68
+
69
+ def latest(index: str) -> pd.DataFrame:
70
+ """Shortcut for ``load(index, 'latest')``."""
71
+ return load(index, "latest")
72
+
73
+
74
+ def history(index: str) -> pd.DataFrame:
75
+ """Shortcut for ``load(index, 'history')``."""
76
+ return load(index, "history")
77
+
78
+
79
+ def constituents_at(index: str, when: DateLike) -> pd.DataFrame:
80
+ """Return constituents that were members of ``index`` on date ``when``.
81
+
82
+ A row qualifies if ``opt-in <= when`` and (``opt-out`` is missing
83
+ or ``opt-out > when``).
84
+ """
85
+ ts = pd.Timestamp(when).normalize()
86
+ df = history(index)
87
+ opt_in = df["opt-in"]
88
+ opt_out = df["opt-out"]
89
+ mask = (opt_in <= ts) & (opt_out.isna() | (opt_out > ts))
90
+ return df.loc[mask].reset_index(drop=True)
91
+
92
+
93
+ def is_member(index: str, symbol: str, when: DateLike) -> bool:
94
+ """Return True if ``symbol`` was a constituent of ``index`` on ``when``."""
95
+ members = constituents_at(index, when)
96
+ return bool((members["symbol"] == symbol).any())
@@ -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,11 @@
1
+ index_constitution/__init__.py,sha256=ozgvknzlAGUJIQHpBm2dC3P7rFvG-YS38Bprp2jGHHM,2775
2
+ index_constitution/_data/history/csi300.pkl,sha256=_TEuO-PNtiLPlQOdPSkiFT1ByRVAcZzlUv24jtyzJ8w,47001
3
+ index_constitution/_data/history/nasdaq100.pkl,sha256=TlpbvsodIrDf_t8Wh2cTKwbqMncxUmoUSLoCRZXESjE,14334
4
+ index_constitution/_data/history/sp500.pkl,sha256=2fXPvI3t05en5zby_oXYTsAxh31R5XFZGbPPxbgCkTQ,36099
5
+ index_constitution/_data/latest/csi300.pkl,sha256=stUmtQhuM03JnTPDCRs5M1UbLDmr5Yj7Xb6p1_B7HJQ,11210
6
+ index_constitution/_data/latest/nasdaq100.pkl,sha256=y_uuGX-IIFiujNUM5X9Kad_4lD5765MSe2BhDAXdF44,5335
7
+ index_constitution/_data/latest/sp500.pkl,sha256=NjM2kgSvmVNOwCkFj5XpT8hh-Ln1_keIpc-o9pO9wTI,16876
8
+ index_constitution-0.1.0.dist-info/METADATA,sha256=uOqq0ci_wsZN0exi0Am8Se881rKfRXggnm3o-71rZVo,4417
9
+ index_constitution-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
10
+ index_constitution-0.1.0.dist-info/licenses/LICENSE,sha256=ffs1GQGu1iypwPkD_EmimyMCili8lSwePsfyWTde-4k,1088
11
+ index_constitution-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -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.