nepsepy 1.0.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.
- nepsepy-1.0.0/LICENSE +21 -0
- nepsepy-1.0.0/PKG-INFO +139 -0
- nepsepy-1.0.0/README.md +116 -0
- nepsepy-1.0.0/nepsepy/__init__.py +18 -0
- nepsepy-1.0.0/nepsepy/_company.py +115 -0
- nepsepy-1.0.0/nepsepy/_market.py +101 -0
- nepsepy-1.0.0/nepsepy/_news.py +167 -0
- nepsepy-1.0.0/nepsepy/_prices.py +101 -0
- nepsepy-1.0.0/nepsepy/_securities.py +111 -0
- nepsepy-1.0.0/nepsepy/auth.py +69 -0
- nepsepy-1.0.0/nepsepy/checksum.py +80 -0
- nepsepy-1.0.0/nepsepy/client.py +288 -0
- nepsepy-1.0.0/nepsepy/exceptions.py +43 -0
- nepsepy-1.0.0/nepsepy/wasm.py +136 -0
- nepsepy-1.0.0/nepsepy.egg-info/PKG-INFO +139 -0
- nepsepy-1.0.0/nepsepy.egg-info/SOURCES.txt +20 -0
- nepsepy-1.0.0/nepsepy.egg-info/dependency_links.txt +1 -0
- nepsepy-1.0.0/nepsepy.egg-info/requires.txt +5 -0
- nepsepy-1.0.0/nepsepy.egg-info/top_level.txt +1 -0
- nepsepy-1.0.0/pyproject.toml +35 -0
- nepsepy-1.0.0/setup.cfg +4 -0
- nepsepy-1.0.0/tests/test_client.py +584 -0
nepsepy-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nepsepy 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.
|
nepsepy-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nepsepy
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Unofficial Python client for public Nepal Stock Exchange market data
|
|
5
|
+
Author: nepsepy contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: httpx>=0.27
|
|
19
|
+
Requires-Dist: wasmtime>=12
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# nepsepy
|
|
25
|
+
|
|
26
|
+

