pypsx-toolkit 3.0.3__tar.gz → 3.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 (24) hide show
  1. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/PKG-INFO +32 -36
  2. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/README.md +23 -28
  3. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pyproject.toml +30 -14
  4. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/__init__.py +86 -14
  5. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/analysis/__init__.py +10 -1
  6. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/api.pyi +10 -4
  7. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/setup.py +21 -0
  8. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/LICENSE +0 -0
  9. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/MANIFEST.in +0 -0
  10. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/__init__.pyi +0 -0
  11. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/analysis/__init__.pyi +0 -0
  12. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/core/__init__.py +0 -0
  13. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/core/errors.pyi +0 -0
  14. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/core/stream.pyi +0 -0
  15. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/endpoints/__init__.py +0 -0
  16. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/endpoints/constants.py +0 -0
  17. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/format/__init__.py +0 -0
  18. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/market.pyi +0 -0
  19. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/models.py +0 -0
  20. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/models.pyi +0 -0
  21. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/py.typed +0 -0
  22. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit/ticker.pyi +0 -0
  23. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/pypsx_toolkit.egg-info/SOURCES.txt +0 -0
  24. {pypsx_toolkit-3.0.3 → pypsx_toolkit-3.1.0}/setup.cfg +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pypsx-toolkit
3
- Version: 3.0.3
3
+ Version: 3.1.0
4
4
  Summary: Pakistan Stock Exchange (PSX) data library with yfinance-like API
5
- Author-email: PyPSX Team <contact@pypsx.dev>
6
- Maintainer-email: PyPSX Team <contact@pypsx.dev>
5
+ Author-email: PyPSX Team <pypsxofficial@gmail.com>
6
+ Maintainer-email: PyPSX Team <pypsxofficial@gmail.com>
7
7
  License: Copyright (c) 2026 PyPSX Team. All rights reserved.
8
8
 
9
9
  This software and associated documentation files (the "Software") are the
@@ -32,24 +32,25 @@ Classifier: Intended Audience :: Financial and Insurance Industry
32
32
  Classifier: License :: Other/Proprietary License
33
33
  Classifier: Operating System :: OS Independent
34
34
  Classifier: Programming Language :: Python :: 3
35
- Classifier: Programming Language :: Python :: 3.8
36
- Classifier: Programming Language :: Python :: 3.9
37
35
  Classifier: Programming Language :: Python :: 3.10
38
36
  Classifier: Programming Language :: Python :: 3.11
39
37
  Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Programming Language :: Python :: 3.13
39
+ Classifier: Programming Language :: Python :: 3.14
40
40
  Classifier: Programming Language :: Python :: 3 :: Only
41
41
  Classifier: Topic :: Office/Business :: Financial
42
42
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
43
43
  Classifier: Topic :: Scientific/Engineering :: Information Analysis
44
- Requires-Python: >=3.8
44
+ Requires-Python: >=3.10
45
45
  Description-Content-Type: text/markdown
46
46
  License-File: LICENSE
47
47
  Requires-Dist: requests>=2.31.0
48
48
  Requires-Dist: beautifulsoup4>=4.12.0
49
49
  Requires-Dist: lxml>=4.9.0
50
- Requires-Dist: pandas<2.3.3,>=2.0.0
50
+ Requires-Dist: pandas<3.0.0,>=2.0.0
51
51
  Requires-Dist: loguru>=0.7.0
52
- Requires-Dist: numpy<2.3.0,>=1.24.0
52
+ Requires-Dist: numpy<2.4.0,>=1.24.0
53
+ Requires-Dist: tqdm>=4.66.0
53
54
  Provides-Extra: plot
54
55
  Requires-Dist: matplotlib>=3.5.0; extra == "plot"
55
56
  Requires-Dist: seaborn>=0.11.0; extra == "plot"
@@ -67,7 +68,7 @@ Dynamic: license-file
67
68
 
68
69
  # pypsx-toolkit — Pakistan Stock Exchange Data Library
69
70
 
70
- A clean, simple Python library to fetch and analyze Pakistan Stock Exchange (PSX) data from official DPS endpoints. Get real-time market data, historical prices, and powerful analysis tools all in one package — no authentication required.
71
+ A clean, simple Python library to fetch and analyze Pakistan Stock Exchange (PSX) market data. Get real-time market data, historical prices, and powerful analysis tools all in one package — no authentication required.
71
72
 
