fin68 0.1.3__cp312-cp312-macosx_10_13_universal2.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.
Files changed (55) hide show
  1. fin68/__init__.py +323 -0
  2. fin68/__init__.pyi +81 -0
  3. fin68/_core/__init__.py +0 -0
  4. fin68/_version.py +17 -0
  5. fin68/auth/__init__.py +0 -0
  6. fin68/auth/api_key.py +0 -0
  7. fin68/clients/__init__.py +3 -0
  8. fin68/clients/base.py +17 -0
  9. fin68/clients/eod/MarketEod.py +142 -0
  10. fin68/clients/eod/MarketEod.pyi +95 -0
  11. fin68/clients/eod/SectorEod.py +146 -0
  12. fin68/clients/eod/SectorEod.pyi +86 -0
  13. fin68/clients/eod/StockEod.py +134 -0
  14. fin68/clients/eod/StockEod.pyi +92 -0
  15. fin68/clients/eod/__init__.py +6 -0
  16. fin68/clients/eod/helper.py +65 -0
  17. fin68/clients/eod/icb_types.py +111 -0
  18. fin68/clients/eod_main.py +169 -0
  19. fin68/clients/eod_main.pyi +102 -0
  20. fin68/clients/financials.py +0 -0
  21. fin68/clients/index.py +0 -0
  22. fin68/clients/info.py +0 -0
  23. fin68/config.py +0 -0
  24. fin68/exceptions.py +28 -0
  25. fin68/models/__init__.py +0 -0
  26. fin68/models/base.py +0 -0
  27. fin68/models/eod.py +0 -0
  28. fin68/models/financials.py +0 -0
  29. fin68/models/index.py +0 -0
  30. fin68/models/meta.py +0 -0
  31. fin68/transport/__init__.py +0 -0
  32. fin68/transport/cache.py +0 -0
  33. fin68/transport/http.py +0 -0
  34. fin68/transport/rate_limiter.py +0 -0
  35. fin68/types.py +90 -0
  36. fin68/utils/__init__.py +5 -0
  37. fin68/utils/_validate_date_eod.py +9 -0
  38. fin68/utils/convert.py +0 -0
  39. fin68/utils/pagination.py +0 -0
  40. fin68/utils/time.py +0 -0
  41. fin68/validators.py +0 -0
  42. fin68-0.1.3.dist-info/METADATA +129 -0
  43. fin68-0.1.3.dist-info/RECORD +55 -0
  44. fin68-0.1.3.dist-info/WHEEL +6 -0
  45. fin68-0.1.3.dist-info/licenses/LICENSE +21 -0
  46. fin68-0.1.3.dist-info/top_level.txt +2 -0
  47. private_core/__init__.py +1 -0
  48. private_core/auth_core.cpython-312-darwin.so +0 -0
  49. private_core/eod_core.cpython-312-darwin.so +0 -0
  50. private_core/financials_core.cpython-312-darwin.so +0 -0
  51. private_core/helpers.cpython-312-darwin.so +0 -0
  52. private_core/http_core.cpython-312-darwin.so +0 -0
  53. private_core/index_core.cpython-312-darwin.so +0 -0
  54. private_core/progress.cpython-312-darwin.so +0 -0
  55. private_core/utils_core.cpython-312-darwin.so +0 -0
