laplace-python-sdk 0.4.0__tar.gz → 1.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.
- {laplace_python_sdk-0.4.0/src/laplace_python_sdk.egg-info → laplace_python_sdk-1.1.0}/PKG-INFO +1 -1
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/pyproject.toml +3 -3
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/base.py +31 -1
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/brokers.py +24 -19
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/capital_increase.py +8 -7
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/client.py +3 -1
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/collections.py +132 -29
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/financials.py +6 -3
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/live_price.py +85 -7
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/models.py +189 -204
- laplace_python_sdk-1.1.0/src/laplace/news.py +94 -0
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/search.py +9 -1
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/stocks.py +61 -13
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/websocket.py +20 -88
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0/src/laplace_python_sdk.egg-info}/PKG-INFO +1 -1
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace_python_sdk.egg-info/SOURCES.txt +1 -0
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/LICENSE +0 -0
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/MANIFEST.in +0 -0
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/README.md +0 -0
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/setup.cfg +0 -0
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/__init__.py +0 -0
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/earnings.py +0 -0
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/funds.py +0 -0
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/politician.py +0 -0
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace/state.py +0 -0
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace_python_sdk.egg-info/dependency_links.txt +0 -0
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace_python_sdk.egg-info/requires.txt +0 -0
- {laplace_python_sdk-0.4.0 → laplace_python_sdk-1.1.0}/src/laplace_python_sdk.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "laplace-python-sdk"
|
|
7
|
-
version = "
|
|
7
|
+
version = "1.1.0"
|
|
8
8
|
description = "Python SDK for Laplace stock data platform"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -64,14 +64,14 @@ profile = "black"
|
|
|
64
64
|
line_length = 100
|
|
65
65
|
|
|
66
66
|
[tool.mypy]
|
|
67
|
-
python_version = "
|
|
67
|
+
python_version = "1.1.0"
|
|
68
68
|
strict = true
|
|
69
69
|
warn_return_any = true
|
|
70
70
|
warn_unused_configs = true
|
|
71
71
|
|
|
72
72
|
[tool.ruff]
|
|
73
73
|
line-length = 100
|
|
74
|
-
target-version = "
|
|
74
|
+
target-version = "1.1.0"
|
|
75
75
|
select = ["E", "W", "F", "I", "N", "B", "UP"]
|
|
76
76
|
ignore = ["B008", "N805"]
|
|
77
77
|
|
|
@@ -39,7 +39,7 @@ class BaseClient:
|
|
|
39
39
|
self.base_url = base_url.rstrip("/")
|
|
40
40
|
self._client = httpx.Client(
|
|
41
41
|
headers={
|
|
42
|
-
"User-Agent": "laplace-python-sdk/
|
|
42
|
+
"User-Agent": "laplace-python-sdk/1.0.0",
|
|
43
43
|
},
|
|
44
44
|
timeout=30.0,
|
|
45
45
|
)
|
|
@@ -119,3 +119,33 @@ class BaseClient:
|
|
|
119
119
|
def delete(self, endpoint: str) -> Dict[str, Any]:
|
|
120
120
|
"""Make a DELETE request."""
|
|
121
121
|
return self._request("DELETE", endpoint)
|
|
122
|
+
|
|
123
|
+
def patch(self, endpoint: str, json: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
124
|
+
"""Make a PATCH request."""
|
|
125
|
+
return self._request("PATCH", endpoint, json=json)
|
|
126
|
+
|
|
127
|
+
def get_bytes(self, endpoint: str, params: Optional[Dict[str, Any]] = None) -> bytes:
|
|
128
|
+
"""Make a GET request and return raw bytes."""
|
|
129
|
+
url = f"{self.base_url}/{endpoint.lstrip('/')}"
|
|
130
|
+
|
|
131
|
+
if params is None:
|
|
132
|
+
params = {}
|
|
133
|
+
params["api_key"] = self.api_key
|
|
134
|
+
|
|
135
|
+
try:
|
|
136
|
+
response = self._client.request(method="GET", url=url, params=params)
|
|
137
|
+
response.raise_for_status()
|
|
138
|
+
return response.content
|
|
139
|
+
except httpx.HTTPStatusError as e:
|
|
140
|
+
try:
|
|
141
|
+
error_data = e.response.json()
|
|
142
|
+
except Exception:
|
|
143
|
+
error_data = {"error": e.response.text}
|
|
144
|
+
|
|
145
|
+
raise LaplaceAPIError(
|
|
146
|
+
message=f"API request failed: {e.response.status_code} {e.response.reason_phrase}",
|
|
147
|
+
status_code=e.response.status_code,
|
|
148
|
+
response=error_data,
|
|
149
|
+
) from e
|
|
150
|
+
except httpx.RequestError as e:
|
|
151
|
+
raise LaplaceAPIError(f"Request failed: {str(e)}") from e
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
"""Brokers client for Laplace API."""
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
|
+
from typing import Optional
|
|
4
5
|
|
|
5
6
|
from laplace.base import BaseClient
|
|
6
7
|
|
|
7
8
|
from .models import (
|
|
9
|
+
AssetClass,
|
|
8
10
|
Broker,
|
|
11
|
+
BrokerList,
|
|
9
12
|
PaginationPageSize,
|
|
10
13
|
Region,
|
|
11
|
-
|
|
12
|
-
BrokerStockData,
|
|
13
|
-
BrokerSortDirection,
|
|
14
|
+
SortDirection,
|
|
14
15
|
BrokerSort,
|
|
15
16
|
PaginatedResponse,
|
|
16
17
|
)
|
|
@@ -32,6 +33,7 @@ class BrokersClient:
|
|
|
32
33
|
region: Region = Region.TR,
|
|
33
34
|
page: int = 0,
|
|
34
35
|
size: PaginationPageSize = PaginationPageSize.PAGE_SIZE_10,
|
|
36
|
+
asset_class: Optional[AssetClass] = None
|
|
35
37
|
) -> PaginatedResponse[Broker]:
|
|
36
38
|
"""Retrieve all brokers.
|
|
37
39
|
|
|
@@ -47,6 +49,9 @@ class BrokersClient:
|
|
|
47
49
|
|
|
48
50
|
params = {"region": region.value, "page": page, "size": size.value}
|
|
49
51
|
|
|
52
|
+
if asset_class:
|
|
53
|
+
params["assetClass"] = asset_class.value
|
|
54
|
+
|
|
50
55
|
response = self._client.get("v1/brokers", params=params)
|
|
51
56
|
return PaginatedResponse[Broker](**response)
|
|
52
57
|
|
|
@@ -55,12 +60,12 @@ class BrokersClient:
|
|
|
55
60
|
symbol: str,
|
|
56
61
|
region: Region,
|
|
57
62
|
sort_by: BrokerSort,
|
|
58
|
-
sort_direction:
|
|
63
|
+
sort_direction: SortDirection,
|
|
59
64
|
from_date: datetime,
|
|
60
65
|
to_date: datetime,
|
|
61
66
|
page: int = 0,
|
|
62
67
|
size: PaginationPageSize = PaginationPageSize.PAGE_SIZE_10,
|
|
63
|
-
) ->
|
|
68
|
+
) -> BrokerList:
|
|
64
69
|
"""Retrieve broker information by symbol.
|
|
65
70
|
|
|
66
71
|
Args:
|
|
@@ -73,7 +78,7 @@ class BrokersClient:
|
|
|
73
78
|
page: Page number (default: 0)
|
|
74
79
|
size: Page size (default: 10)
|
|
75
80
|
Returns:
|
|
76
|
-
|
|
81
|
+
BrokerList: Broker information
|
|
77
82
|
"""
|
|
78
83
|
if region != Region.TR:
|
|
79
84
|
raise ValueError("Broker endpoint only works with the 'tr' region")
|
|
@@ -89,18 +94,18 @@ class BrokersClient:
|
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
response = self._client.get(f"v1/brokers/stock/{symbol}", params=params)
|
|
92
|
-
return
|
|
97
|
+
return BrokerList(**response)
|
|
93
98
|
|
|
94
99
|
def get_broker_list_for_market(
|
|
95
100
|
self,
|
|
96
101
|
region: Region,
|
|
97
102
|
sort_by: BrokerSort,
|
|
98
|
-
sort_direction:
|
|
103
|
+
sort_direction: SortDirection,
|
|
99
104
|
from_date: datetime,
|
|
100
105
|
to_date: datetime,
|
|
101
106
|
page: int = 0,
|
|
102
107
|
size: PaginationPageSize = PaginationPageSize.PAGE_SIZE_10,
|
|
103
|
-
) ->
|
|
108
|
+
) -> BrokerList:
|
|
104
109
|
"""Retrieve broker market data.
|
|
105
110
|
|
|
106
111
|
Args:
|
|
@@ -113,7 +118,7 @@ class BrokersClient:
|
|
|
113
118
|
size: Page size (default: 10)
|
|
114
119
|
|
|
115
120
|
Returns:
|
|
116
|
-
|
|
121
|
+
BrokerList: Broker market data
|
|
117
122
|
"""
|
|
118
123
|
if region != Region.TR:
|
|
119
124
|
raise ValueError("Broker market endpoint only works with the 'tr' region")
|
|
@@ -129,19 +134,19 @@ class BrokersClient:
|
|
|
129
134
|
}
|
|
130
135
|
|
|
131
136
|
response = self._client.get("v1/brokers/market", params=params)
|
|
132
|
-
return
|
|
137
|
+
return BrokerList(**response)
|
|
133
138
|
|
|
134
139
|
def get_broker_list_for_stock(
|
|
135
140
|
self,
|
|
136
141
|
symbol: str,
|
|
137
142
|
region: Region,
|
|
138
143
|
sort_by: BrokerSort,
|
|
139
|
-
sort_direction:
|
|
144
|
+
sort_direction: SortDirection,
|
|
140
145
|
from_date: datetime,
|
|
141
146
|
to_date: datetime,
|
|
142
147
|
page: int = 0,
|
|
143
148
|
size: PaginationPageSize = PaginationPageSize.PAGE_SIZE_10,
|
|
144
|
-
) ->
|
|
149
|
+
) -> BrokerList:
|
|
145
150
|
"""Retrieve stock data for a specific broker.
|
|
146
151
|
|
|
147
152
|
Args:
|
|
@@ -155,7 +160,7 @@ class BrokersClient:
|
|
|
155
160
|
size: Page size (default: 10)
|
|
156
161
|
|
|
157
162
|
Returns:
|
|
158
|
-
|
|
163
|
+
BrokerList: Stock data for the broker
|
|
159
164
|
"""
|
|
160
165
|
if region != Region.TR:
|
|
161
166
|
raise ValueError("Broker stock endpoint only works with the 'tr' region")
|
|
@@ -171,18 +176,18 @@ class BrokersClient:
|
|
|
171
176
|
}
|
|
172
177
|
|
|
173
178
|
response = self._client.get(f"v1/brokers/{symbol}", params=params)
|
|
174
|
-
return
|
|
179
|
+
return BrokerList(**response)
|
|
175
180
|
|
|
176
181
|
def get_stock_list_for_market(
|
|
177
182
|
self,
|
|
178
183
|
region: Region,
|
|
179
184
|
sort_by: BrokerSort,
|
|
180
|
-
sort_direction:
|
|
185
|
+
sort_direction: SortDirection,
|
|
181
186
|
from_date: datetime,
|
|
182
187
|
to_date: datetime,
|
|
183
188
|
page: int = 0,
|
|
184
189
|
size: PaginationPageSize = PaginationPageSize.PAGE_SIZE_10,
|
|
185
|
-
) ->
|
|
190
|
+
) -> BrokerList:
|
|
186
191
|
"""Retrieve market stock data for brokers.
|
|
187
192
|
|
|
188
193
|
Args:
|
|
@@ -195,7 +200,7 @@ class BrokersClient:
|
|
|
195
200
|
size: Page size (default: 10)
|
|
196
201
|
|
|
197
202
|
Returns:
|
|
198
|
-
|
|
203
|
+
BrokerList: Market stock data for brokers
|
|
199
204
|
"""
|
|
200
205
|
if region != Region.TR:
|
|
201
206
|
raise ValueError("Broker market stock endpoint only works with the 'tr' region")
|
|
@@ -211,4 +216,4 @@ class BrokersClient:
|
|
|
211
216
|
}
|
|
212
217
|
|
|
213
218
|
response = self._client.get("v1/brokers/market/stock", params=params)
|
|
214
|
-
return
|
|
219
|
+
return BrokerList(**response)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Capital Increase client for Laplace API."""
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import List, Optional
|
|
4
5
|
from laplace.base import BaseClient
|
|
5
6
|
|
|
6
7
|
from .models import (
|
|
@@ -53,7 +54,7 @@ class CapitalIncreaseClient:
|
|
|
53
54
|
page: int = 0,
|
|
54
55
|
size: PaginationPageSize = PaginationPageSize.PAGE_SIZE_10,
|
|
55
56
|
) -> PaginatedResponse[CapitalIncrease]:
|
|
56
|
-
"""Retrieve capital increase information by
|
|
57
|
+
"""Retrieve capital increase information by symbol.
|
|
57
58
|
|
|
58
59
|
Args:
|
|
59
60
|
symbol: Stock symbol (e.g., "AKBNK")
|
|
@@ -72,20 +73,20 @@ class CapitalIncreaseClient:
|
|
|
72
73
|
response = self._client.get(f"v1/capital-increase/{symbol}", params=params)
|
|
73
74
|
return PaginatedResponse[CapitalIncrease](**response)
|
|
74
75
|
|
|
75
|
-
def get_active_rights(self, symbol: str,
|
|
76
|
+
def get_active_rights(self, symbol: str, date: Optional[datetime] = None) -> List[CapitalIncrease]:
|
|
76
77
|
"""Retrieve active rights for a specific stock.
|
|
77
78
|
|
|
78
79
|
Args:
|
|
79
80
|
symbol: Stock symbol (e.g., "AKBNK")
|
|
80
|
-
|
|
81
|
+
date: Optional date filter (defaults to today on the server)
|
|
81
82
|
|
|
82
83
|
Returns:
|
|
83
84
|
List[CapitalIncrease]: Active rights data
|
|
84
85
|
"""
|
|
85
|
-
|
|
86
|
-
raise ValueError("Rights endpoint only works with the 'tr' region")
|
|
86
|
+
params = {}
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
if date is not None:
|
|
89
|
+
params["date"] = date.strftime("%Y-%m-%d")
|
|
89
90
|
|
|
90
91
|
response = self._client.get(f"v1/rights/active/{symbol}", params=params)
|
|
91
92
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Main Laplace client."""
|
|
2
2
|
|
|
3
|
+
from laplace.news import NewsClient
|
|
3
4
|
from .base import BaseClient
|
|
4
5
|
from .brokers import BrokersClient
|
|
5
6
|
from .capital_increase import CapitalIncreaseClient
|
|
@@ -19,7 +20,7 @@ from typing import Optional, List
|
|
|
19
20
|
class LaplaceClient(BaseClient):
|
|
20
21
|
"""Main Laplace API client with all sub-clients."""
|
|
21
22
|
|
|
22
|
-
def __init__(self, api_key: str, base_url: str = "https://
|
|
23
|
+
def __init__(self, api_key: str, base_url: str = "https://api.finfree.app/api"):
|
|
23
24
|
"""Initialize the Laplace client.
|
|
24
25
|
|
|
25
26
|
Args:
|
|
@@ -40,6 +41,7 @@ class LaplaceClient(BaseClient):
|
|
|
40
41
|
self.earnings = EarningsClient(self)
|
|
41
42
|
self.search = SearchClient(self)
|
|
42
43
|
self.state = StateClient(self)
|
|
44
|
+
self.news = NewsClient(self)
|
|
43
45
|
|
|
44
46
|
# WebSocket client will be created on demand
|
|
45
47
|
self._websocket_client: Optional[LivePriceWebSocketClient] = None
|
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
"""Collections client for Laplace API."""
|
|
2
2
|
|
|
3
|
-
from typing import List, Optional
|
|
3
|
+
from typing import Dict, List, Optional
|
|
4
4
|
|
|
5
5
|
from laplace.base import BaseClient
|
|
6
6
|
|
|
7
7
|
from .models import (
|
|
8
8
|
Collection,
|
|
9
9
|
CollectionDetail,
|
|
10
|
-
|
|
11
|
-
IndustryDetail,
|
|
10
|
+
CollectionStatus,
|
|
12
11
|
Locale,
|
|
13
|
-
Region
|
|
14
|
-
Sector,
|
|
15
|
-
SectorDetail,
|
|
16
|
-
Theme,
|
|
17
|
-
ThemeDetail,
|
|
12
|
+
Region
|
|
18
13
|
)
|
|
19
14
|
|
|
20
15
|
|
|
@@ -62,7 +57,7 @@ class CollectionsClient:
|
|
|
62
57
|
response = self._client.get(f"v1/collection/{collection_id}", params=params)
|
|
63
58
|
return CollectionDetail(**response)
|
|
64
59
|
|
|
65
|
-
def get_themes(self, region: Region, locale: Locale = "en") -> List[
|
|
60
|
+
def get_themes(self, region: Region, locale: Locale = "en") -> List[Collection]:
|
|
66
61
|
"""Retrieve a list of themes along with the number of stocks in each.
|
|
67
62
|
|
|
68
63
|
Args:
|
|
@@ -70,14 +65,14 @@ class CollectionsClient:
|
|
|
70
65
|
locale: Locale code (tr, en) (default: en)
|
|
71
66
|
|
|
72
67
|
Returns:
|
|
73
|
-
List[
|
|
68
|
+
List[Collection]: List of themes
|
|
74
69
|
"""
|
|
75
70
|
params = {"region": region.value, "locale": locale}
|
|
76
71
|
|
|
77
72
|
response = self._client.get("v1/theme", params=params)
|
|
78
|
-
return [
|
|
73
|
+
return [Collection(**theme) for theme in response]
|
|
79
74
|
|
|
80
|
-
def get_theme_detail(self, theme_id: str, region: Region, locale: Locale = "en") ->
|
|
75
|
+
def get_theme_detail(self, theme_id: str, region: Region, locale: Locale = "en") -> CollectionDetail:
|
|
81
76
|
"""Retrieve detailed information about a specific theme.
|
|
82
77
|
|
|
83
78
|
Args:
|
|
@@ -86,14 +81,14 @@ class CollectionsClient:
|
|
|
86
81
|
locale: Locale code (tr, en) (default: en)
|
|
87
82
|
|
|
88
83
|
Returns:
|
|
89
|
-
|
|
84
|
+
CollectionDetail: Detailed theme information
|
|
90
85
|
"""
|
|
91
86
|
params = {"locale": locale, "region": region.value}
|
|
92
87
|
|
|
93
88
|
response = self._client.get(f"v1/theme/{theme_id}", params=params)
|
|
94
|
-
return
|
|
89
|
+
return CollectionDetail(**response)
|
|
95
90
|
|
|
96
|
-
def get_industries(self, region: Region, locale: Locale = "en") -> List[
|
|
91
|
+
def get_industries(self, region: Region, locale: Locale = "en") -> List[Collection]:
|
|
97
92
|
"""Retrieve a list of industries along with the number of stocks in each.
|
|
98
93
|
|
|
99
94
|
Args:
|
|
@@ -101,16 +96,16 @@ class CollectionsClient:
|
|
|
101
96
|
locale: Locale code (tr, en) (default: en)
|
|
102
97
|
|
|
103
98
|
Returns:
|
|
104
|
-
List[
|
|
99
|
+
List[Collection]: List of industries
|
|
105
100
|
"""
|
|
106
101
|
params = {"region": region.value, "locale": locale}
|
|
107
102
|
|
|
108
103
|
response = self._client.get("v1/industry", params=params)
|
|
109
|
-
return [
|
|
104
|
+
return [Collection(**industry) for industry in response]
|
|
110
105
|
|
|
111
106
|
def get_industry_detail(
|
|
112
107
|
self, industry_id: str, region: Region, locale: Locale = "en"
|
|
113
|
-
) ->
|
|
108
|
+
) -> CollectionDetail:
|
|
114
109
|
"""Retrieve detailed information about a specific industry.
|
|
115
110
|
|
|
116
111
|
Args:
|
|
@@ -119,14 +114,14 @@ class CollectionsClient:
|
|
|
119
114
|
locale: Locale code (tr, en) (default: en)
|
|
120
115
|
|
|
121
116
|
Returns:
|
|
122
|
-
|
|
117
|
+
CollectionDetail: Detailed industry information
|
|
123
118
|
"""
|
|
124
119
|
params = {"locale": locale, "region": region.value}
|
|
125
120
|
|
|
126
121
|
response = self._client.get(f"v1/industry/{industry_id}", params=params)
|
|
127
|
-
return
|
|
122
|
+
return CollectionDetail(**response)
|
|
128
123
|
|
|
129
|
-
def get_custom_themes(self, locale: Locale, region: Region) -> List[
|
|
124
|
+
def get_custom_themes(self, locale: Locale, region: Region) -> List[Collection]:
|
|
130
125
|
"""Get a list of all your custom themes.
|
|
131
126
|
|
|
132
127
|
Args:
|
|
@@ -134,12 +129,12 @@ class CollectionsClient:
|
|
|
134
129
|
region: Region code (tr, us)
|
|
135
130
|
|
|
136
131
|
Returns:
|
|
137
|
-
List[
|
|
132
|
+
List[Collection]: List of custom themes
|
|
138
133
|
"""
|
|
139
134
|
params = {"locale": locale, "region": region.value}
|
|
140
135
|
|
|
141
136
|
response = self._client.get("v1/custom-theme", params=params)
|
|
142
|
-
return [
|
|
137
|
+
return [Collection(**theme) for theme in response]
|
|
143
138
|
|
|
144
139
|
def get_custom_theme_detail(
|
|
145
140
|
self, theme_id: str, locale: Locale, region: Region, sort_by: Optional[str] = None
|
|
@@ -163,7 +158,115 @@ class CollectionsClient:
|
|
|
163
158
|
response = self._client.get(f"v1/custom-theme/{theme_id}", params=params)
|
|
164
159
|
return CollectionDetail(**response)
|
|
165
160
|
|
|
166
|
-
def
|
|
161
|
+
def delete_custom_theme(self, theme_id: str) -> None:
|
|
162
|
+
"""Delete specific custom theme.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
theme_id: Unique identifier for the custom theme
|
|
166
|
+
"""
|
|
167
|
+
self._client.delete(f"v1/custom-theme/{theme_id}")
|
|
168
|
+
|
|
169
|
+
def create_custom_theme(
|
|
170
|
+
self,
|
|
171
|
+
title: Dict[str, str],
|
|
172
|
+
stock_ids: List[str],
|
|
173
|
+
status: CollectionStatus,
|
|
174
|
+
description: Optional[Dict[str, str]] = None,
|
|
175
|
+
region: Optional[List[Region]] = None,
|
|
176
|
+
image_url: Optional[str] = None,
|
|
177
|
+
image: Optional[str] = None,
|
|
178
|
+
avatar_url: Optional[str] = None,
|
|
179
|
+
order: Optional[int] = None,
|
|
180
|
+
meta_data: Optional[dict] = None,
|
|
181
|
+
) -> str:
|
|
182
|
+
"""Create a new custom theme.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
title: Localized title (e.g., {"tr": "Başlık", "en": "Title"})
|
|
186
|
+
stock_ids: List of stock IDs
|
|
187
|
+
status: Collection status
|
|
188
|
+
description: Localized description (optional)
|
|
189
|
+
region: List of regions (optional)
|
|
190
|
+
image_url: Image URL (optional)
|
|
191
|
+
image: Image data (optional)
|
|
192
|
+
avatar_url: Avatar URL (optional)
|
|
193
|
+
order: Display order (optional)
|
|
194
|
+
meta_data: Additional metadata (optional)
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
str: Created theme ID
|
|
198
|
+
"""
|
|
199
|
+
body: dict = {
|
|
200
|
+
"title": title,
|
|
201
|
+
"stocks": stock_ids,
|
|
202
|
+
"status": status.value,
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if description is not None:
|
|
206
|
+
body["description"] = description
|
|
207
|
+
if region is not None:
|
|
208
|
+
body["region"] = [r.value for r in region]
|
|
209
|
+
if image_url is not None:
|
|
210
|
+
body["image_url"] = image_url
|
|
211
|
+
if image is not None:
|
|
212
|
+
body["image"] = image
|
|
213
|
+
if avatar_url is not None:
|
|
214
|
+
body["avatar_url"] = avatar_url
|
|
215
|
+
if order is not None:
|
|
216
|
+
body["order"] = order
|
|
217
|
+
if meta_data is not None:
|
|
218
|
+
body["meta_data"] = meta_data
|
|
219
|
+
|
|
220
|
+
response = self._client.post("v1/custom-theme", json=body)
|
|
221
|
+
return response["id"]
|
|
222
|
+
|
|
223
|
+
def update_custom_theme(
|
|
224
|
+
self,
|
|
225
|
+
theme_id: str,
|
|
226
|
+
title: Optional[Dict[str, str]] = None,
|
|
227
|
+
stock_ids: Optional[List[str]] = None,
|
|
228
|
+
status: Optional[CollectionStatus] = None,
|
|
229
|
+
description: Optional[Dict[str, str]] = None,
|
|
230
|
+
image_url: Optional[str] = None,
|
|
231
|
+
image: Optional[str] = None,
|
|
232
|
+
avatar_url: Optional[str] = None,
|
|
233
|
+
meta_data: Optional[dict] = None,
|
|
234
|
+
) -> None:
|
|
235
|
+
"""Update an existing custom theme.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
theme_id: Unique identifier for the custom theme
|
|
239
|
+
title: Localized title (optional)
|
|
240
|
+
stock_ids: List of stock IDs (optional)
|
|
241
|
+
status: Collection status (optional)
|
|
242
|
+
description: Localized description (optional)
|
|
243
|
+
image_url: Image URL (optional)
|
|
244
|
+
image: Image data (optional)
|
|
245
|
+
avatar_url: Avatar URL (optional)
|
|
246
|
+
meta_data: Additional metadata (optional)
|
|
247
|
+
"""
|
|
248
|
+
body: dict = {}
|
|
249
|
+
|
|
250
|
+
if title is not None:
|
|
251
|
+
body["title"] = title
|
|
252
|
+
if stock_ids is not None:
|
|
253
|
+
body["stockIds"] = stock_ids
|
|
254
|
+
if status is not None:
|
|
255
|
+
body["status"] = status.value
|
|
256
|
+
if description is not None:
|
|
257
|
+
body["description"] = description
|
|
258
|
+
if image_url is not None:
|
|
259
|
+
body["image_url"] = image_url
|
|
260
|
+
if image is not None:
|
|
261
|
+
body["image"] = image
|
|
262
|
+
if avatar_url is not None:
|
|
263
|
+
body["avatar_url"] = avatar_url
|
|
264
|
+
if meta_data is not None:
|
|
265
|
+
body["meta_data"] = meta_data
|
|
266
|
+
|
|
267
|
+
self._client.patch(f"v1/custom-theme/{theme_id}", json=body)
|
|
268
|
+
|
|
269
|
+
def get_sectors(self, region: Region, locale: Locale = "en") -> List[Collection]:
|
|
167
270
|
"""Retrieve a list of sectors along with the number of stocks in each.
|
|
168
271
|
|
|
169
272
|
Args:
|
|
@@ -171,16 +274,16 @@ class CollectionsClient:
|
|
|
171
274
|
locale: Locale code (tr, en) (default: en)
|
|
172
275
|
|
|
173
276
|
Returns:
|
|
174
|
-
List[
|
|
277
|
+
List[Collection]: List of sectors
|
|
175
278
|
"""
|
|
176
279
|
params = {"region": region.value, "locale": locale}
|
|
177
280
|
|
|
178
281
|
response = self._client.get("v1/sector", params=params)
|
|
179
|
-
return [
|
|
282
|
+
return [Collection(**sector) for sector in response]
|
|
180
283
|
|
|
181
284
|
def get_sector_detail(
|
|
182
285
|
self, sector_id: str, region: Region, locale: Locale = "en"
|
|
183
|
-
) ->
|
|
286
|
+
) -> CollectionDetail:
|
|
184
287
|
"""Retrieve detailed information about a specific sector.
|
|
185
288
|
|
|
186
289
|
Args:
|
|
@@ -189,9 +292,9 @@ class CollectionsClient:
|
|
|
189
292
|
locale: Locale code (tr, en) (default: en)
|
|
190
293
|
|
|
191
294
|
Returns:
|
|
192
|
-
|
|
295
|
+
CollectionDetail: Detailed sector information
|
|
193
296
|
"""
|
|
194
297
|
params = {"locale": locale, "region": region.value}
|
|
195
298
|
|
|
196
299
|
response = self._client.get(f"v1/sector/{sector_id}", params=params)
|
|
197
|
-
return
|
|
300
|
+
return CollectionDetail(**response)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Financials client for Laplace API."""
|
|
2
2
|
|
|
3
|
-
from typing import List
|
|
3
|
+
from typing import List, Optional
|
|
4
4
|
|
|
5
5
|
from laplace.base import BaseClient
|
|
6
6
|
|
|
@@ -41,14 +41,17 @@ class FinancialsClient:
|
|
|
41
41
|
return [StockPeerFinancialRatioComparison(**item) for item in resp]
|
|
42
42
|
|
|
43
43
|
def get_historical_ratios(
|
|
44
|
-
self, symbol: str, keys: List[str], region: Region, locale: Locale
|
|
44
|
+
self, symbol: str, keys: List[str], region: Region, locale: Optional[Locale] = None
|
|
45
45
|
) -> List[StockHistoricalRatios]:
|
|
46
46
|
params = {
|
|
47
47
|
"symbol": symbol,
|
|
48
48
|
"region": region.value,
|
|
49
|
-
"locale": locale,
|
|
50
49
|
"slugs": ",".join(keys),
|
|
51
50
|
}
|
|
51
|
+
|
|
52
|
+
if locale:
|
|
53
|
+
params["locale"] = locale
|
|
54
|
+
|
|
52
55
|
resp = self._client.get("v2/stock/historical-ratios", params=params)
|
|
53
56
|
return [StockHistoricalRatios(**item) for item in resp]
|
|
54
57
|
|