72
73
  ## Installation
73
74
 
@@ -218,7 +219,7 @@ ticker = pypsx_toolkit.PSXTicker("OGDC")
218
219
  - `ticker.history(period="1y", interval="1d")` - Get historical data
219
220
  - `ticker.intraday()` - Get intraday trades (last ~2 days)
220
221
  - `ticker.get_historical(start_date, end_date)` - Get full OHLCV data for date range
221
- - `ticker.dividends()` - Get dividend information (external source)
222
+ - `ticker.dividends()` - Get dividend information
222
223
  - `ticker.announcements()` - Get company announcements
223
224
  - `ticker.orderbook()` - Get trading board data (bid/ask prices)
224
225
 
@@ -505,17 +506,6 @@ historical = ticker.get_historical(
505
506
  print(historical.head())
506
507
  ```
507
508
 
508
- ## Data Sources
509
-
510
- PyPSX Toolkit uses official Pakistan Stock Exchange DPS endpoints:
511
- - Market Watch: `https://dps.psx.com.pk/market-watch`
512
- - Sector Summary: `https://dps.psx.com.pk/sector-summary/sectorwise`
513
- - Indices: `https://dps.psx.com.pk/indices/{INDEX}`
514
- - Trading Board: `https://dps.psx.com.pk/trading-board/REG/main`
515
- - Performers: `https://dps.psx.com.pk/performers`
516
- - Timeseries: `https://dps.psx.com.pk/timeseries/int/{SYMBOL}`, `.../eod/{SYMBOL}`
517
- - Historical OHLCV: `https://dps.psx.com.pk/historical`
518
-
519
509
  ## Examples
520
510
 
521
511
  ### Example 1: Find Top Volume Stocks
@@ -605,22 +595,24 @@ for insight in analysis["portfolio_insights"]:
605
595
  ### PSXTicker Class
606
596
 
607
597
  ```python
608
- ticker = pypsx_toolkit.PSXTicker(symbol: str)
598
+ import pypsx_toolkit
599
+
600
+ ticker = pypsx_toolkit.PSXTicker("OGDC")
609
601
 
610
- # Properties
602
+ # Properties (no parentheses)
611
603
  ticker.info # Dict with company info
612
604
  ticker.snapshot # Dict with comprehensive snapshot data from all tabs
613
- ticker.fast_info # Quick metrics dict
605
+ ticker.fast_info # Quick metrics dict
614
606
 
615
607
  # Methods
616
- ticker.history(period="1y", interval="1d") # Historical data
617
- ticker.intraday() # Intraday trades
618
- ticker.get_historical(start_date, end_date) # Full OHLCV data
619
- ticker.market_watch() # Market watch row
620
- ticker.sector() # Sector information
621
- ticker.orderbook() # Trading board data
622
- ticker.dividends() # DataFrame with dividends
623
- ticker.announcements() # DataFrame with announcements
608
+ ticker.history(period="1y", interval="1d") # Historical data
609
+ ticker.intraday() # Intraday trades
610
+ ticker.get_historical("2024-01-01", "2024-12-31") # Full OHLCV data
611
+ ticker.market_watch() # Market watch row
612
+ ticker.sector() # Sector information
613
+ ticker.orderbook() # Trading board data
614
+ ticker.dividends() # DataFrame with dividends
615
+ ticker.announcements() # DataFrame with announcements
624
616
  ```
625
617
 
626
618
  ### Market Functions
@@ -650,9 +642,13 @@ pypsx_toolkit.get_snapshot(symbol) # Get snapshot data from all tab
650
642
  ### Download Functions
651
643
 
652
644
  ```python
653
- pypsx_toolkit.download(symbols, period="1y", interval="1d") # Batch download
654
- pypsx_toolkit.get_intraday_multiple(symbols) # Multiple intraday
655
- pypsx_toolkit.get_historical(symbol, start_date, end_date) # Historical OHLCV
645
+ import pypsx_toolkit
646
+
647
+ symbols = ["OGDC", "HBL"]
648
+
649
+ pypsx_toolkit.download(symbols, period="1y", interval="1d") # Batch download
650
+ pypsx_toolkit.get_intraday_multiple(symbols) # Multiple intraday
651
+ pypsx_toolkit.get_historical("OGDC", "2024-01-01", "2024-12-31") # Historical OHLCV
656
652
  ```
657
653
 
658
654
  ## Backward Compatibility
@@ -663,7 +659,7 @@ The library maintains backward compatibility:
663
659
 
664
660
  ## Notes
665
661
 
666
- - **Dividends**: PSX doesn't provide a dividends endpoint. The `dividends` property uses an external data source.
662
+ - **Dividends**: dividend records use their own column naming, which differs from the conventions used elsewhere in the toolkit.
667
663
  - **Data Availability**: Some data may not be available when the market is closed.
668
664
  - **Symbol Names**: Use official PSX symbols (e.g., "OGDC", "PPL", "KEL").
669
665
 
@@ -1,6 +1,6 @@
1
1
  # pypsx-toolkit — Pakistan Stock Exchange Data Library
2
2
 
3
- A clean, simple Python library to fetch and analyze Pakistan Stock Exchange (PSX) data from official DPS endpoints. Get real-time market data, historical prices, and powerful analysis tools all in one package — no authentication required.
3
+ A clean, simple Python library to fetch and analyze Pakistan Stock Exchange (PSX) market data. Get real-time market data, historical prices, and powerful analysis tools all in one package — no authentication required.
4
4
 
5
5
  ## Installation
6
6
 
@@ -151,7 +151,7 @@ ticker = pypsx_toolkit.PSXTicker("OGDC")
151
151
  - `ticker.history(period="1y", interval="1d")` - Get historical data
152
152
  - `ticker.intraday()` - Get intraday trades (last ~2 days)
153
153
  - `ticker.get_historical(start_date, end_date)` - Get full OHLCV data for date range
154
- - `ticker.dividends()` - Get dividend information (external source)
154
+ - `ticker.dividends()` - Get dividend information
155
155
  - `ticker.announcements()` - Get company announcements
156
156
  - `ticker.orderbook()` - Get trading board data (bid/ask prices)
157
157
 
@@ -438,17 +438,6 @@ historical = ticker.get_historical(
438
438
  print(historical.head())
439
439
  ```
440
440
 
441
- ## Data Sources
442
-
443
- PyPSX Toolkit uses official Pakistan Stock Exchange DPS endpoints:
444
- - Market Watch: `https://dps.psx.com.pk/market-watch`
445
- - Sector Summary: `https://dps.psx.com.pk/sector-summary/sectorwise`
446
- - Indices: `https://dps.psx.com.pk/indices/{INDEX}`
447
- - Trading Board: `https://dps.psx.com.pk/trading-board/REG/main`
448
- - Performers: `https://dps.psx.com.pk/performers`
449
- - Timeseries: `https://dps.psx.com.pk/timeseries/int/{SYMBOL}`, `.../eod/{SYMBOL}`
450
- - Historical OHLCV: `https://dps.psx.com.pk/historical`
451
-
452
441
  ## Examples
453
442
 
454
443
  ### Example 1: Find Top Volume Stocks
@@ -538,22 +527,24 @@ for insight in analysis["portfolio_insights"]:
538
527
  ### PSXTicker Class
539
528
 
540
529
  ```python
541
- ticker = pypsx_toolkit.PSXTicker(symbol: str)
530
+ import pypsx_toolkit
531
+
532
+ ticker = pypsx_toolkit.PSXTicker("OGDC")
542
533
 
543
- # Properties
534
+ # Properties (no parentheses)
544
535
  ticker.info # Dict with company info
545
536
  ticker.snapshot # Dict with comprehensive snapshot data from all tabs
546
- ticker.fast_info # Quick metrics dict
537
+ ticker.fast_info # Quick metrics dict
547
538
 
548
539
  # Methods
549
- ticker.history(period="1y", interval="1d") # Historical data
550
- ticker.intraday() # Intraday trades
551
- ticker.get_historical(start_date, end_date) # Full OHLCV data
552
- ticker.market_watch() # Market watch row
553
- ticker.sector() # Sector information
554
- ticker.orderbook() # Trading board data
555
- ticker.dividends() # DataFrame with dividends
556
- ticker.announcements() # DataFrame with announcements
540
+ ticker.history(period="1y", interval="1d") # Historical data
541
+ ticker.intraday() # Intraday trades
542
+ ticker.get_historical("2024-01-01", "2024-12-31") # Full OHLCV data
543
+ ticker.market_watch() # Market watch row
544
+ ticker.sector() # Sector information
545
+ ticker.orderbook() # Trading board data
546
+ ticker.dividends() # DataFrame with dividends
547
+ ticker.announcements() # DataFrame with announcements
557
548
  ```
558
549
 
559
550
  ### Market Functions
@@ -583,9 +574,13 @@ pypsx_toolkit.get_snapshot(symbol) # Get snapshot data from all tab
583
574
  ### Download Functions
584
575
 
585
576
  ```python
586
- pypsx_toolkit.download(symbols, period="1y", interval="1d") # Batch download
587
- pypsx_toolkit.get_intraday_multiple(symbols) # Multiple intraday
588
- pypsx_toolkit.get_historical(symbol, start_date, end_date) # Historical OHLCV
577
+ import pypsx_toolkit
578
+
579
+ symbols = ["OGDC", "HBL"]
580
+
581
+ pypsx_toolkit.download(symbols, period="1y", interval="1d") # Batch download
582
+ pypsx_toolkit.get_intraday_multiple(symbols) # Multiple intraday
583
+ pypsx_toolkit.get_historical("OGDC", "2024-01-01", "2024-12-31") # Historical OHLCV
589
584
  ```
590
585
 
591
586
  ## Backward Compatibility
@@ -596,7 +591,7 @@ The library maintains backward compatibility:
596
591
 
597
592
  ## Notes
598
593
 
599
- - **Dividends**: PSX doesn't provide a dividends endpoint. The `dividends` property uses an external data source.
594
+ - **Dividends**: dividend records use their own column naming, which differs from the conventions used elsewhere in the toolkit.
600
595
  - **Data Availability**: Some data may not be available when the market is closed.
601
596
  - **Symbol Names**: Use official PSX symbols (e.g., "OGDC", "PPL", "KEL").
602
597
 
@@ -4,16 +4,18 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pypsx-toolkit"
7
- version = "3.0.3"
7
+ version = "3.1.0"
8
8
  description = "Pakistan Stock Exchange (PSX) data library with yfinance-like API"
9
9
  readme = "README.md"
10
- requires-python = ">=3.8"
10
+ # 3.10 is the real floor: `pandas>=2.0` already excludes 3.8/3.9, and
11
+ # core/utils.py uses PEP 604 (`int | None`) in a runtime signature.
12
+ requires-python = ">=3.10"
11
13
  license = { file = "LICENSE" }
12
14
  authors = [
13
- { name = "PyPSX Team", email = "contact@pypsx.dev" }
15
+ { name = "PyPSX Team", email = "pypsxofficial@gmail.com" }
14
16
  ]
15
17
  maintainers = [
16
- { name = "PyPSX Team", email = "contact@pypsx.dev" }
18
+ { name = "PyPSX Team", email = "pypsxofficial@gmail.com" }
17
19
  ]
18
20
  keywords = ["psx", "pakistan", "stock", "finance", "data", "api", "pandas", "yfinance", "market-data"]
19
21
  classifiers = [
@@ -23,11 +25,11 @@ classifiers = [
23
25
  "License :: Other/Proprietary License",
24
26
  "Operating System :: OS Independent",
25
27
  "Programming Language :: Python :: 3",
26
- "Programming Language :: Python :: 3.8",
27
- "Programming Language :: Python :: 3.9",
28
28
  "Programming Language :: Python :: 3.10",
29
29
  "Programming Language :: Python :: 3.11",
30
30
  "Programming Language :: Python :: 3.12",
31
+ "Programming Language :: Python :: 3.13",
32
+ "Programming Language :: Python :: 3.14",
31
33
  "Programming Language :: Python :: 3 :: Only",
32
34
  "Topic :: Office/Business :: Financial",
33
35
  "Topic :: Software Development :: Libraries :: Python Modules",
@@ -38,9 +40,17 @@ dependencies = [
38
40
  "requests>=2.31.0",
39
41
  "beautifulsoup4>=4.12.0",
40
42
  "lxml>=4.9.0",
41
- "pandas>=2.0.0,<2.3.3",
43
+ # See pypsx_dev/pyproject.toml's identical pins for the reasoning: the
44
+ # ceiling must not exclude the first cp314-wheel release (pandas 2.3.3,
45
+ # numpy 2.3.2), and is deliberately kept below pandas 3.0 (mandatory CoW +
46
+ # other breaking changes) pending its own review.
47
+ "pandas>=2.0.0,<3.0.0",
42
48
  "loguru>=0.7.0",
43
- "numpy>=1.24.0,<2.3.0",
49
+ "numpy>=1.24.0,<2.4.0",
50
+ # Imported by api.py, endpoints/historical.py and core/utils.py. Those imports
51
+ # are try/except-guarded with a no-op fallback, but the fallback path is
52
+ # untested and every target environment (including Colab) already ships tqdm.
53
+ "tqdm>=4.66.0",
44
54
  ]
45
55
 
46
56
  [project.optional-dependencies]
@@ -61,8 +71,12 @@ Homepage = "https://pypsx.com"
61
71
  Documentation = "https://markets.pypsx.com/docs"
62
72
  Changelog = "https://markets.pypsx.com/docs/changelog"
63
73
 
64
- [project.scripts]
65
- pypsx-toolkit = "pypsx_toolkit:quick_start"
74
+ # NOTE: no [project.scripts]. This previously declared
75
+ # pypsx-toolkit = "pypsx_toolkit:quick_start"
76
+ # but `quick_start` does not exist anywhere in the package, so the installed
77
+ # console script raised AttributeError on every invocation. This library has no
78
+ # CLI; removing the entry point is the honest fix. If a CLI is wanted later,
79
+ # implement the target function first.
66
80
 
67
81
  [tool.setuptools]
68
82
  include-package-data = true
@@ -152,8 +166,10 @@ markers = [
152
166
  "integration: marks tests as integration tests",
153
167
  "unit: marks tests as unit tests",
154
168
  ]
155
- filterwarnings = [
156
- "ignore::DeprecationWarning",
157
- "ignore::PendingDeprecationWarning",
158
- ]
169
+ # NOTE: deliberately no blanket `filterwarnings = ["ignore::DeprecationWarning"]`
170
+ # here. The Colab-mirror suite (b2c/tests/colab_mirror/) runs under
171
+ # `filterwarnings = error` because a warning in a notebook cell is a user-visible
172
+ # defect. A blanket ignore at this level hides exactly the class of bug that
173
+ # suite exists to catch. Allow-list individual warnings there, with an owner and
174
+ # an expiry, instead of re-adding a catch-all.
159
175
 
@@ -2,9 +2,9 @@
2
2
  PSX yfinance-style API
3
3
  """
4
4
 
5
- __version__ = "3.0.3"
5
+ __version__ = "3.1.0"
6
6
  __author__ = "PyPSX Team"
7
- __email__ = "pypsx@example.com"
7
+ __email__ = "pypsxofficial@gmail.com"
8
8
 
9
9
  from pypsx_toolkit.ticker import PSXTicker, Ticker
10
10
 
@@ -37,6 +37,14 @@ from pypsx_toolkit.endpoints.sectors import get_sector_constituents as _get_sect
37
37
  from pypsx_toolkit.endpoints.compliant_listings import get_symbols_by_sector as _get_symbols_by_sector
38
38
  from pypsx_toolkit.endpoints.snapshot import get_snapshot
39
39
 
40
+ # Financial reports. Implemented and working, but previously not reachable from
41
+ # anywhere in the public surface.
42
+ from pypsx_toolkit.endpoints.reports import get_reports
43
+
44
+ # Cache control. Useful in notebooks, where a stale cached response is a common
45
+ # source of "why is my data wrong" confusion.
46
+ from pypsx_toolkit.core.cache import clear_pypsx_cache, get_cache_stats
47
+
40
48
  from pypsx_toolkit.market import (
41
49
  top_performers,
42
50
  sector_summary,
@@ -70,18 +78,29 @@ from pypsx_toolkit.models import (
70
78
  DividendHistory,
71
79
  )
72
80
 
73
- # Analysis module (optional - requires analysis package)
74
- try:
75
- from pypsx_toolkit.analysis import (
76
- interpret_stock,
77
- sharpe_ratio,
78
- rsi,
79
- macd,
80
- bollinger_bands,
81
- )
82
- except ImportError:
83
- # Analysis module not available
84
- pass
81
+ # Exceptions. Previously these were reachable only via the private
82
+ # `pypsx_toolkit.core.errors` path, which the docs told users to import from.
83
+ # Re-exported here as the supported location; the old path still works.
84
+ from pypsx_toolkit.core.errors import (
85
+ PSXError,
86
+ PSXHTTPError,
87
+ PSXTimeoutError,
88
+ PSXNotFoundError,
89
+ PSXScopeError,
90
+ )
91
+
92
+ # Analysis module. This is NOT optional -- it depends only on pandas and numpy,
93
+ # both hard requirements of this package. It was previously wrapped in a
94
+ # `try/except ImportError: pass`, which silently turned any genuine bug inside
95
+ # the analysis package into a confusing AttributeError at call time.
96
+ from pypsx_toolkit import analysis
97
+ from pypsx_toolkit.analysis import (
98
+ interpret_stock,
99
+ sharpe_ratio,
100
+ rsi,
101
+ macd,
102
+ bollinger_bands,
103
+ )
85
104
 
86
105
  __all__ = [
87
106
  "__version__",
@@ -129,6 +148,14 @@ __all__ = [
129
148
  "get_sector_constituents",
130
149
  "get_symbols_by_sector",
131
150
  "get_snapshot",
151
+ "get_reports",
152
+ # Cache control
153
+ "clear_pypsx_cache",
154
+ "get_cache_stats",
155
+ # NOTE: `charts` is deliberately NOT listed here. It resolves lazily via
156
+ # __getattr__ and needs the optional `[plot]` extra, so including it would
157
+ # make `from pypsx_toolkit import *` raise ImportError on a plain install.
158
+ # Access it as `pypsx_toolkit.charts` (see the Charting docs).
132
159
  # Models
133
160
  "SymbolInfo",
134
161
  "SectorSummary",
@@ -147,8 +174,53 @@ __all__ = [
147
174
  "Announcement",
148
175
  "DividendInfo",
149
176
  "DividendHistory",
177
+ # Exceptions. Also available at the original `pypsx_toolkit.core.errors` path.
178
+ "PSXError",
179
+ "PSXHTTPError",
180
+ "PSXTimeoutError",
181
+ "PSXNotFoundError",
182
+ "PSXScopeError",
183
+ # Analysis. `analysis` is the submodule (documented usage is
184
+ # `import pypsx_toolkit.analysis as pa`); the rest are convenience
185
+ # re-exports that were importable before but absent from __all__.
186
+ "analysis",
187
+ "interpret_stock",
188
+ "sharpe_ratio",
189
+ "rsi",
190
+ "macd",
191
+ "bollinger_bands",
150
192
  ]
151
193
 
194
+ # `market_watch_func` / `get_indices_func` are internal aliases created to avoid
195
+ # colliding with the same-named api.py functions. They stay bound for backward
196
+ # compatibility but are deliberately excluded from __all__ above -- they are not
197
+ # part of the supported surface. Use `market_watch()` / `get_indices()`.
198
+
199
+
200
+ def __getattr__(name: str):
201
+ """
202
+ Lazily expose `pypsx_toolkit.charts`.
203
+
204
+ The charting helpers need matplotlib/seaborn, which ship only under the
205
+ optional `[plot]` extra. Importing them eagerly would make a plain
206
+ `pip install pypsx-toolkit` fail at `import pypsx_toolkit`, so resolution is
207
+ deferred until first access and a missing extra produces an actionable
208
+ message instead of a bare ModuleNotFoundError.
209
+ """
210
+ if name == "charts":
211
+ import sys
212
+
213
+ try:
214
+ from pypsx_toolkit.endpoints import charts as _charts
215
+ except ImportError as exc: # pragma: no cover - depends on install extras
216
+ raise ImportError(
217
+ "pypsx_toolkit.charts requires the optional plotting dependencies. "
218
+ "Install them with: pip install 'pypsx-toolkit[plot]'"
219
+ ) from exc
220
+ setattr(sys.modules[__name__], "charts", _charts)
221
+ return _charts
222
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
223
+
152
224
 
153
225
  # Legacy compatibility wrappers used by audit script (clean outputs only)
154
226
 
@@ -70,7 +70,16 @@ __all__ = [
70
70
 
71
71
  # Insight engine
72
72
  'interpret_stock', 'interpret_portfolio', 'detect_patterns',
73
- 'generate_trading_signals', 'market_sentiment_analysis'
73
+ 'generate_trading_signals', 'market_sentiment_analysis',
74
+
75
+ # Composite helpers (defined in this module, below)
76
+ 'quick_analysis', 'portfolio_analysis',
77
+
78
+ # Short aliases (defined at the bottom of this module). These are used in
79
+ # the published documentation, so they are part of the supported surface.
80
+ 'ma', 'ema', 'bb', 'sharpe', 'sortino', 'calmar', 'cum_returns', 'max_dd',
81
+ 'win_rate_pct', 'pl_ratio', 'recovery', 'perf_summary', 'interpret',
82
+ 'patterns', 'signals', 'sentiment',
74
83
  ]
75
84
 
76
85
 
@@ -6,9 +6,10 @@ import pandas as pd
6
6
 
7
7
  def download(
8
8
  symbols: Union[str, List[str]],
9
- period: str = "1mo",
9
+ period: str = "1y",
10
10
  interval: str = "1d",
11
11
  to_csv: Optional[str] = None,
12
+ show_progress: bool = True,
12
13
  ) -> pd.DataFrame:
13
14
  """
14
15
  Download historical OHLCV data for one or more PSX symbols (yfinance-style).
@@ -18,6 +19,8 @@ def download(
18
19
  period: Time period — "1d","5d","1mo","3mo","6mo","1y","2y","5y","10y","ytd","max".
19
20
  interval: Bar interval. Only "1d" is currently supported.
20
21
  to_csv: Optional path to save the result as CSV.
22
+ show_progress: Display a progress bar while fetching. Set False in
23
+ notebooks, reports or logs where the bar is just noise.
21
24
 
22
25
  Returns:
23
26
  For a single symbol: DataFrame with [Open, High, Low, Close, Volume, Change%].
@@ -61,8 +64,6 @@ def get_intraday(symbol: str) -> pd.DataFrame:
61
64
  """
62
65
  Fetch intraday tick data for the last 2 trading days.
63
66
 
64
- Runs on the user's local machine to distribute scraping traffic.
65
-
66
67
  Args:
67
68
  symbol: PSX ticker symbol.
68
69
 
@@ -75,12 +76,17 @@ def get_intraday(symbol: str) -> pd.DataFrame:
75
76
  ...
76
77
 
77
78
 
78
- def get_intraday_multiple(symbols: List[str]) -> pd.DataFrame:
79
+ def get_intraday_multiple(
80
+ symbols: List[str],
81
+ show_progress: bool = True,
82
+ ) -> pd.DataFrame:
79
83
  """
80
84
  Fetch intraday tick data for multiple symbols in parallel.
81
85
 
82
86
  Args:
83
87
  symbols: List of PSX ticker symbols.
88
+ show_progress: Display a progress bar while fetching. Set False in
89
+ notebooks, reports or logs where the bar is just noise.
84
90
 
85
91
  Returns:
86
92
  Concatenated DataFrame with an additional "Symbol" column.
@@ -85,6 +85,27 @@ def main():
85
85
  # embedsignature=True: embeds the Python call signature in the docstring
86
86
  # so IDEs can show it even when the .pyi stub is absent.
87
87
  "embedsignature": True,
88
+ # annotation_typing defaults to True, which makes Cython treat a
89
+ # PEP 484 parameter annotation like
90
+ # `def correlation_matrix(df_dict: Dict[str, pd.DataFrame])`
91
+ # as a `cdef dict` declaration and enforce it at the C level.
92
+ #
93
+ # Two problems, both COMPILED-ONLY -- they cannot reproduce from
94
+ # source, which is the worst possible failure mode here:
95
+ #
96
+ # 1. Cython's builtin-container coercion is exact-type-only, so
97
+ # passing an OrderedDict/defaultdict/Counter to a
98
+ # Dict[...]-annotated parameter raises TypeError even though
99
+ # it is a perfectly good Mapping.
100
+ # 2. It pre-empts the library's own validation. The argument
101
+ # checks in analysis/stats.py exist to say "correlation_matrix()
102
+ # expects {symbol: DataFrame}, got a single DataFrame" -- but
103
+ # with annotation_typing on, Cython rejects the call first with
104
+ # a terse message naming neither the function nor the fix.
105
+ #
106
+ # pypsx set this to False for the same reason; the toolkit had
107
+ # been left on the default.
108
+ "annotation_typing": False,
88
109
  },
89
110
  build_dir="build",
90
111
  annotate=False,
File without changes
File without changes
File without changes