@@ -0,0 +1,146 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ fin68.clients.eod.sector
5
+ ========================
6
+
7
+ Cung cấp lớp `SectorEod` — các endpoint EOD (End-of-Day) cho dữ liệu ngành (ICB Sector Aggregates).
8
+
9
+ Dữ liệu thể hiện hiệu suất, biến động, và khối lượng giao dịch trung bình của từng ngành
10
+ (ICB Code) hoặc nhóm ngành (Sub-sector). Phù hợp cho phân tích xoay vòng ngành (sector rotation)
11
+ và đánh giá xu hướng thị trường theo nhóm.
12
+
13
+ Notes
14
+ -----
15
+ - Dữ liệu được lấy qua `private_core.eod_core.fetch_ohlcv()`.
16
+ - Tất cả kết quả trả về dạng `pandas.DataFrame`.
17
+ - Cho phép truy vấn nhiều mã ngành cùng lúc.
18
+ """
19
+
20
+ from typing import TYPE_CHECKING, Sequence, Union
21
+ from private_core import eod_core
22
+ from ..base import BaseClient
23
+ from .helper import DateStr, Interval, _EodMixin
24
+ from .icb_types import SectorArg,icbMap
25
+ if TYPE_CHECKING:
26
+ from pandas import DataFrame
27
+ from private_core.http_core import HttpSession
28
+
29
+
30
+
31
+
32
+ class SectorEod(BaseClient, _EodMixin):
33
+ """
34
+ Cung cấp các endpoint EOD cho nhóm ngành (ICB Sector/Industry).
35
+
36
+ Lớp này giúp truy vấn dữ liệu tổng hợp cho từng ngành (ICB Code) theo ngày, tuần, tháng, v.v.
37
+
38
+ Parameters
39
+ ----------
40
+ session : HttpSession
41
+ Phiên HTTP đã xác thực, được truyền từ `EodClient`.
42
+
43
+ Notes
44
+ -----
45
+ - Cho phép lấy dữ liệu nhiều mã ngành cùng lúc (list[str]).
46
+ - Hỗ trợ chuẩn hóa khoảng thời gian và kiểm tra `interval`.
47
+ - Trả về OHLCV (Open, High, Low, Close, Volume) trung bình của từng ngành.
48
+ - Các mã ngành tuân theo chuẩn phân loại ICB (ví dụ: `ICB01010`, `ICB03020`...).
49
+ """
50
+
51
+ def __init__(self, session: "HttpSession") -> None:
52
+ """
53
+ Khởi tạo `SectorEod` với session HTTP đã xác thực.
54
+
55
+ Parameters
56
+ ----------
57
+ session : HttpSession
58
+ Phiên HTTP dùng chung từ `EodClient`.
59
+ """
60
+ super().__init__(session=session)
61
+
62
+ def ohlcv(
63
+ self,
64
+ symbol: SectorArg,
65
+ start: DateStr = None,
66
+ end: DateStr = None,
67
+ interval: Interval = "1D",
68
+ ) -> "DataFrame":
69
+ """
70
+ Lấy dữ liệu OHLCV (Open, High, Low, Close, Volume) cho một hoặc nhiều ngành ICB.
71
+
72
+ Parameters
73
+ ----------
74
+ symbol : str or Sequence[str]
75
+ Mã ngành hoặc danh sách mã ngành (ví dụ: `"ICB01010"`, `["ICB01010", "ICB03020"]`).
76
+ start : str, optional
77
+ Ngày bắt đầu, định dạng `"YYYY-MM-DD"`.
78
+ Nếu không truyền, hệ thống sẽ chọn mặc định (thường là 1 năm gần nhất).
79
+ end : str, optional
80
+ Ngày kết thúc, định dạng `"YYYY-MM-DD"`.
81
+ Nếu không truyền, mặc định là ngày hiện tại.
82
+ interval : {"1D", "1W", "1M", "3M", "6M", "1Y"}, default "1D"
83
+ Khoảng thời gian dữ liệu:
84
+ - `"1D"`: theo ngày
85
+ - `"1W"`: theo tuần
86
+ - `"1M"`: theo tháng
87
+ - `"3M"`, `"6M"`, `"1Y"`: theo quý, nửa năm hoặc năm
88
+
89
+ Returns
90
+ -------
91
+ DataFrame
92
+ Bảng dữ liệu OHLCV cho từng mã ngành, gồm:
93
+ - `icbCode`: mã ngành
94
+ - `Date`: ngày giao dịch
95
+ - `Open`, `High`, `Low`, `Close`, `Volume`
96
+ - Có thể có thêm `MarketCap`, `TurnoverRatio` nếu backend hỗ trợ.
97
+
98
+ Raises
99
+ ------
100
+ ValueError
101
+ Nếu ngày bắt đầu > ngày kết thúc hoặc `interval` không hợp lệ.
102
+ ApiRequestError
103
+ Nếu backend trả lỗi khi gọi API.
104
+
105
+ Examples
106
+ --------
107
+ >>> from fin68 import client
108
+ >>> cli = client(api_key="sk_live_...")
109
+ >>> df = cli.eod.sector.ohlcv("ICB01010", start="2024-01-01", end="2024-06-30")
110
+ >>> df.head()
111
+ icbCode Date Open High Low Close Volume
112
+ 0 ICB01010 2024-01-02 1320.25 1334.11 1305.21 1310.55 9.32e6
113
+
114
+ >>> # Lấy đồng thời nhiều ngành
115
+ >>> cli.eod.sector.ohlcv(["ICB01010", "ICB03020"])
116
+
117
+ Notes
118
+ -----
119
+ - Phù hợp để phân tích hiệu suất ngành theo thời gian.
120
+ - Dữ liệu thường được tổng hợp từ trung bình trọng số theo vốn hóa.
121
+ - Wrapper của `private_core.eod_core.fetch_ohlcv`.
122
+ """
123
+ icb_codes=[]
124
+ if isinstance(symbol, list):
125
+ for sec in symbol:
126
+ if sec.lower() not in icbMap:
127
+ raise ValueError(f"Không tìm thấy mã ngành cho tên '{sec}'")
128
+ icb_codes.append(icbMap.get(sec.lower()))
129
+ else:
130
+ if symbol.lower() not in icbMap:
131
+ raise ValueError(f"Không tìm thấy mã ngành cho tên '{symbol}'")
132
+ icb_codes.append(icbMap.get(symbol.lower()))
133
+
134
+
135
+ if not symbol:
136
+ raise ValueError(f"Không tìm thấy mã ngành cho tên '{symbol}'")
137
+ start_date, end_date = self._normalize_range(start, end)
138
+ interval_value = self._validate_interval(interval)
139
+ payload = eod_core.fetch_ohlcv(
140
+ self.session,
141
+ icb_codes,
142
+ start=start_date,
143
+ end=end_date,
144
+ interval=interval_value,
145
+ )
146
+ return self._to_dataframe(payload)
@@ -0,0 +1,86 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ fin68.clients.eod.sector (stub)
5
+ ==============================
6
+
7
+ Type stub cho lớp `SectorEod` — phục vụ autocomplete/typing trong IDE và
8
+ static type checker. Không thực thi logic, chỉ khai báo kiểu & docstring ngắn.
9
+ """
10
+
11
+ from typing import TYPE_CHECKING, Sequence, Union
12
+ from ..base import BaseClient
13
+ from .helper import DateStr, Interval,IcbName, _EodMixin
14
+ from .icb_types import SectorArg
15
+ if TYPE_CHECKING:
16
+ from pandas import DataFrame
17
+ from private_core.http_core import HttpSession
18
+
19
+
20
+
21
+ class SectorEod(BaseClient, _EodMixin):
22
+ """
23
+ Endpoint EOD cho dữ liệu ngành (ICB Sector Aggregates).
24
+
25
+ Parameters
26
+ ----------
27
+ session : HttpSession
28
+ Phiên HTTP đã xác thực, truyền từ `EodClient`.
29
+
30
+ Notes
31
+ -----
32
+ - Hỗ trợ nhiều mã ngành cùng lúc (list[str]).
33
+ - Chuẩn hóa khoảng thời gian, validate `interval`.
34
+ - Trả về OHLCV trung bình/tổng hợp cho từng ngành.
35
+ """
36
+
37
+ def __init__(self, session: "HttpSession") -> None: ...
38
+ """
39
+ Khởi tạo `SectorEod` với session HTTP đã xác thực.
40
+
41
+ Parameters
42
+ ----------
43
+ session : HttpSession
44
+ Phiên HTTP dùng chung từ `EodClient`.
45
+ """
46
+
47
+ def ohlcv(
48
+ self,
49
+ symbol: SectorArg,
50
+ start: DateStr = None,
51
+ end: DateStr = None,
52
+ interval: Interval = "1D",
53
+ ) -> "DataFrame": ...
54
+ """
55
+ Lấy dữ liệu OHLCV (Open, High, Low, Close, Volume) cho một hoặc nhiều ngành ICB.
56
+
57
+ Parameters
58
+ ----------
59
+ symbol : str or Sequence[str]
60
+ Mã ngành hoặc danh sách mã ngành (VD: "ICB01010", ["ICB01010", "ICB03020"]).
61
+ start : str, optional
62
+ Ngày bắt đầu "YYYY-MM-DD". Nếu None, dùng mặc định hệ thống.
63
+ end : str, optional
64
+ Ngày kết thúc "YYYY-MM-DD". Nếu None, mặc định là hôm nay.
65
+ interval : {"1D", "1W", "1M", "3M", "6M", "1Y"}, default "1D"
66
+ Khoảng thời gian lấy dữ liệu.
67
+
68
+ Returns
69
+ -------
70
+ DataFrame
71
+ Gồm các cột cơ bản: `icbCode`, `Date`, `Open`, `High`, `Low`, `Close`, `Volume`.
72
+
73
+ Raises
74
+ ------
75
+ ValueError
76
+ Nếu `start > end` hoặc `interval` không hợp lệ.
77
+ ApiRequestError
78
+ Nếu backend trả lỗi khi gọi API.
79
+
80
+ Examples
81
+ --------
82
+ >>> from fin68 import client
83
+ >>> cli = client(api_key="sk_live_...")
84
+ >>> cli.eod.sector.ohlcv("ICB01010", start="2024-01-01", end="2024-06-30")
85
+ >>> cli.eod.sector.ohlcv(["ICB01010", "ICB03020"])
86
+ """
@@ -0,0 +1,134 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ fin68.clients.eod.stock
5
+ =======================
6
+
7
+ Cung cấp lớp `StockEod` — tập trung các endpoint EOD dành cho từng mã cổ phiếu riêng lẻ.
8
+ Bao gồm dữ liệu OHLCV (Open, High, Low, Close, Volume), điều chỉnh giá (adjusted) và
9
+ hỗ trợ các khoảng thời gian khác nhau (ngày, tuần, tháng...).
10
+
11
+ Notes
12
+ -----
13
+ - Dữ liệu lấy từ `private_core.eod_core.fetch_ohlcv()`.
14
+ - Tất cả kết quả được trả về dưới dạng `pandas.DataFrame`.
15
+ - Tự động kiểm tra và chuẩn hóa ngày bắt đầu/kết thúc, validate interval.
16
+ """
17
+
18
+ from typing import TYPE_CHECKING, Sequence, Union
19
+
20
+ from private_core import eod_core
21
+ from ..base import BaseClient
22
+ from .helper import DateStr, Interval, _EodMixin
23
+
24
+ if TYPE_CHECKING:
25
+ from pandas import DataFrame
26
+ from private_core.http_core import HttpSession
27
+
28
+ SymbolArg = Union[str, Sequence[str]]
29
+
30
+
31
+ class StockEod(BaseClient, _EodMixin):
32
+ """
33
+ Cung cấp các endpoint EOD cho từng mã cổ phiếu (equity symbol).
34
+
35
+ Lớp này cho phép truy vấn dữ liệu giá, khối lượng và chỉ báo kỹ thuật
36
+ ở cấp mã cổ phiếu, tương tự như chức năng `get_price_data()` trong các
37
+ hệ thống tài chính chuyên nghiệp.
38
+
39
+ Parameters
40
+ ----------
41
+ session : HttpSession
42
+ Phiên HTTP đã xác thực, được truyền từ `EodClient`.
43
+
44
+ Notes
45
+ -----
46
+ - Toàn bộ phương thức đều hỗ trợ truy vấn nhiều mã cùng lúc (`list[str]`).
47
+ - Có thể chọn chế độ `adjusted=True` để lấy dữ liệu điều chỉnh cổ tức/chia tách.
48
+ - Hàm `_EodMixin` cung cấp các helper cho việc chuẩn hóa khoảng thời gian
49
+ (`_normalize_range`) và kiểm tra tính hợp lệ của `interval`.
50
+ """
51
+
52
+ def __init__(self, session: "HttpSession") -> None:
53
+ """
54
+ Khởi tạo lớp `StockEod` với session HTTP đã được xác thực.
55
+
56
+ Parameters
57
+ ----------
58
+ session : HttpSession
59
+ Phiên HTTP dùng chung từ `EodClient`.
60
+ """
61
+ super().__init__(session=session)
62
+
63
+ def ohlcv(
64
+ self,
65
+ symbol: SymbolArg,
66
+ start: DateStr = None,
67
+ end: DateStr = None,
68
+ adjusted: bool = True,
69
+ interval: Interval = "1D",
70
+ ) -> "DataFrame":
71
+ """
72
+ Lấy dữ liệu OHLCV (Open, High, Low, Close, Volume) cho một hoặc nhiều mã cổ phiếu.
73
+
74
+ Parameters
75
+ ----------
76
+ symbol : str or Sequence[str]
77
+ Mã cổ phiếu hoặc danh sách mã cổ phiếu cần lấy dữ liệu (VD: `"HPG"`, `["HPG", "VCB"]`).
78
+ start : str, optional
79
+ Ngày bắt đầu, định dạng `"YYYY-MM-DD"`.
80
+ Nếu không truyền, hệ thống sẽ tự động lấy ngược về theo khoảng mặc định.
81
+ end : str, optional
82
+ Ngày kết thúc, định dạng `"YYYY-MM-DD"`.
83
+ Nếu không truyền, mặc định là ngày hiện tại.
84
+ adjusted : bool, default True
85
+ Nếu `True`, trả về giá đã điều chỉnh theo cổ tức và chia tách cổ phiếu.
86
+ interval : {"1D", "1W", "1M", "3M", "6M", "1Y"}, default "1D"
87
+ Khoảng thời gian dữ liệu cần lấy:
88
+ - `"1D"`: theo ngày
89
+ - `"1W"`: theo tuần
90
+ - `"1M"`: theo tháng
91
+ - `"3M"`, `"6M"`, `"1Y"`: theo quý, nửa năm, hoặc năm
92
+
93
+ Returns
94
+ -------
95
+ DataFrame
96
+ Bảng dữ liệu gồm các cột:
97
+ - `symbol`: mã cổ phiếu
98
+ - `Date`: ngày giao dịch
99
+ - `Open`, `High`, `Low`, `Close`, `Volume`
100
+ - Các cột bổ sung nếu backend cung cấp (ví dụ: `Adj Close`)
101
+
102
+ Raises
103
+ ------
104
+ ValueError
105
+ Khi tham số `start` > `end`, hoặc `interval` không hợp lệ.
106
+ ApiRequestError
107
+ Khi backend trả lỗi trong quá trình gọi API.
108
+
109
+ Examples
110
+ --------
111
+ >>> from fin68 import client
112
+ >>> cli = client(api_key="sk_live_...")
113
+ >>> df = cli.eod.stock.ohlcv("HPG", start="2024-01-01", end="2024-06-30")
114
+ >>> df.head()
115
+ symbol Date Open High Low Close Volume
116
+ 0 HPG 2024-01-02 27200 27500 26900 27400 15300000
117
+
118
+ Notes
119
+ -----
120
+ - Tự động validate khoảng thời gian (`start <= end`).
121
+ - Có thể truy vấn nhiều mã cùng lúc để so sánh hiệu suất.
122
+ - Hàm này là wrapper của `private_core.eod_core.fetch_ohlcv`.
123
+ """
124
+ start_date, end_date = self._normalize_range(start, end)
125
+ interval_value = self._validate_interval(interval)
126
+ payload = eod_core.fetch_ohlcv(
127
+ self.session,
128
+ symbol,
129
+ start=start_date,
130
+ end=end_date,
131
+ adjusted=adjusted,
132
+ interval=interval_value,
133
+ )
134
+ return self._to_dataframe(payload)
@@ -0,0 +1,92 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ fin68.clients.eod.stock (stub)
5
+ ==============================
6
+
7
+ Type stub cho lớp `StockEod` — phục vụ autocomplete/typing trong IDE (VSCode/PyCharm)
8
+ và static type checker (mypy/pyright). Không thực thi logic.
9
+
10
+ Ghi chú
11
+ -------
12
+ - Docstring giữ chuẩn NumPy style như bản .py.
13
+ - Các thân hàm được thay bằng `...` (ellipsis) theo PEP 484.
14
+ """
15
+
16
+ from typing import TYPE_CHECKING, Sequence, Union
17
+ from ..base import BaseClient
18
+ from .helper import DateStr, Interval, _EodMixin
19
+
20
+ if TYPE_CHECKING:
21
+ from pandas import DataFrame
22
+ from private_core.http_core import HttpSession
23
+
24
+ SymbolArg = Union[str, Sequence[str]]
25
+
26
+ class StockEod(BaseClient, _EodMixin):
27
+ """
28
+ Cung cấp các endpoint EOD cho từng mã cổ phiếu (equity symbol).
29
+
30
+ Parameters
31
+ ----------
32
+ session : HttpSession
33
+ Phiên HTTP đã xác thực, được truyền từ `EodClient`.
34
+
35
+ Notes
36
+ -----
37
+ - Hỗ trợ truy vấn nhiều mã cùng lúc (`list[str]`).
38
+ - Có `adjusted=True` để lấy giá đã điều chỉnh cổ tức/chia tách.
39
+ - Kế thừa `_EodMixin` để chuẩn hóa khoảng thời gian và validate interval.
40
+ """
41
+
42
+ def __init__(self, session: "HttpSession") -> None: ...
43
+ """
44
+ Khởi tạo `StockEod` với session đã xác thực.
45
+
46
+ Parameters
47
+ ----------
48
+ session : HttpSession
49
+ Phiên HTTP dùng chung từ `EodClient`.
50
+ """
51
+
52
+ def ohlcv(
53
+ self,
54
+ symbol: SymbolArg,
55
+ start: DateStr = None,
56
+ end: DateStr = None,
57
+ interval: Interval = "1D",
58
+ ) -> "DataFrame": ...
59
+ """
60
+ Lấy dữ liệu OHLCV (Open, High, Low, Close, Volume) cho một hoặc nhiều mã cổ phiếu.
61
+
62
+ Parameters
63
+ ----------
64
+ symbol : str or Sequence[str]
65
+ Mã cổ phiếu hoặc danh sách mã (VD: "HPG", ["HPG", "VCB"]).
66
+ start : str, optional
67
+ Ngày bắt đầu, định dạng "YYYY-MM-DD". Nếu `None`, dùng mặc định hệ thống.
68
+ end : str, optional
69
+ Ngày kết thúc, định dạng "YYYY-MM-DD". Nếu `None`, mặc định là hôm nay.
70
+ interval : {"1D", "1W", "1M", "3M", "6M", "1Y"}, default "1D"
71
+ Khoảng thời gian lấy dữ liệu.
72
+
73
+ Returns
74
+ -------
75
+ DataFrame
76
+ Gồm các cột cơ bản: `symbol`, `Date`, `Open`, `High`, `Low`, `Close`, `Volume`.
77
+
78
+
79
+ Raises
80
+ ------
81
+ ValueError
82
+ Nếu `start > end` hoặc `interval` không hợp lệ.
83
+ ApiRequestError
84
+ Nếu backend trả lỗi khi gọi API.
85
+
86
+ Examples
87
+ --------
88
+ >>> from fin68 import client
89
+ >>> cli = client(api_key="sk_live_...")
90
+ >>> df = cli.eod.stock.ohlcv("HPG", start="2024-01-01", end="2024-06-30")
91
+ >>> df.head()
92
+ """
@@ -0,0 +1,6 @@
1
+ from .helper import DateStr, Interval
2
+ from .MarketEod import MarketEod
3
+ from .SectorEod import SectorEod
4
+ from .StockEod import StockEod
5
+
6
+ __all__ = ["DateStr", "Interval", "StockEod", "MarketEod", "SectorEod"]
@@ -0,0 +1,65 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import date, datetime, timedelta
4
+ from typing import ClassVar, Iterable, Literal, Optional, TypeAlias,Union,Sequence
5
+
6
+ import pandas as pd
7
+
8
+ from ...utils import _validate_date_eod
9
+
10
+ DateStr: TypeAlias = Optional[str]
11
+ Interval = Literal["1D", "1W", "1M", "3M", "6M", "1Y"]
12
+
13
+
14
+
15
+ class _EodMixin:
16
+ """Common helpers shared across EOD namespaces."""
17
+
18
+ _DEFAULT_LOOKBACK_DAYS: ClassVar[int] = 30
19
+ _ALLOWED_INTERVALS: ClassVar[set[str]] = {"1D", "1W", "1M", "3M", "6M", "1Y"}
20
+
21
+ def _normalize_range(self, start: DateStr, end: DateStr) -> tuple[str, str]:
22
+ """Return a validated (start, end) date pair in ISO format."""
23
+ today = date.today()
24
+
25
+ if end is None:
26
+ end_date = today
27
+ else:
28
+ _validate_date_eod(end, "end")
29
+ end_date = datetime.strptime(end, "%Y-%m-%d").date()
30
+
31
+ if start is None:
32
+ start_date = end_date - timedelta(days=self._DEFAULT_LOOKBACK_DAYS)
33
+ else:
34
+ _validate_date_eod(start, "start")
35
+ start_date = datetime.strptime(start, "%Y-%m-%d").date()
36
+
37
+ if start_date > end_date:
38
+ raise ValueError(
39
+ f"start date ({start_date:%Y-%m-%d}) cannot be after end date ({end_date:%Y-%m-%d})."
40
+ )
41
+
42
+ return start_date.strftime("%Y-%m-%d"), end_date.strftime("%Y-%m-%d")
43
+
44
+ def _validate_interval(self, interval: Interval) -> Interval:
45
+ """Ensure the provided interval value is supported by the backend."""
46
+ if interval not in self._ALLOWED_INTERVALS:
47
+ allowed = ", ".join(sorted(self._ALLOWED_INTERVALS))
48
+ raise ValueError(f"interval must be one of {{{allowed}}}, received {interval!r}.")
49
+ return interval
50
+
51
+ @staticmethod
52
+ def _to_dataframe(rows: Iterable[dict]) -> pd.DataFrame:
53
+ """Materialise raw rows into a sorted pandas.DataFrame."""
54
+ frame = pd.DataFrame(rows)
55
+ if frame.empty:
56
+ return frame
57
+
58
+ if "date" in frame.columns:
59
+ frame["date"] = pd.to_datetime(frame["date"], errors="coerce")
60
+
61
+ sort_cols = [column for column in ("symbol", "date") if column in frame.columns]
62
+ if sort_cols:
63
+ frame = frame.sort_values(sort_cols).reset_index(drop=True)
64
+
65
+ return frame
@@ -0,0 +1,111 @@
1
+ from typing import ClassVar, Iterable, Literal, Optional, TypeAlias,Union,Sequence
2
+ icbMap={'xây dựng': '2357',
3
+ 'vật liệu xây dựng & nội thất': '2353',
4
+ 'đường sắt': '2775',
5
+ 'kho bãi, hậu cần và bảo dưỡng': '2777',
6
+ 'dịch vụ vận tải': '2779',
7
+ 'tư vấn & hỗ trợ kd': '2791',
8
+ 'đào tạo & việc làm': '2793',
9
+ 'công nghiệp hàng không': '2713',
10
+ 'quốc phòng': '2717',
11
+ 'containers & đóng gói': '2723',
12
+ 'công nghiệp phức hợp': '2727',
13
+ 'hàng điện & điện tử': '2733',
14
+ 'thiết bị điện': '2737',
15
+ 'xe tải & đóng tàu': '2753',
16
+ 'máy công nghiệp': '2757',
17
+ 'chuyển phát nhanh': '2771',
18
+ 'vận tải thủy': '2773',
19
+ 'nhựa, cao su & sợi': '1353',
20
+ 'sản phẩm hóa dầu, nông dược & hóa chất khác': '1357',
21
+ 'lâm sản và chế biến gỗ': '1733',
22
+ 'sản xuất giấy': '1737',
23
+ 'nhôm': '1753',
24
+ 'kim loại màu': '1755',
25
+ 'thép và sản phẩm thép': '1757',
26
+ 'khai thác than': '1771',
27
+ 'đá quý và kim cương': '1773',
28
+ 'khai khoáng': '1775',
29
+ 'khai thác vàng': '1777',
30
+ 'bạch kim & kim loại quý khác': '1779',
31
+ 'quản lý tài chính': '2795',
32
+ 'chất thải & môi trường': '2799',
33
+ 'sản xuất ô tô': '3353',
34
+ 'phụ tùng ô tô': '3355',
35
+ 'lốp xe': '3357',
36
+ 'sản xuất và khai thác dầu khí': '0533',
37
+ 'tổ hợp dầu khí': '0537',
38
+ 'thiết bị và dịch vụ dầu khí': '0573',
39
+ 'ống dẫn dầu': '0577',
40
+ 'thiết bị năng lượng tái chế': '0583',
41
+ 'nhiên liệu thay thế': '0587',
42
+ 'nhà cung cấp thiết bị': '2797',
43
+ 'sản xuất bia': '3533',
44
+ 'vang & rượu mạnh': '3535',
45
+ 'đồ uống & giải khát': '3537',
46
+ 'nuôi trồng nông & hải sản': '3573',
47
+ 'thực phẩm': '3577',
48
+ 'đồ gia dụng lâu bền': '3722',
49
+ 'đồ gia dụng một lần': '3724',
50
+ 'thiết bị gia dụng': '3726',
51
+ 'xây nhà': '3728',
52
+ 'điện tử tiêu dùng': '3743',
53
+ 'sản phẩm nghệ thuật': '3745',
54
+ 'đồ chơi': '3747',
55
+ 'hàng may mặc': '3763',
56
+ 'giầy dép': '3765',
57
+ 'hàng cá nhân': '3767',
58
+ 'thuốc lá': '3785',
59
+ 'chăm sóc y tế': '4533',
60
+ 'thiết bị y tế': '4535',
61
+ 'dụng cụ y tế': '4537',
62
+ 'công nghệ sinh học': '4573',
63
+ 'dược phẩm': '4577',
64
+ 'phân phối dược phẩm': '5333',
65
+ 'phân phối thực phẩm': '5337',
66
+ 'giải trí & truyền thông': '5553',
67
+ 'dịch vụ truyền thông': '5555',
68
+ 'sách, ấn bản & sản phẩm văn hóa': '5557',
69
+ 'nhà hàng và quán bar': '5757',
70
+ 'vận tải hành khách & du lịch': '5759',
71
+ 'viễn thông cố định': '6535',
72
+ 'môi giới bảo hiểm': '8534',
73
+ 'bảo hiểm phi nhân thọ': '8536',
74
+ 'tái bảo hiểm': '8538',
75
+ 'bảo hiểm nhân thọ': '8575',
76
+ 'bán lẻ hàng may mặc': '5371',
77
+ 'bán lẻ phức hợp': '5373',
78
+ 'phân phối nội thất': '5375',
79
+ 'dịch vụ tiêu dùng chuyên ngành': '5377',
80
+ 'phân phối hàng chuyên dụng': '5379',
81
+ 'dịch vụ hàng không': '5751',
82
+ 'gambling': '5752',
83
+ 'khách sạn': '5753',
84
+ 'dịch vụ giải trí': '5755',
85
+ 'viễn thông di động': '6575',
86
+ 'ngân hàng': '8355',
87
+ 'bảo hiểm phức hợp': '8532',
88
+ 'sản xuất & phân phối điện': '7535',
89
+ 'phân phối xăng dầu & khí đốt': '7573',
90
+ 'tiện ích khác': '7575',
91
+ 'nước': '7577',
92
+ 'bất động sản': '8633',
93
+ 'phần mềm': '9537',
94
+ 'phần cứng': '9572',
95
+ 'thiết bị văn phòng': '9574',
96
+ 'bán dẫn': '9576',
97
+ 'thiết bị viễn thông': '9578',
98
+ 'tư vấn, định giá, môi giới bất động sản': '8637',
99
+ 'quỹ ủy thác bđs': '8677',
100
+ 'quản lý tài sản': '8771',
101
+ 'tài chính cá nhân': '8773',
102
+ 'tài chính đặc biệt': '8775',
103
+ 'môi giới chứng khoán': '8777',
104
+ 'cầm cố': '8779',
105
+ 'quỹ đầu tư': '8985',
106
+ 'dịch vụ máy tính': '9533',
107
+ 'internet': '9535'}
108
+ SectorArg = Union[
109
+ Literal['Xây dựng', 'Vật liệu xây dựng & Nội thất', 'Đường sắt', 'Kho bãi, hậu cần và bảo dưỡng', 'Dịch vụ vận tải', 'Tư vấn & Hỗ trợ KD', 'Đào tạo & Việc làm', 'Công nghiệp hàng không', 'Quốc phòng', 'Containers & Đóng gói', 'Công nghiệp phức hợp', 'Hàng điện & điện tử', 'Thiết bị điện', 'Xe tải & Đóng tàu', 'Máy công nghiệp', 'Chuyển phát nhanh', 'Vận tải Thủy', 'Nhựa, cao su & sợi', 'Sản phẩm hóa dầu, Nông dược & Hóa chất khác', 'Lâm sản và Chế biến gỗ', 'Sản xuất giấy', 'Nhôm', 'Kim Loại màu', 'Thép và sản phẩm thép', 'Khai thác Than', 'Đá quý và Kim cương', 'Khai khoáng', 'Khai thác vàng', 'Bạch kim & Kim loại quý khác', 'Quản lý Tài chính', 'Chất thải & Môi trường', 'Sản xuất ô tô', 'Phụ tùng ô tô', 'Lốp xe', 'Sản xuất và Khai thác dầu khí', 'Tổ hợp Dầu khí', 'Thiết bị và Dịch vụ Dầu khí', 'Ống dẫn Dầu', 'Thiết bị năng lượng tái chế', 'Nhiên liệu thay thế', 'Nhà cung cấp thiết bị', 'Sản xuất bia', 'Vang & Rượu mạnh', 'Đồ uống & giải khát', 'Nuôi trồng nông & hải sản', 'Thực phẩm', 'Đồ gia dụng lâu bền', 'Đồ gia dụng một lần', 'Thiết bị gia dụng', 'Xây nhà', 'Điện tử tiêu dùng', 'Sản phẩm nghệ thuật', 'Đồ chơi', 'Hàng May mặc', 'Giầy dép', 'Hàng cá nhân', 'Thuốc lá', 'Chăm sóc y tế', 'Thiết bị y tế', 'Dụng cụ y tế', 'Công nghệ sinh học', 'Dược phẩm', 'Phân phối dược phẩm', 'Phân phối thực phẩm', 'Giải trí & Truyền thông', 'Dịch vụ truyền thông', 'Sách, ấn bản & sản phẩm văn hóa', 'Nhà hàng và quán bar', 'Vận tải hành khách & Du lịch', 'Viễn thông cố định', 'Môi giới bảo hiểm', 'Bảo hiểm phi nhân thọ', 'Tái bảo hiểm', 'Bảo hiểm nhân thọ', 'Bán lẻ hàng may mặc', 'Bán lẻ phức hợp', 'Phân phối nội thất', 'Dịch vụ tiêu dùng chuyên ngành', 'Phân phối hàng chuyên dụng', 'Dịch vụ hàng không', 'Gambling', 'Khách sạn', 'Dịch vụ giải trí', 'Viễn thông di động', 'Ngân hàng', 'Bảo hiểm phức hợp', 'Sản xuất & Phân phối Điện', 'Phân phối xăng dầu & khí đốt', 'Tiện ích khác', 'Nước', 'Bất động sản', 'Phần mềm', 'Phần cứng', 'Thiết bị văn phòng', 'Bán dẫn', 'Thiết bị viễn thông', 'Tư Vấn, Định giá, Môi giới Bất động sản', 'Quỹ ủy thác BĐS', 'Quản lý tài sản', 'Tài chính cá nhân', 'Tài chính đặc biệt', 'Môi giới chứng khoán', 'Cầm cố', 'Quỹ đầu tư', 'Dịch vụ Máy tính', 'Internet'],
110
+ Sequence[
111
+ Literal['Xây dựng', 'Vật liệu xây dựng & Nội thất', 'Đường sắt', 'Kho bãi, hậu cần và bảo dưỡng', 'Dịch vụ vận tải', 'Tư vấn & Hỗ trợ KD', 'Đào tạo & Việc làm', 'Công nghiệp hàng không', 'Quốc phòng', 'Containers & Đóng gói', 'Công nghiệp phức hợp', 'Hàng điện & điện tử', 'Thiết bị điện', 'Xe tải & Đóng tàu', 'Máy công nghiệp', 'Chuyển phát nhanh', 'Vận tải Thủy', 'Nhựa, cao su & sợi', 'Sản phẩm hóa dầu, Nông dược & Hóa chất khác', 'Lâm sản và Chế biến gỗ', 'Sản xuất giấy', 'Nhôm', 'Kim Loại màu', 'Thép và sản phẩm thép', 'Khai thác Than', 'Đá quý và Kim cương', 'Khai khoáng', 'Khai thác vàng', 'Bạch kim & Kim loại quý khác', 'Quản lý Tài chính', 'Chất thải & Môi trường', 'Sản xuất ô tô', 'Phụ tùng ô tô', 'Lốp xe', 'Sản xuất và Khai thác dầu khí', 'Tổ hợp Dầu khí', 'Thiết bị và Dịch vụ Dầu khí', 'Ống dẫn Dầu', 'Thiết bị năng lượng tái chế', 'Nhiên liệu thay thế', 'Nhà cung cấp thiết bị', 'Sản xuất bia', 'Vang & Rượu mạnh', 'Đồ uống & giải khát', 'Nuôi trồng nông & hải sản', 'Thực phẩm', 'Đồ gia dụng lâu bền', 'Đồ gia dụng một lần', 'Thiết bị gia dụng', 'Xây nhà', 'Điện tử tiêu dùng', 'Sản phẩm nghệ thuật', 'Đồ chơi', 'Hàng May mặc', 'Giầy dép', 'Hàng cá nhân', 'Thuốc lá', 'Chăm sóc y tế', 'Thiết bị y tế', 'Dụng cụ y tế', 'Công nghệ sinh học', 'Dược phẩm', 'Phân phối dược phẩm', 'Phân phối thực phẩm', 'Giải trí & Truyền thông', 'Dịch vụ truyền thông', 'Sách, ấn bản & sản phẩm văn hóa', 'Nhà hàng và quán bar', 'Vận tải hành khách & Du lịch', 'Viễn thông cố định', 'Môi giới bảo hiểm', 'Bảo hiểm phi nhân thọ', 'Tái bảo hiểm', 'Bảo hiểm nhân thọ', 'Bán lẻ hàng may mặc', 'Bán lẻ phức hợp', 'Phân phối nội thất', 'Dịch vụ tiêu dùng chuyên ngành', 'Phân phối hàng chuyên dụng', 'Dịch vụ hàng không', 'Gambling', 'Khách sạn', 'Dịch vụ giải trí', 'Viễn thông di động', 'Ngân hàng', 'Bảo hiểm phức hợp', 'Sản xuất & Phân phối Điện', 'Phân phối xăng dầu & khí đốt', 'Tiện ích khác', 'Nước', 'Bất động sản', 'Phần mềm', 'Phần cứng', 'Thiết bị văn phòng', 'Bán dẫn', 'Thiết bị viễn thông', 'Tư Vấn, Định giá, Môi giới Bất động sản', 'Quỹ ủy thác BĐS', 'Quản lý tài sản', 'Tài chính cá nhân', 'Tài chính đặc biệt', 'Môi giới chứng khoán', 'Cầm cố', 'Quỹ đầu tư', 'Dịch vụ Máy tính', 'Internet']]]