powernse 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.
Files changed (43) hide show
  1. powernse-0.1.0/LICENSE +21 -0
  2. powernse-0.1.0/PKG-INFO +175 -0
  3. powernse-0.1.0/README.md +142 -0
  4. powernse-0.1.0/pyproject.toml +87 -0
  5. powernse-0.1.0/pyproject.toml.orig +73 -0
  6. powernse-0.1.0/src/powernse/__init__.py +60 -0
  7. powernse-0.1.0/src/powernse/__main__.py +6 -0
  8. powernse-0.1.0/src/powernse/adjust.py +100 -0
  9. powernse-0.1.0/src/powernse/archive/__init__.py +39 -0
  10. powernse-0.1.0/src/powernse/archive/layout.py +106 -0
  11. powernse-0.1.0/src/powernse/archive/manifest.py +68 -0
  12. powernse-0.1.0/src/powernse/archive/zipcsv.py +32 -0
  13. powernse-0.1.0/src/powernse/bundle.py +148 -0
  14. powernse-0.1.0/src/powernse/calendar.py +69 -0
  15. powernse-0.1.0/src/powernse/cli/__init__.py +5 -0
  16. powernse-0.1.0/src/powernse/cli/app.py +76 -0
  17. powernse-0.1.0/src/powernse/cli/bundle_cmd.py +41 -0
  18. powernse-0.1.0/src/powernse/cli/common.py +58 -0
  19. powernse-0.1.0/src/powernse/cli/dated.py +70 -0
  20. powernse-0.1.0/src/powernse/cli/read.py +159 -0
  21. powernse-0.1.0/src/powernse/cli/snapshots.py +126 -0
  22. powernse-0.1.0/src/powernse/constants.py +27 -0
  23. powernse-0.1.0/src/powernse/data.py +430 -0
  24. powernse-0.1.0/src/powernse/downloaders/__init__.py +85 -0
  25. powernse-0.1.0/src/powernse/downloaders/base.py +77 -0
  26. powernse-0.1.0/src/powernse/downloaders/bhavcopy.py +108 -0
  27. powernse-0.1.0/src/powernse/downloaders/corporate_actions.py +159 -0
  28. powernse-0.1.0/src/powernse/downloaders/dated.py +95 -0
  29. powernse-0.1.0/src/powernse/downloaders/deals.py +110 -0
  30. powernse-0.1.0/src/powernse/downloaders/fo_bhavcopy.py +93 -0
  31. powernse-0.1.0/src/powernse/downloaders/full_bhavcopy.py +77 -0
  32. powernse-0.1.0/src/powernse/downloaders/index_closes.py +77 -0
  33. powernse-0.1.0/src/powernse/downloaders/index_constituents.py +150 -0
  34. powernse-0.1.0/src/powernse/downloaders/resume.py +55 -0
  35. powernse-0.1.0/src/powernse/errors.py +17 -0
  36. powernse-0.1.0/src/powernse/http/__init__.py +5 -0
  37. powernse-0.1.0/src/powernse/http/client.py +151 -0
  38. powernse-0.1.0/src/powernse/loaders.py +8 -0
  39. powernse-0.1.0/src/powernse/parsers/__init__.py +5 -0
  40. powernse-0.1.0/src/powernse/parsers/rows.py +185 -0
  41. powernse-0.1.0/src/powernse/py.typed +0 -0
  42. powernse-0.1.0/src/powernse/settings.py +89 -0
  43. powernse-0.1.0/src/powernse/types.py +88 -0