|
|
27
|
+
|
|
28
|
+
[](https://pypi.org/project/nepsepy/)
|
|
29
|
+
[](https://pypi.org/project/nepsepy/)
|
|
30
|
+
[](https://github.com/menaceXnadin/nepsepy/actions/workflows/tests.yml)
|
|
31
|
+
[](LICENSE)
|
|
32
|
+
|
|
33
|
+
> A clean Python interface for public Nepal Stock Exchange (NEPSE) market data.
|
|
34
|
+
|
|
35
|
+
`nepsepy` provides a small, synchronous API for market status, prices, floor
|
|
36
|
+
sheets, indices, company information, notices, and other data used by the
|
|
37
|
+
NEPSE website.
|
|
38
|
+
|
|
39
|
+
It is not affiliated with the Nepal Stock Exchange.
|
|
40
|
+
|
|
41
|
+
## Why nepsepy?
|
|
42
|
+
|
|
43
|
+
- **Simple API** — use named methods such as `today_price()` and
|
|
44
|
+
`security_profile()` instead of manually assembling HTTP requests.
|
|
45
|
+
- **Public session handling** — performs the same login-free bootstrap used by
|
|
46
|
+
the NEPSE frontend; no user credentials are needed.
|
|
47
|
+
- **Careful by default** — requests are paced, token values are kept in memory,
|
|
48
|
+
and rate limiting is surfaced clearly instead of retried aggressively.
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
Requires Python 3.10 or later.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
python -m pip install nepsepy
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The PyPI distribution and Python import package are both named `nepsepy`.
|
|
59
|
+
|
|
60
|
+
## Quick start
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from nepsepy import NepseClient
|
|
64
|
+
|
|
65
|
+
with NepseClient() as client:
|
|
66
|
+
status = client.market_status()
|
|
67
|
+
gainers = client.top_gainers()
|
|
68
|
+
prices = client.today_price(page=1, size=20)
|
|
69
|
+
|
|
70
|
+
print(status["isOpen"])
|
|
71
|
+
print(gainers[:3])
|
|
72
|
+
print(prices["content"][:3])
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Most methods return the JSON object or list supplied by NEPSE. Pagination uses
|
|
76
|
+
1-based page numbers, matching the website UI. Dates use `yyyy-MM-dd`.
|
|
77
|
+
|
|
78
|
+
## Features
|
|
79
|
+
|
|
80
|
+
| Area | Included data |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| Market | Status, summaries, live market data, ticker, and top-ten lists |
|
|
83
|
+
| Prices & trades | Today’s prices, floor sheets, depth, supply/demand, and trade history |
|
|
84
|
+
| Charts | NEPSE indices, index history, and market/company chart data |
|
|
85
|
+
| Companies | Profiles, corporate actions, financial reports, dividends, AGMs, and news |
|
|
86
|
+
| Directories | Companies, sectors, share groups, promoters, brokers, and dealers |
|
|
87
|
+
| News & files | Notices, disclosures, holidays, reports, events, CSV exports, and downloads |
|
|
88
|
+
|
|
89
|
+
## Authentication and rate limits
|
|
90
|
+
|
|
91
|
+
No account credentials are required. `NepseClient` performs the same public
|
|
92
|
+
session bootstrap used by NEPSE’s frontend when it is first needed. Session
|
|
93
|
+
tokens stay in memory and are redacted from package diagnostics.
|
|
94
|
+
|
|
95
|
+
Requests are paced conservatively. A `429 Too Many Requests` response raises
|
|
96
|
+
`RateLimitedError`; the client does not retry in a loop.
|
|
97
|
+
|
|
98
|
+
## Common examples
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from nepsepy import NepseClient
|
|
102
|
+
|
|
103
|
+
with NepseClient() as client:
|
|
104
|
+
# Use numeric security IDs; resolve them from companies() or securities().
|
|
105
|
+
companies = client.companies()
|
|
106
|
+
barun = next(row for row in companies if row["symbol"] == "BARUN")
|
|
107
|
+
|
|
108
|
+
profile = client.security_profile(barun["id"])
|
|
109
|
+
floorsheet = client.floorsheets(stock_id=barun["id"])
|
|
110
|
+
|
|
111
|
+
print(profile)
|
|
112
|
+
print(floorsheet["totalTrades"])
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Interactive explorer
|
|
116
|
+
|
|
117
|
+
The repository includes a terminal explorer for local use:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
python tui.py
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Development
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
python -m pip install -e ".[dev]"
|
|
127
|
+
pytest -q
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Scope and disclaimer
|
|
131
|
+
|
|
132
|
+
This package is for public, read-only market-data workflows. It does not handle
|
|
133
|
+
user login, trading, portfolio actions, or other state-changing operations.
|
|
134
|
+
NEPSE data may be delayed or corrected by the exchange; verify information
|
|
135
|
+
independently before making financial decisions.
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
Distributed under the [MIT License](LICENSE).
|
nepsepy-1.0.0/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# nepsepy
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/nepsepy/)
|
|
6
|
+
[](https://pypi.org/project/nepsepy/)
|
|
7
|
+
[](https://github.com/menaceXnadin/nepsepy/actions/workflows/tests.yml)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
10
|
+
> A clean Python interface for public Nepal Stock Exchange (NEPSE) market data.
|
|
11
|
+
|
|
12
|
+
`nepsepy` provides a small, synchronous API for market status, prices, floor
|
|
13
|
+
sheets, indices, company information, notices, and other data used by the
|
|
14
|
+
NEPSE website.
|
|
15
|
+
|
|
16
|
+
It is not affiliated with the Nepal Stock Exchange.
|
|
17
|
+
|
|
18
|
+
## Why nepsepy?
|
|
19
|
+
|
|
20
|
+
- **Simple API** — use named methods such as `today_price()` and
|
|
21
|
+
`security_profile()` instead of manually assembling HTTP requests.
|
|
22
|
+
- **Public session handling** — performs the same login-free bootstrap used by
|
|
23
|
+
the NEPSE frontend; no user credentials are needed.
|
|
24
|
+
- **Careful by default** — requests are paced, token values are kept in memory,
|
|
25
|
+
and rate limiting is surfaced clearly instead of retried aggressively.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
Requires Python 3.10 or later.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
python -m pip install nepsepy
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The PyPI distribution and Python import package are both named `nepsepy`.
|
|
36
|
+
|
|
37
|
+
## Quick start
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from nepsepy import NepseClient
|
|
41
|
+
|
|
42
|
+
with NepseClient() as client:
|
|
43
|
+
status = client.market_status()
|
|
44
|
+
gainers = client.top_gainers()
|
|
45
|
+
prices = client.today_price(page=1, size=20)
|
|
46
|
+
|
|
47
|
+
print(status["isOpen"])
|
|
48
|
+
print(gainers[:3])
|
|
49
|
+
print(prices["content"][:3])
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Most methods return the JSON object or list supplied by NEPSE. Pagination uses
|
|
53
|
+
1-based page numbers, matching the website UI. Dates use `yyyy-MM-dd`.
|
|
54
|
+
|
|
55
|
+
## Features
|
|
56
|
+
|
|
57
|
+
| Area | Included data |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| Market | Status, summaries, live market data, ticker, and top-ten lists |
|
|
60
|
+
| Prices & trades | Today’s prices, floor sheets, depth, supply/demand, and trade history |
|
|
61
|
+
| Charts | NEPSE indices, index history, and market/company chart data |
|
|
62
|
+
| Companies | Profiles, corporate actions, financial reports, dividends, AGMs, and news |
|
|
63
|
+
| Directories | Companies, sectors, share groups, promoters, brokers, and dealers |
|
|
64
|
+
| News & files | Notices, disclosures, holidays, reports, events, CSV exports, and downloads |
|
|
65
|
+
|
|
66
|
+
## Authentication and rate limits
|
|
67
|
+
|
|
68
|
+
No account credentials are required. `NepseClient` performs the same public
|
|
69
|
+
session bootstrap used by NEPSE’s frontend when it is first needed. Session
|
|
70
|
+
tokens stay in memory and are redacted from package diagnostics.
|
|
71
|
+
|
|
72
|
+
Requests are paced conservatively. A `429 Too Many Requests` response raises
|
|
73
|
+
`RateLimitedError`; the client does not retry in a loop.
|
|
74
|
+
|
|
75
|
+
## Common examples
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from nepsepy import NepseClient
|
|
79
|
+
|
|
80
|
+
with NepseClient() as client:
|
|
81
|
+
# Use numeric security IDs; resolve them from companies() or securities().
|
|
82
|
+
companies = client.companies()
|
|
83
|
+
barun = next(row for row in companies if row["symbol"] == "BARUN")
|
|
84
|
+
|
|
85
|
+
profile = client.security_profile(barun["id"])
|
|
86
|
+
floorsheet = client.floorsheets(stock_id=barun["id"])
|
|
87
|
+
|
|
88
|
+
print(profile)
|
|
89
|
+
print(floorsheet["totalTrades"])
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Interactive explorer
|
|
93
|
+
|
|
94
|
+
The repository includes a terminal explorer for local use:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
python tui.py
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Development
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
python -m pip install -e ".[dev]"
|
|
104
|
+
pytest -q
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Scope and disclaimer
|
|
108
|
+
|
|
109
|
+
This package is for public, read-only market-data workflows. It does not handle
|
|
110
|
+
user login, trading, portfolio actions, or other state-changing operations.
|
|
111
|
+
NEPSE data may be delayed or corrected by the exchange; verify information
|
|
112
|
+
independently before making financial decisions.
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
Distributed under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Public NEPSE market-data client (normal public-site flow only)."""
|
|
2
|
+
|
|
3
|
+
from .auth import ProveResponse, TokenState
|
|
4
|
+
from .checksum import base as checksum_base
|
|
5
|
+
from .checksum import current_day as checksum_day
|
|
6
|
+
from .checksum import variant_a as checksum_a
|
|
7
|
+
from .checksum import variant_b as checksum_b
|
|
8
|
+
from .checksum import variant_c as checksum_c
|
|
9
|
+
from .client import NepseClient
|
|
10
|
+
from .exceptions import (AuthExpiredError, BootstrapError, NepseError,
|
|
11
|
+
PublicEndpointError, RateLimitedError, WasmError)
|
|
12
|
+
from .wasm import WasmCleaner, redact, strip_at_indexes
|
|
13
|
+
|
|
14
|
+
__all__ = ["NepseClient", "ProveResponse", "TokenState", "WasmCleaner",
|
|
15
|
+
"redact", "strip_at_indexes", "NepseError", "BootstrapError",
|
|
16
|
+
"WasmError", "AuthExpiredError", "RateLimitedError",
|
|
17
|
+
"PublicEndpointError", "checksum_base", "checksum_day",
|
|
18
|
+
"checksum_a", "checksum_b", "checksum_c"]
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Per-security data and company tabs. endpoints (mixin for NepseClient)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CompanyMixin:
|
|
9
|
+
# -- per-security data (GET; mirrors company tabs) --------------------------
|
|
10
|
+
def security_detail(self, security_id: int) -> dict:
|
|
11
|
+
"""{securityData, securityMcsData} (Market Depth page header)."""
|
|
12
|
+
return self.get_json(f"/api/nots/security/{security_id}") # type: ignore[return-value]
|
|
13
|
+
|
|
14
|
+
def security_profile(self, security_id: int) -> dict:
|
|
15
|
+
return self.get_json(f"/api/nots/security/profile/{security_id}") # type: ignore[return-value]
|
|
16
|
+
|
|
17
|
+
def board_of_directors(self, security_id: int) -> list:
|
|
18
|
+
return self.get_json(f"/api/nots/security/boardOfDirectors/{security_id}") # type: ignore[return-value]
|
|
19
|
+
|
|
20
|
+
def corporate_actions(self, security_id: int) -> list:
|
|
21
|
+
"""Bonus/cash/right [{fiscalYear, bonusPercentage, ...}]."""
|
|
22
|
+
return self.get_json(f"/api/nots/security/corporate-actions/{security_id}") # type: ignore[return-value]
|
|
23
|
+
|
|
24
|
+
def financial_reports(self, security_id: int) -> list:
|
|
25
|
+
return self.get_json(f"/api/nots/application/reports/{security_id}") # type: ignore[return-value]
|
|
26
|
+
|
|
27
|
+
def agm(self, security_id: int) -> list:
|
|
28
|
+
return self.get_json(f"/api/nots/application/agm/{security_id}") # type: ignore[return-value]
|
|
29
|
+
|
|
30
|
+
def security_company_news(self, security_id: int) -> list:
|
|
31
|
+
return self.get_json(f"/api/nots/application/company-news/{security_id}") # type: ignore[return-value]
|
|
32
|
+
|
|
33
|
+
def market_security(self, security_id: int) -> dict:
|
|
34
|
+
"""Flat daily-trade snapshot + nested security (Listing Information)."""
|
|
35
|
+
return self.get_json(f"/api/nots/market/security/{security_id}") # type: ignore[return-value]
|
|
36
|
+
|
|
37
|
+
def security_market_picture(self, security_id: int) -> dict:
|
|
38
|
+
"""Compact quote {receivedDateTime, securityId, lastTradedPrice,
|
|
39
|
+
openPrice, highPrice, lowPrice} (site's getSecurityDetailsFromMarketPicture)."""
|
|
40
|
+
return self.get_json(f"/api/nots/security-detail/{security_id}") # type: ignore[return-value]
|
|
41
|
+
|
|
42
|
+
def dividends(self, security_id: int) -> list:
|
|
43
|
+
"""Dividend applications/news for a security (site's getSecurityDividendNewsById)."""
|
|
44
|
+
return self.get_json(f"/api/nots/application/dividend/{security_id}") # type: ignore[return-value]
|
|
45
|
+
|
|
46
|
+
def book_close(self, news_id: int) -> dict:
|
|
47
|
+
"""Book-closure news by id (site's getSecurityBookCloseNewsById).
|
|
48
|
+
|
|
49
|
+
NOTE: currently HTTP 404 for every id tried (security ids and
|
|
50
|
+
company-news ids alike), so this is mapped-but-dead like
|
|
51
|
+
security_floorsheet() until the backend serves it again.
|
|
52
|
+
"""
|
|
53
|
+
return self.get_json(f"/api/nots/news/book-close/{news_id}") # type: ignore[return-value]
|
|
54
|
+
|
|
55
|
+
def security_price_history(self, security_id: int, page: int = 1,
|
|
56
|
+
size: int = 20,
|
|
57
|
+
business_date: Optional[str] = None) -> dict:
|
|
58
|
+
"""Price History tab (Spring page of OHLCV rows; page 1-based)."""
|
|
59
|
+
query = f"?&size={size}"
|
|
60
|
+
if business_date:
|
|
61
|
+
query += f"&businessDate={business_date}"
|
|
62
|
+
if page > 1:
|
|
63
|
+
query = f"?page={page - 1}&size={size}" + (
|
|
64
|
+
f"&businessDate={business_date}" if business_date else "")
|
|
65
|
+
return self.get_json(f"/api/nots/market/security/price/{security_id}{query}") # type: ignore[return-value]
|
|
66
|
+
|
|
67
|
+
def stock_trading_history(self, security_id: int, page: int = 1,
|
|
68
|
+
size: int = 20,
|
|
69
|
+
start: Optional[str] = None,
|
|
70
|
+
end: Optional[str] = None) -> dict:
|
|
71
|
+
"""Stock Trading page (page 1-based; dates 'yyyy-MM-dd')."""
|
|
72
|
+
query = f"?&size={size}"
|
|
73
|
+
if start:
|
|
74
|
+
query += f"&startDate={start}"
|
|
75
|
+
if end:
|
|
76
|
+
query += f"&endDate={end}"
|
|
77
|
+
if page > 1:
|
|
78
|
+
query = f"?page={page - 1}&size={size}" + (
|
|
79
|
+
f"&startDate={start}" if start else "") + (
|
|
80
|
+
f"&endDate={end}" if end else "")
|
|
81
|
+
return self.get_json(f"/api/nots/market/history/security/{security_id}{query}") # type: ignore[return-value]
|
|
82
|
+
|
|
83
|
+
def trading_average(self, n_days: int = 120,
|
|
84
|
+
business_date: Optional[str] = None,
|
|
85
|
+
stock_id: Optional[int] = None) -> list:
|
|
86
|
+
"""N-day average price per security (Trading Average page)."""
|
|
87
|
+
path = f"/api/nots/nepse-data/trading-average?nDays={n_days}"
|
|
88
|
+
if business_date:
|
|
89
|
+
path += f"&businessDate={business_date}"
|
|
90
|
+
if stock_id is not None:
|
|
91
|
+
path += f"&stockId={stock_id}"
|
|
92
|
+
return self.get_json(path) # type: ignore[return-value]
|
|
93
|
+
|
|
94
|
+
def market_cap_history(self, page: int = 1) -> list:
|
|
95
|
+
"""Daily market caps [{businessDate, marCap, ...}] (filter client-side)."""
|
|
96
|
+
path = "/api/nots/nepse-data/marcapbydate/?"
|
|
97
|
+
if page > 1:
|
|
98
|
+
path = f"/api/nots/nepse-data/marcapbydate/?page={page - 1}"
|
|
99
|
+
return self.get_json(path) # type: ignore[return-value]
|
|
100
|
+
|
|
101
|
+
# -- signed POST: company data --------------------------------------------------
|
|
102
|
+
def company_info(self, security_id: int) -> dict:
|
|
103
|
+
"""Company header {securityDailyTradeDto, security, ...} (detail page)."""
|
|
104
|
+
return self.post_json(f"/api/nots/security/{security_id}", # type: ignore[return-value]
|
|
105
|
+
{"id": self._signed("raw")})
|
|
106
|
+
|
|
107
|
+
def company_graph(self, security_id: int) -> list:
|
|
108
|
+
"""Company OHLC history [{businessDate, openPrice, ...}] (chart tab)."""
|
|
109
|
+
return self.post_json(f"/api/nots/market/graphdata/{security_id}", # type: ignore[return-value]
|
|
110
|
+
{"id": self._signed("raw")})
|
|
111
|
+
|
|
112
|
+
def company_graph_intraday(self, security_id: int) -> list:
|
|
113
|
+
"""Company intraday LTP (Charts Company tab, 1D range)."""
|
|
114
|
+
return self.post_json(f"/api/nots/market/graphdata/daily/{security_id}", # type: ignore[return-value]
|
|
115
|
+
{"id": self._signed("raw")})
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Market data, indices, top tens and depth. endpoints (mixin for NepseClient)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MarketMixin:
|
|
9
|
+
# -- market status / summary / ticker --------------------------------
|
|
10
|
+
def market_status(self) -> dict:
|
|
11
|
+
"""Market open state (homepage + every page reads this)."""
|
|
12
|
+
return self.get_json("/api/nots/nepse-data/market-open") # type: ignore[return-value]
|
|
13
|
+
|
|
14
|
+
def market_summary(self) -> list:
|
|
15
|
+
"""Homepage summary tiles [{detail, value}]."""
|
|
16
|
+
return self.get_json("/api/nots/market-summary/") # type: ignore[return-value]
|
|
17
|
+
|
|
18
|
+
def market_summary_history(self) -> list:
|
|
19
|
+
"""Daily history [{businessDate, totalTurnover, ...}]."""
|
|
20
|
+
return self.get_json("/api/nots/market-summary-history") # type: ignore[return-value]
|
|
21
|
+
|
|
22
|
+
def ticker(self, index_id: int = 58) -> list:
|
|
23
|
+
"""Live ticker strip [{symbol, ltp, ...}] (every page load)."""
|
|
24
|
+
return self.get_json(f"/api/nots/securityDailyTradeStat/{index_id}") # type: ignore[return-value]
|
|
25
|
+
|
|
26
|
+
def live_market(self) -> list:
|
|
27
|
+
"""Full live snapshot (356 rows: OHLC, volumes, per-security indexId).
|
|
28
|
+
|
|
29
|
+
The Live Market *page* redirects to `/` while the market is closed,
|
|
30
|
+
but the API itself answers 200 regardless — verified live.
|
|
31
|
+
"""
|
|
32
|
+
return self.get_json("/api/nots/lives-market") # type: ignore[return-value]
|
|
33
|
+
|
|
34
|
+
def nepse_indices(self) -> list:
|
|
35
|
+
"""Index snapshot [{index, close, change, perChange, ...}]."""
|
|
36
|
+
return self.get_json("/api/nots/nepse-index") # type: ignore[return-value]
|
|
37
|
+
|
|
38
|
+
def sub_indices(self) -> list:
|
|
39
|
+
"""Sub-index snapshot [{id, index, change, currentValue}]."""
|
|
40
|
+
return self.get_json("/api/nots") # type: ignore[return-value]
|
|
41
|
+
|
|
42
|
+
def indices_list(self) -> list:
|
|
43
|
+
"""Index directory [{id, indexCode, indexName, ...}]."""
|
|
44
|
+
return self.get_json("/api/nots/index") # type: ignore[return-value]
|
|
45
|
+
|
|
46
|
+
def index_history(self, index_id: int = 58, page: int = 1,
|
|
47
|
+
size: int = 20) -> dict:
|
|
48
|
+
"""Datewise index OHLC (Indices page; page is 1-based like the UI)."""
|
|
49
|
+
path = f"/api/nots/index/history/{index_id}?&size={size}"
|
|
50
|
+
if page > 1:
|
|
51
|
+
path = f"/api/nots/index/history/{index_id}?page={page - 1}&size={size}"
|
|
52
|
+
return self.get_json(path) # type: ignore[return-value]
|
|
53
|
+
|
|
54
|
+
def sector_summary(self, business_date: Optional[str] = None) -> list:
|
|
55
|
+
"""Sector turnover (Sector Summary page; date 'yyyy-MM-dd')."""
|
|
56
|
+
path = "/api/nots/sectorwise"
|
|
57
|
+
if business_date:
|
|
58
|
+
path += f"?businessDate={business_date}"
|
|
59
|
+
return self.get_json(path) # type: ignore[return-value]
|
|
60
|
+
|
|
61
|
+
# -- top tens ------------------------------------------------------------
|
|
62
|
+
def _top_ten(self, kind: str, full: bool = False) -> list:
|
|
63
|
+
return self.get_json(f"/api/nots/top-ten/{kind}?all={str(full).lower()}") # type: ignore[return-value]
|
|
64
|
+
|
|
65
|
+
def top_gainers(self, full: bool = False) -> list:
|
|
66
|
+
"""Top gainers [{symbol, ltp, pointChange, percentageChange, ...}]."""
|
|
67
|
+
return self._top_ten("top-gainer", full)
|
|
68
|
+
|
|
69
|
+
def top_losers(self, full: bool = False) -> list:
|
|
70
|
+
"""Top losers (same shape as gainers)."""
|
|
71
|
+
return self._top_ten("top-loser", full)
|
|
72
|
+
|
|
73
|
+
def top_turnover(self, full: bool = False) -> list:
|
|
74
|
+
"""Top by turnover."""
|
|
75
|
+
return self._top_ten("turnover", full)
|
|
76
|
+
|
|
77
|
+
def top_traded_shares(self, full: bool = False) -> list:
|
|
78
|
+
"""Top by shares traded."""
|
|
79
|
+
return self._top_ten("trade", full)
|
|
80
|
+
|
|
81
|
+
def top_transactions(self, full: bool = False) -> list:
|
|
82
|
+
"""Top by transaction count."""
|
|
83
|
+
return self._top_ten("transaction", full)
|
|
84
|
+
|
|
85
|
+
def top_active(self, full: bool = False) -> list:
|
|
86
|
+
"""Most active scrips (trade quantity)."""
|
|
87
|
+
return self._top_ten("trade-qty", full)
|
|
88
|
+
|
|
89
|
+
# -- supply / demand / depth ----------------------------------------------
|
|
90
|
+
def supply_demand(self, full: bool = False) -> dict:
|
|
91
|
+
"""Top supply/demand {supplyList, demandList}."""
|
|
92
|
+
return self.get_json( # type: ignore[return-value]
|
|
93
|
+
f"/api/nots/nepse-data/supplydemand?all={str(full).lower()}")
|
|
94
|
+
|
|
95
|
+
def market_depth(self, security_id: int) -> dict:
|
|
96
|
+
"""Order book {totalBuyQty, totalSellQty, marketDepth{...}}."""
|
|
97
|
+
return self.get_json(f"/api/nots/nepse-data/marketdepth/{security_id}") # type: ignore[return-value]
|
|
98
|
+
|
|
99
|
+
def odd_lot_depth(self, security_id: int) -> dict:
|
|
100
|
+
"""Odd-lot order book (same shape as market_depth)."""
|
|
101
|
+
return self.get_json(f"/api/nots/nepse-data/marketdepth-ol/{security_id}") # type: ignore[return-value]
|