powernse-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PowerNSE 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 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.
@@ -0,0 +1,175 @@
1
+ Metadata-Version: 2.4
2
+ Name: powernse
3
+ Version: 0.1.0
4
+ Summary: Download and use official NSE India equity archives via CLI and Python
5
+ Keywords: nse,india,bhavcopy,equities,market-data,download
6
+ Author: Vishal Mishra
7
+ Author-email: Vishal Mishra <vishal.k.mishra2@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Financial and Insurance Industry
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Office/Business :: Financial :: Investment
17
+ Classifier: Typing :: Typed
18
+ Requires-Dist: exchange-calendars>=4.5
19
+ Requires-Dist: filelock>=3.32
20
+ Requires-Dist: pydantic-settings>=2.15
21
+ Requires-Dist: requests>=2.32
22
+ Requires-Dist: tenacity>=9.0
23
+ Requires-Dist: typer>=0.27
24
+ Requires-Dist: pandas>=2.2 ; extra == 'pandas'
25
+ Requires-Python: >=3.13
26
+ Project-URL: Homepage, https://inquilabee.github.io/powernse/
27
+ Project-URL: Documentation, https://inquilabee.github.io/powernse/
28
+ Project-URL: Repository, https://github.com/inquilabee/powernse
29
+ Project-URL: Issues, https://github.com/inquilabee/powernse/issues
30
+ Project-URL: Changelog, https://github.com/inquilabee/powernse/blob/main/CHANGELOG.md
31
+ Provides-Extra: pandas
32
+ Description-Content-Type: text/markdown
33
+
34
+ <p align="center">
35
+ <a href="https://pypi.org/project/powernse/"><img src="https://img.shields.io/pypi/v/powernse.svg" alt="PyPI version"/></a>
36
+ <a href="https://pypi.org/project/powernse/"><img src="https://img.shields.io/pypi/pyversions/powernse.svg" alt="Python versions"/></a>
37
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"/></a>
38
+ <a href="https://inquilabee.github.io/powernse/"><img src="https://img.shields.io/badge/docs-GitHub%20Pages-blue" alt="Documentation"/></a>
39
+ </p>
40
+
41
+ <p align="center">
42
+ <strong>Official NSE India archives on disk. One CLI. A small Python API.</strong><br/>
43
+ Bhavcopy, F&amp;O, indexes, deals, corporate actions — downloaded from the exchange,
44
+ not scraped from a third-party dump.
45
+ </p>
46
+
47
+ <p align="center">
48
+ <a href="https://inquilabee.github.io/powernse/">Docs</a> ·
49
+ <a href="https://inquilabee.github.io/powernse/user/quickstart/">Quick start</a> ·
50
+ <a href="https://pypi.org/project/powernse/">PyPI</a> ·
51
+ <a href="CHANGELOG.md">Changelog</a>
52
+ </p>
53
+
54
+ ______________________________________________________________________
55
+
56
+ NSE publishes end-of-day files. The URLs move, the session cookie is picky, and
57
+ nobody wants to re-learn the layout every quarter. **PowerNSE** stages those
58
+ archives under a local `nse-data/` tree, keeps a download manifest, and lets you
59
+ query OHLC from the CLI or from Python.
60
+
61
+ Need a ready-made tree? `powernse fetch-bundle` pulls the tracked `nse-data/` from
62
+ this GitHub repo. Prefer building it yourself? Point the downloaders at NSE.
63
+
64
+ Python **3.13+**.
65
+
66
+ ## Install
67
+
68
+ ```bash
69
+ pip install powernse
70
+ pip install 'powernse[pandas]' # optional DataFrame helpers
71
+ ```
72
+
73
+ ## Quick start
74
+
75
+ ```bash
76
+ powernse bhavcopy --resume
77
+ powernse fo-bhavcopy --resume --days 30
78
+ powernse index-closes --from 2024-08-01 --to 2024-08-05
79
+ powernse fetch-bundle --force # optional: GitHub-hosted archive
80
+ powernse status
81
+ powernse ohlc RELIANCE --from 2024-08-01 --to 2024-08-05
82
+ powernse doctor
83
+ ```
84
+
85
+ ```python
86
+ from datetime import date
87
+ from powernse import BhavcopyDownloader, NSEData
88
+
89
+ BhavcopyDownloader("./nse-data").download_range(date(2024, 8, 1), date(2024, 8, 5))
90
+ data = NSEData("./nse-data")
91
+ bars = data.ohlc("RELIANCE", from_date=date(2024, 8, 1), to_date=date(2024, 8, 5))
92
+ ```
93
+
94
+ Full walkthrough: [docs site quickstart](https://inquilabee.github.io/powernse/user/quickstart/).
95
+
96
+ ## What you get
97
+
98
+ | Surface | Covers |
99
+ | --- | --- |
100
+ | Cash / F&O / full bhavcopy | Daily equity and derivatives archives |
101
+ | Index closes & constituents | Index levels and membership snapshots |
102
+ | Bulk / block deals, F&O ban | As-of snapshots |
103
+ | Corporate actions | JSON for adjustment helpers |
104
+ | `NSEData` / CLI | OHLC, coverage gaps, inventory, doctor |
105
+ | `fetch-bundle` | Zip extract of this repo's `nse-data/` |
106
+
107
+ Trading days use XBOM sessions when `exchange-calendars` covers the window
108
+ (from 2006-08-16). Earlier dates fall back to weekdays.
109
+
110
+ ## Archive layout
111
+
112
+ ```text
113
+ nse-data/
114
+ raw/bhavcopy/YYYY/YYYY-MM-DD.csv
115
+ raw/fo_bhavcopy/…
116
+ raw/full_bhavcopy/…
117
+ raw/index_closes/…
118
+ raw/bulk_deals/… raw/block_deals/… raw/fo_secban/…
119
+ raw/corporate_actions/YYYY/YYYY-MM-DD.json
120
+ raw/index_constituents/YYYY/YYYY-MM-DD_<index>.json
121
+ manifest/downloads.jsonl
122
+ ```
123
+
124
+ ## Etiquette
125
+
126
+ Requests are throttled and an NSE session cookie is primed first. Keep date
127
+ ranges modest; `--skip-existing` is on by default. Exchange URLs can change
128
+ without notice.
129
+
130
+ This project does **not** download or ingest Kaggle (or other third-party) dumps.
131
+ If you only need rough historical OHLCV for experiments, fetch those yourself —
132
+ PowerNSE sticks to official archives.
133
+
134
+ ## Disclaimer
135
+
136
+ PowerNSE is **not affiliated with, endorsed by, or connected to** the National
137
+ Stock Exchange of India (NSE) or any related entity. It is an unofficial tool
138
+ for **educational and research** use only — not financial advice, and not an
139
+ official data feed.
140
+
141
+ You are responsible for how you use the software and any data it retrieves,
142
+ including compliance with NSE terms of use. The author accepts **no liability**
143
+ for losses, damages, or other consequences arising from use of this package.
144
+ Use at your own risk.
145
+
146
+ Full text: [DISCLAIMER.md](DISCLAIMER.md).
147
+
148
+ ## Documentation
149
+
150
+ | Guide | Link |
151
+ | --- | --- |
152
+ | [Install](https://inquilabee.github.io/powernse/user/install/) | pip / uv / clone |
153
+ | [Quick start](https://inquilabee.github.io/powernse/user/quickstart/) | Download + query |
154
+ | [Archives](https://inquilabee.github.io/powernse/user/download/archives/) | Every downloader |
155
+ | [NSEData](https://inquilabee.github.io/powernse/user/python/nsedata/) | Python API |
156
+ | [fetch-bundle](https://inquilabee.github.io/powernse/user/bundle/fetch-bundle/) | GitHub zip extract |
157
+ | [Disclaimer](https://inquilabee.github.io/powernse/user/disclaimer/) | Unofficial · educational use |
158
+ | [Publish](https://inquilabee.github.io/powernse/maintainer/publish/) | Maintainer release |
159
+
160
+ ## Development
161
+
162
+ ```bash
163
+ uv sync
164
+ make check # ShipGate
165
+ make format
166
+ make test
167
+ make build
168
+ ```
169
+
170
+ Local docs: `uv run --with mkdocs-material mkdocs serve`. Quality gates:
171
+ [ShipGate](https://inquilabee.github.io/shipgate/) (`suite: standard`).
172
+
173
+ ## License
174
+
175
+ MIT — see [LICENSE](LICENSE). Also read [DISCLAIMER.md](DISCLAIMER.md).
@@ -0,0 +1,142 @@
1
+ <p align="center">
2
+ <a href="https://pypi.org/project/powernse/"><img src="https://img.shields.io/pypi/v/powernse.svg" alt="PyPI version"/></a>
3
+ <a href="https://pypi.org/project/powernse/"><img src="https://img.shields.io/pypi/pyversions/powernse.svg" alt="Python versions"/></a>
4
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"/></a>
5
+ <a href="https://inquilabee.github.io/powernse/"><img src="https://img.shields.io/badge/docs-GitHub%20Pages-blue" alt="Documentation"/></a>
6
+ </p>
7
+
8
+ <p align="center">
9
+ <strong>Official NSE India archives on disk. One CLI. A small Python API.</strong><br/>
10
+ Bhavcopy, F&amp;O, indexes, deals, corporate actions — downloaded from the exchange,
11
+ not scraped from a third-party dump.
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="https://inquilabee.github.io/powernse/">Docs</a> ·
16
+ <a href="https://inquilabee.github.io/powernse/user/quickstart/">Quick start</a> ·
17
+ <a href="https://pypi.org/project/powernse/">PyPI</a> ·
18
+ <a href="CHANGELOG.md">Changelog</a>
19
+ </p>
20
+
21
+ ______________________________________________________________________
22
+
23
+ NSE publishes end-of-day files. The URLs move, the session cookie is picky, and
24
+ nobody wants to re-learn the layout every quarter. **PowerNSE** stages those
25
+ archives under a local `nse-data/` tree, keeps a download manifest, and lets you
26
+ query OHLC from the CLI or from Python.
27
+
28
+ Need a ready-made tree? `powernse fetch-bundle` pulls the tracked `nse-data/` from
29
+ this GitHub repo. Prefer building it yourself? Point the downloaders at NSE.
30
+
31
+ Python **3.13+**.
32
+
33
+ ## Install
34
+
35
+ ```bash
36
+ pip install powernse
37
+ pip install 'powernse[pandas]' # optional DataFrame helpers
38
+ ```
39
+
40
+ ## Quick start
41
+
42
+ ```bash
43
+ powernse bhavcopy --resume
44
+ powernse fo-bhavcopy --resume --days 30
45
+ powernse index-closes --from 2024-08-01 --to 2024-08-05
46
+ powernse fetch-bundle --force # optional: GitHub-hosted archive
47
+ powernse status
48
+ powernse ohlc RELIANCE --from 2024-08-01 --to 2024-08-05
49
+ powernse doctor
50
+ ```
51
+
52
+ ```python
53
+ from datetime import date
54
+ from powernse import BhavcopyDownloader, NSEData
55
+
56
+ BhavcopyDownloader("./nse-data").download_range(date(2024, 8, 1), date(2024, 8, 5))
57
+ data = NSEData("./nse-data")
58
+ bars = data.ohlc("RELIANCE", from_date=date(2024, 8, 1), to_date=date(2024, 8, 5))
59
+ ```
60
+
61
+ Full walkthrough: [docs site quickstart](https://inquilabee.github.io/powernse/user/quickstart/).
62
+
63
+ ## What you get
64
+
65
+ | Surface | Covers |
66
+ | --- | --- |
67
+ | Cash / F&O / full bhavcopy | Daily equity and derivatives archives |
68
+ | Index closes & constituents | Index levels and membership snapshots |
69
+ | Bulk / block deals, F&O ban | As-of snapshots |
70
+ | Corporate actions | JSON for adjustment helpers |
71
+ | `NSEData` / CLI | OHLC, coverage gaps, inventory, doctor |
72
+ | `fetch-bundle` | Zip extract of this repo's `nse-data/` |
73
+
74
+ Trading days use XBOM sessions when `exchange-calendars` covers the window
75
+ (from 2006-08-16). Earlier dates fall back to weekdays.
76
+
77
+ ## Archive layout
78
+
79
+ ```text
80
+ nse-data/
81
+ raw/bhavcopy/YYYY/YYYY-MM-DD.csv
82
+ raw/fo_bhavcopy/…
83
+ raw/full_bhavcopy/…
84
+ raw/index_closes/…
85
+ raw/bulk_deals/… raw/block_deals/… raw/fo_secban/…
86
+ raw/corporate_actions/YYYY/YYYY-MM-DD.json
87
+ raw/index_constituents/YYYY/YYYY-MM-DD_<index>.json
88
+ manifest/downloads.jsonl
89
+ ```
90
+
91
+ ## Etiquette
92
+
93
+ Requests are throttled and an NSE session cookie is primed first. Keep date
94
+ ranges modest; `--skip-existing` is on by default. Exchange URLs can change
95
+ without notice.
96
+
97
+ This project does **not** download or ingest Kaggle (or other third-party) dumps.
98
+ If you only need rough historical OHLCV for experiments, fetch those yourself —
99
+ PowerNSE sticks to official archives.
100
+
101
+ ## Disclaimer
102
+
103
+ PowerNSE is **not affiliated with, endorsed by, or connected to** the National
104
+ Stock Exchange of India (NSE) or any related entity. It is an unofficial tool
105
+ for **educational and research** use only — not financial advice, and not an
106
+ official data feed.
107
+
108
+ You are responsible for how you use the software and any data it retrieves,
109
+ including compliance with NSE terms of use. The author accepts **no liability**
110
+ for losses, damages, or other consequences arising from use of this package.
111
+ Use at your own risk.
112
+
113
+ Full text: [DISCLAIMER.md](DISCLAIMER.md).
114
+
115
+ ## Documentation
116
+
117
+ | Guide | Link |
118
+ | --- | --- |
119
+ | [Install](https://inquilabee.github.io/powernse/user/install/) | pip / uv / clone |
120
+ | [Quick start](https://inquilabee.github.io/powernse/user/quickstart/) | Download + query |
121
+ | [Archives](https://inquilabee.github.io/powernse/user/download/archives/) | Every downloader |
122
+ | [NSEData](https://inquilabee.github.io/powernse/user/python/nsedata/) | Python API |
123
+ | [fetch-bundle](https://inquilabee.github.io/powernse/user/bundle/fetch-bundle/) | GitHub zip extract |
124
+ | [Disclaimer](https://inquilabee.github.io/powernse/user/disclaimer/) | Unofficial · educational use |
125
+ | [Publish](https://inquilabee.github.io/powernse/maintainer/publish/) | Maintainer release |
126
+
127
+ ## Development
128
+
129
+ ```bash
130
+ uv sync
131
+ make check # ShipGate
132
+ make format
133
+ make test
134
+ make build
135
+ ```
136
+
137
+ Local docs: `uv run --with mkdocs-material mkdocs serve`. Quality gates:
138
+ [ShipGate](https://inquilabee.github.io/shipgate/) (`suite: standard`).
139
+
140
+ ## License
141
+
142
+ MIT — see [LICENSE](LICENSE). Also read [DISCLAIMER.md](DISCLAIMER.md).
@@ -0,0 +1,87 @@
1
+ [project]
2
+ name = "powernse"
3
+ version = "0.1.0"
4
+ description = "Download and use official NSE India equity archives via CLI and Python"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ keywords = [
9
+ "nse",
10
+ "india",
11
+ "bhavcopy",
12
+ "equities",
13
+ "market-data",
14
+ "download",
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "Intended Audience :: Financial and Insurance Industry",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Topic :: Office/Business :: Financial :: Investment",
24
+ "Typing :: Typed",
25
+ ]
26
+ requires-python = ">=3.13"
27
+ dependencies = [
28
+ "exchange-calendars>=4.5",
29
+ "filelock>=3.32",
30
+ "pydantic-settings>=2.15",
31
+ "requests>=2.32",
32
+ "tenacity>=9.0",
33
+ "typer>=0.27",
34
+ ]
35
+
36
+ [[project.authors]]
37
+ name = "Vishal Mishra"
38
+ email = "vishal.k.mishra2@gmail.com"
39
+
40
+ [project.optional-dependencies]
41
+ pandas = ["pandas>=2.2"]
42
+
43
+ [project.scripts]
44
+ powernse = "powernse.cli:main"
45
+
46
+ [project.urls]
47
+ Homepage = "https://inquilabee.github.io/powernse/"
48
+ Documentation = "https://inquilabee.github.io/powernse/"
49
+ Repository = "https://github.com/inquilabee/powernse"
50
+ Issues = "https://github.com/inquilabee/powernse/issues"
51
+ Changelog = "https://github.com/inquilabee/powernse/blob/main/CHANGELOG.md"
52
+
53
+ [build-system]
54
+ requires = ["uv_build>=0.11.19,<0.12.0"]
55
+ build-backend = "uv_build"
56
+
57
+ [tool.uv]
58
+ default-groups = ["dev"]
59
+
60
+ [tool.ruff]
61
+ line-length = 120
62
+ target-version = "py313"
63
+
64
+ [tool.ruff.lint]
65
+ select = [
66
+ "B",
67
+ "E",
68
+ "F",
69
+ "I",
70
+ "UP",
71
+ ]
72
+
73
+ [tool.ruff.lint.per-file-ignores]
74
+ "src/powernse/__init__.py" = ["F401"]
75
+
76
+ [tool.pytest.ini_options]
77
+ testpaths = ["tests"]
78
+ addopts = ["-q"]
79
+ filterwarnings = ["error"]
80
+
81
+ [dependency-groups]
82
+ dev = [
83
+ "pandas>=2.2",
84
+ "pre-commit>=4.6",
85
+ "pytest>=8.3",
86
+ "shipgate>=0.1.11",
87
+ ]
@@ -0,0 +1,73 @@
1
+ [project]
2
+ name = "powernse"
3
+ version = "0.1.0"
4
+ description = "Download and use official NSE India equity archives via CLI and Python"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [
9
+ { name = "Vishal Mishra", email = "vishal.k.mishra2@gmail.com" },
10
+ ]
11
+ keywords = ["nse", "india", "bhavcopy", "equities", "market-data", "download"]
12
+ classifiers = [
13
+ "Development Status :: 4 - Beta",
14
+ "Environment :: Console",
15
+ "Intended Audience :: Developers",
16
+ "Intended Audience :: Financial and Insurance Industry",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Topic :: Office/Business :: Financial :: Investment",
20
+ "Typing :: Typed",
21
+ ]
22
+ requires-python = ">=3.13"
23
+ dependencies = [
24
+ "exchange-calendars>=4.5",
25
+ "filelock>=3.32",
26
+ "pydantic-settings>=2.15",
27
+ "requests>=2.32",
28
+ "tenacity>=9.0",
29
+ "typer>=0.27",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ pandas = ["pandas>=2.2"]
34
+
35
+ [project.scripts]
36
+ powernse = "powernse.cli:main"
37
+
38
+ [project.urls]
39
+ Homepage = "https://inquilabee.github.io/powernse/"
40
+ Documentation = "https://inquilabee.github.io/powernse/"
41
+ Repository = "https://github.com/inquilabee/powernse"
42
+ Issues = "https://github.com/inquilabee/powernse/issues"
43
+ Changelog = "https://github.com/inquilabee/powernse/blob/main/CHANGELOG.md"
44
+
45
+ [build-system]
46
+ requires = ["uv_build>=0.11.19,<0.12.0"]
47
+ build-backend = "uv_build"
48
+
49
+ [tool.uv]
50
+ default-groups = ["dev"]
51
+
52
+ [dependency-groups]
53
+ dev = [
54
+ "pandas>=2.2",
55
+ "pre-commit>=4.6",
56
+ "pytest>=8.3",
57
+ "shipgate>=0.1.11",
58
+ ]
59
+
60
+ [tool.ruff]
61
+ line-length = 120
62
+ target-version = "py313"
63
+
64
+ [tool.ruff.lint]
65
+ select = ["B", "E", "F", "I", "UP"]
66
+
67
+ [tool.pytest.ini_options]
68
+ testpaths = ["tests"]
69
+ addopts = ["-q"]
70
+ filterwarnings = ["error"]
71
+
72
+ [tool.ruff.lint.per-file-ignores]
73
+ "src/powernse/__init__.py" = ["F401"]
@@ -0,0 +1,60 @@
1
+ """PowerNSE — download and use official NSE India equity archives."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ from powernse.archive import ArchiveRoot
6
+ from powernse.calendar import iter_trading_dates
7
+ from powernse.data import NSEData
8
+ from powernse.downloaders import (
9
+ BhavcopyDownloader,
10
+ BlockDealsDownloader,
11
+ BulkDealsDownloader,
12
+ CorporateActionsDownloader,
13
+ FoBhavcopyDownloader,
14
+ FoSecbanDownloader,
15
+ FullBhavcopyDownloader,
16
+ IndexClosesDownloader,
17
+ IndexConstituentsDownloader,
18
+ bhavcopy_archive_url,
19
+ )
20
+ from powernse.errors import ArchiveError, DownloadError, PayloadError, PowerNseError
21
+ from powernse.loaders import ArchiveReader
22
+ from powernse.settings import Settings
23
+ from powernse.types import AdjustedOhlcBar, DownloadSummary, FoBar, IndexBar, OhlcBar
24
+
25
+ __all__ = [
26
+ "ArchiveError",
27
+ "ArchiveReader",
28
+ "ArchiveRoot",
29
+ "AdjustedOhlcBar",
30
+ "BhavcopyDownloader",
31
+ "BlockDealsDownloader",
32
+ "BulkDealsDownloader",
33
+ "CorporateActionsDownloader",
34
+ "DownloadError",
35
+ "DownloadSummary",
36
+ "FoBar",
37
+ "FoBhavcopyDownloader",
38
+ "FoSecbanDownloader",
39
+ "FullBhavcopyDownloader",
40
+ "IndexBar",
41
+ "IndexClosesDownloader",
42
+ "IndexConstituentsDownloader",
43
+ "NSEData",
44
+ "OhlcBar",
45
+ "PayloadError",
46
+ "PowerNseError",
47
+ "Settings",
48
+ "bhavcopy_archive_url",
49
+ "iter_trading_dates",
50
+ ]
51
+
52
+
53
+ def package_version() -> str:
54
+ try:
55
+ return version("powernse")
56
+ except PackageNotFoundError:
57
+ return "0.0.0+local"
58
+
59
+
60
+ __version__ = package_version()
@@ -0,0 +1,6 @@
1
+ """python -m powernse"""
2
+
3
+ from powernse.cli import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())
@@ -0,0 +1,100 @@
1
+ """Opt-in corporate-action adjustment helpers for equity OHLC."""
2
+
3
+ import re
4
+ from datetime import date
5
+
6
+ from powernse.downloaders.corporate_actions import parse_corporate_action_date
7
+ from powernse.types import AdjustedOhlcBar, OhlcBar
8
+
9
+ BONUS_RATIO = re.compile(r"bonus\s*(?:issue\s*)?(\d+)\s*:\s*(\d+)", re.IGNORECASE)
10
+ SPLIT_RATIO = re.compile(
11
+ r"(?:split|face\s*value\s*split).*?(\d+)\s*(?:for|:|/)\s*(\d+)",
12
+ re.IGNORECASE,
13
+ )
14
+ SPLIT_TO_FROM = re.compile(
15
+ r"face\s*value\s*split.*?from\s*(?:rs\.?\s*)?(\d+(?:\.\d+)?).*?to\s*(?:rs\.?\s*)?(\d+(?:\.\d+)?)",
16
+ re.IGNORECASE,
17
+ )
18
+
19
+
20
+ def price_adjustment_factor_from_subject(subject: str) -> float | None:
21
+ """Return a price divisor for a CA subject, or None when unrecognized.
22
+
23
+ Bonus ``A:B`` (A shares for B held) → factor ``(A+B)/B``.
24
+ Face-value from→to → ``old/new``. Split ``N for M`` → larger/smaller share multiple.
25
+ """
26
+ text = subject.strip()
27
+ if not text:
28
+ return None
29
+ bonus = BONUS_RATIO.search(text)
30
+ if bonus is not None:
31
+ bonus_shares = int(bonus.group(1))
32
+ held = int(bonus.group(2))
33
+ if held <= 0:
34
+ return None
35
+ return (bonus_shares + held) / held
36
+ face = SPLIT_TO_FROM.search(text)
37
+ if face is not None:
38
+ old_fv = float(face.group(1))
39
+ new_fv = float(face.group(2))
40
+ if new_fv <= 0:
41
+ return None
42
+ return old_fv / new_fv
43
+ split = SPLIT_RATIO.search(text)
44
+ if split is not None:
45
+ left = int(split.group(1))
46
+ right = int(split.group(2))
47
+ if left <= 0 or right <= 0:
48
+ return None
49
+ return max(left, right) / min(left, right)
50
+ return None
51
+
52
+
53
+ def corporate_action_price_events(records: list[dict[str, object]]) -> list[tuple[date, float]]:
54
+ """Extract ``(ex_date, price_divisor)`` pairs from corporate-action records."""
55
+ events: list[tuple[date, float]] = []
56
+ for record in records:
57
+ subject = str(record.get("subject") or record.get("SUBJECT") or "")
58
+ factor = price_adjustment_factor_from_subject(subject)
59
+ if factor is None or factor == 1.0:
60
+ continue
61
+ ex_date = parse_corporate_action_date(record)
62
+ if ex_date is None:
63
+ continue
64
+ events.append((ex_date, factor))
65
+ events.sort(key=lambda item: item[0])
66
+ return events
67
+
68
+
69
+ def apply_price_adjustments(bars: list[OhlcBar], events: list[tuple[date, float]]) -> list[AdjustedOhlcBar]:
70
+ """Apply cumulative CA factors so the newest bar keeps factor 1.0."""
71
+ if not bars:
72
+ return []
73
+ ordered = sorted(bars, key=lambda bar: bar.trade_date)
74
+ cumulative = 1.0
75
+ event_index = len(events) - 1
76
+ result_rev: list[AdjustedOhlcBar] = []
77
+ for i, bar in enumerate(reversed(ordered)):
78
+ newer = ordered[len(ordered) - i] if i > 0 else None
79
+ upper = newer.trade_date if newer is not None else date.max
80
+ while event_index >= 0 and bar.trade_date < events[event_index][0] <= upper:
81
+ cumulative *= events[event_index][1]
82
+ event_index -= 1
83
+ result_rev.append(
84
+ AdjustedOhlcBar(
85
+ trade_date=bar.trade_date,
86
+ symbol=bar.symbol,
87
+ series=bar.series,
88
+ open=bar.open / cumulative,
89
+ high=bar.high / cumulative,
90
+ low=bar.low / cumulative,
91
+ close=bar.close / cumulative,
92
+ volume=int(round(bar.volume * cumulative)),
93
+ factor=cumulative,
94
+ isin=bar.isin,
95
+ )
96
+ )
97
+ while event_index >= 0 and events[event_index][0] == bar.trade_date:
98
+ cumulative *= events[event_index][1]
99
+ event_index -= 1
100
+ return list(reversed(result_rev))