kabukit 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.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.
- kabukit/__init__.py +6 -4
- kabukit/analysis/__init__.py +0 -0
- kabukit/analysis/indicators.py +0 -0
- kabukit/analysis/preprocess.py +0 -0
- kabukit/analysis/screener.py +0 -0
- kabukit/analysis/visualization.py +57 -0
- kabukit/cli/__init__.py +0 -0
- kabukit/cli/app.py +22 -0
- kabukit/cli/auth.py +86 -0
- kabukit/core/__init__.py +0 -0
- kabukit/core/base.py +45 -0
- kabukit/core/client.py +25 -0
- kabukit/core/info.py +12 -0
- kabukit/core/prices.py +30 -0
- kabukit/core/statements.py +7 -0
- kabukit/edinet/__init__.py +3 -0
- kabukit/edinet/client.py +113 -0
- kabukit/edinet/concurrent.py +153 -0
- kabukit/edinet/doc.py +32 -0
- kabukit/jquants/__init__.py +3 -0
- kabukit/jquants/client.py +197 -197
- kabukit/jquants/concurrent.py +91 -0
- kabukit/jquants/info.py +31 -0
- kabukit/jquants/prices.py +29 -0
- kabukit/jquants/schema.py +180 -0
- kabukit/jquants/statements.py +102 -0
- kabukit/py.typed +0 -0
- kabukit/utils/__init__.py +0 -0
- kabukit/utils/concurrent.py +148 -0
- kabukit/utils/config.py +26 -0
- kabukit/utils/params.py +47 -0
- kabukit-0.2.0.dist-info/METADATA +64 -0
- kabukit-0.2.0.dist-info/RECORD +35 -0
- {kabukit-0.1.0.dist-info → kabukit-0.2.0.dist-info}/WHEEL +1 -1
- kabukit-0.2.0.dist-info/entry_points.txt +3 -0
- kabukit/cli.py +0 -40
- kabukit-0.1.0.dist-info/METADATA +0 -33
- kabukit-0.1.0.dist-info/RECORD +0 -8
- kabukit-0.1.0.dist-info/entry_points.txt +0 -3
kabukit/jquants/client.py
CHANGED
@@ -1,324 +1,324 @@
|
|
1
|
-
"""This module provides a client for the J-Quants API.
|
2
|
-
|
3
|
-
It handles authentication and provides methods to interact with
|
4
|
-
the API endpoints.
|
5
|
-
"""
|
6
|
-
|
7
1
|
from __future__ import annotations
|
8
2
|
|
9
3
|
import datetime
|
10
4
|
import os
|
11
5
|
from enum import StrEnum
|
12
|
-
from functools import cached_property
|
13
|
-
from pathlib import Path
|
14
6
|
from typing import TYPE_CHECKING
|
15
7
|
|
16
8
|
import polars as pl
|
17
|
-
from dotenv import load_dotenv, set_key
|
18
|
-
from httpx import Client
|
19
|
-
from platformdirs import user_config_dir
|
20
9
|
from polars import DataFrame
|
21
10
|
|
11
|
+
from kabukit.core.client import Client
|
12
|
+
from kabukit.utils.config import load_dotenv, set_key
|
13
|
+
from kabukit.utils.params import get_params
|
14
|
+
|
15
|
+
from . import info, prices, statements
|
16
|
+
|
22
17
|
if TYPE_CHECKING:
|
23
|
-
from collections.abc import
|
24
|
-
from typing import Any
|
18
|
+
from collections.abc import AsyncIterator
|
19
|
+
from typing import Any, Self
|
25
20
|
|
26
21
|
from httpx import HTTPStatusError # noqa: F401
|
27
22
|
from httpx._types import QueryParamTypes
|
28
23
|
|
29
24
|
API_VERSION = "v1"
|
30
|
-
|
31
|
-
|
32
|
-
class AuthenticationError(Exception):
|
33
|
-
"""Custom exception for authentication failures."""
|
25
|
+
BASE_URL = f"https://api.jquants.com/{API_VERSION}"
|
34
26
|
|
35
27
|
|
36
28
|
class AuthKey(StrEnum):
|
37
|
-
"""
|
29
|
+
"""J-Quants認証のための環境変数キー。"""
|
38
30
|
|
39
31
|
REFRESH_TOKEN = "JQUANTS_REFRESH_TOKEN" # noqa: S105
|
40
32
|
ID_TOKEN = "JQUANTS_ID_TOKEN" # noqa: S105
|
41
33
|
|
42
34
|
|
43
|
-
class JQuantsClient:
|
44
|
-
"""
|
35
|
+
class JQuantsClient(Client):
|
36
|
+
"""J-Quants APIと対話するためのクライアント。
|
45
37
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
user's standard config directory.
|
38
|
+
API認証トークン(リフレッシュトークンおよびIDトークン)を管理し、
|
39
|
+
各種J-Quants APIエンドポイントへアクセスするメソッドを提供する。
|
40
|
+
トークンは設定ファイルから読み込まれ、またファイルに保存される。
|
50
41
|
|
51
42
|
Attributes:
|
52
|
-
client:
|
53
|
-
refresh_token: The refresh token for authentication.
|
54
|
-
id_token: The ID token for API requests.
|
43
|
+
client: APIリクエストを行うための `AsyncClient` インスタンス。
|
55
44
|
"""
|
56
45
|
|
57
|
-
|
58
|
-
|
59
|
-
|
46
|
+
def __init__(self, id_token: str | None = None) -> None:
|
47
|
+
super().__init__(BASE_URL)
|
48
|
+
self.set_id_token(id_token)
|
60
49
|
|
61
|
-
def
|
62
|
-
"""
|
50
|
+
def set_id_token(self, id_token: str | None = None) -> None:
|
51
|
+
"""IDトークンをヘッダーに設定する。
|
63
52
|
|
64
|
-
|
65
|
-
|
66
|
-
|
53
|
+
Args:
|
54
|
+
id_token (str | None, optional): 設定するIDトークン。
|
55
|
+
Noneの場合、環境変数から読み込む。
|
67
56
|
"""
|
68
|
-
self.client = Client(base_url=f"https://api.jquants.com/{API_VERSION}")
|
69
|
-
self._setup_config_path()
|
70
|
-
self._load_tokens()
|
71
|
-
self.set_header()
|
72
|
-
|
73
|
-
@cached_property
|
74
|
-
def dotenv_path(self) -> Path:
|
75
|
-
"""Returns the path to the .env file in the user config directory."""
|
76
|
-
config_dir = Path(user_config_dir("kabukit"))
|
77
|
-
config_dir.mkdir(parents=True, exist_ok=True)
|
78
|
-
return config_dir / ".env"
|
79
|
-
|
80
|
-
def _setup_config_path(self) -> None:
|
81
|
-
"""Determines the config path and creates the directory."""
|
82
|
-
# Accessing dotenv_path property will create the directory if it doesn't exist
|
83
|
-
_ = self.dotenv_path
|
84
|
-
|
85
|
-
def _load_tokens(self) -> None:
|
86
|
-
"""Loads tokens from the .env file."""
|
87
|
-
load_dotenv(self.dotenv_path)
|
88
|
-
self.refresh_token = os.environ.get(AuthKey.REFRESH_TOKEN)
|
89
|
-
self.id_token = os.environ.get(AuthKey.ID_TOKEN)
|
90
|
-
|
91
|
-
def set_header(self) -> None:
|
92
|
-
"""Sets the Authorization header if an ID token is available."""
|
93
|
-
if self.id_token:
|
94
|
-
self.client.headers["Authorization"] = f"Bearer {self.id_token}"
|
95
|
-
# Clear header if no ID token is available
|
96
|
-
elif "Authorization" in self.client.headers:
|
97
|
-
del self.client.headers["Authorization"]
|
98
|
-
|
99
|
-
def auth(self, mailaddress: str, password: str) -> None:
|
100
|
-
"""Authenticates, saves tokens, and sets the auth header.
|
101
57
|
|
102
|
-
|
103
|
-
|
104
|
-
|
58
|
+
if id_token is None:
|
59
|
+
load_dotenv()
|
60
|
+
id_token = os.environ.get(AuthKey.ID_TOKEN)
|
105
61
|
|
106
|
-
|
107
|
-
|
108
|
-
"""
|
109
|
-
self.refresh_token = self.get_refresh_token(mailaddress, password)
|
110
|
-
self.id_token = self.get_id_token(self.refresh_token)
|
111
|
-
set_key(self.dotenv_path, AuthKey.REFRESH_TOKEN, self.refresh_token)
|
112
|
-
set_key(self.dotenv_path, AuthKey.ID_TOKEN, self.id_token)
|
113
|
-
self.set_header()
|
62
|
+
if id_token:
|
63
|
+
self.client.headers["Authorization"] = f"Bearer {id_token}"
|
114
64
|
|
115
|
-
def post(self, url: str, json: Any | None = None) -> Any:
|
116
|
-
"""
|
65
|
+
async def post(self, url: str, json: Any | None = None) -> Any:
|
66
|
+
"""指定されたURLにPOSTリクエストを送信する。
|
117
67
|
|
118
68
|
Args:
|
119
|
-
url:
|
120
|
-
json:
|
69
|
+
url: POSTリクエストのURLパス。
|
70
|
+
json: リクエストボディのJSONペイロード。
|
121
71
|
|
122
72
|
Returns:
|
123
|
-
|
73
|
+
APIからのJSONレスポンス。
|
124
74
|
|
125
75
|
Raises:
|
126
|
-
|
127
|
-
HTTPStatusError: If the API request fails.
|
76
|
+
HTTPStatusError: APIリクエストが失敗した場合。
|
128
77
|
"""
|
129
|
-
|
130
|
-
msg = "ID token is not available. Please authenticate first."
|
131
|
-
raise AuthenticationError(msg)
|
132
|
-
|
133
|
-
resp = self.client.post(url, json=json)
|
78
|
+
resp = await self.client.post(url, json=json)
|
134
79
|
resp.raise_for_status()
|
135
80
|
return resp.json()
|
136
81
|
|
137
|
-
def
|
138
|
-
"""
|
82
|
+
async def get(self, url: str, params: QueryParamTypes | None = None) -> Any:
|
83
|
+
"""指定されたURLにGETリクエストを送信する。
|
139
84
|
|
140
85
|
Args:
|
141
|
-
|
142
|
-
|
86
|
+
url (str): GETリクエストのURLパス。
|
87
|
+
params (QueryParamTypes | None, optional): リクエストのクエリパラメータ。
|
143
88
|
|
144
89
|
Returns:
|
145
|
-
|
90
|
+
APIからのJSONレスポンス。
|
146
91
|
|
147
92
|
Raises:
|
148
|
-
|
93
|
+
HTTPStatusError: APIリクエストが失敗した場合。
|
149
94
|
"""
|
150
|
-
|
151
|
-
|
95
|
+
resp = await self.client.get(url, params=params)
|
96
|
+
resp.raise_for_status()
|
97
|
+
return resp.json()
|
152
98
|
|
153
|
-
def
|
154
|
-
|
99
|
+
async def auth(
|
100
|
+
self,
|
101
|
+
mailaddress: str,
|
102
|
+
password: str,
|
103
|
+
*,
|
104
|
+
save: bool = False,
|
105
|
+
) -> Self:
|
106
|
+
"""認証を行い、トークンを保存する。
|
155
107
|
|
156
108
|
Args:
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
The new ID token.
|
109
|
+
mailaddress (str): J-Quantsに登録したメールアドレス。
|
110
|
+
password (str): J-Quantsのパスワード。
|
111
|
+
save (bool, optional): トークンを環境変数に保存するかどうか。
|
161
112
|
|
162
113
|
Raises:
|
163
|
-
HTTPStatusError:
|
114
|
+
HTTPStatusError: APIリクエストが失敗した場合。
|
164
115
|
"""
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
def get(self, url: str, params: QueryParamTypes | None = None) -> Any:
|
169
|
-
"""Sends a GET request to the specified URL.
|
116
|
+
json_data = {"mailaddress": mailaddress, "password": password}
|
117
|
+
data = await self.post("/token/auth_user", json=json_data)
|
118
|
+
refresh_token = data["refreshToken"]
|
170
119
|
|
171
|
-
|
172
|
-
|
173
|
-
|
120
|
+
url = f"/token/auth_refresh?refreshtoken={refresh_token}"
|
121
|
+
data = await self.post(url)
|
122
|
+
id_token = data["idToken"]
|
174
123
|
|
175
|
-
|
176
|
-
|
124
|
+
if save:
|
125
|
+
set_key(AuthKey.REFRESH_TOKEN, refresh_token)
|
126
|
+
set_key(AuthKey.ID_TOKEN, id_token)
|
177
127
|
|
178
|
-
|
179
|
-
|
180
|
-
HTTPStatusError: If the API request fails.
|
181
|
-
"""
|
182
|
-
if not self.id_token:
|
183
|
-
msg = "ID token is not available. Please authenticate first."
|
184
|
-
raise AuthenticationError(msg)
|
185
|
-
|
186
|
-
resp = self.client.get(url, params=params)
|
187
|
-
resp.raise_for_status()
|
188
|
-
return resp.json()
|
128
|
+
self.set_id_token(id_token)
|
129
|
+
return self
|
189
130
|
|
190
|
-
def
|
131
|
+
async def get_info(
|
191
132
|
self,
|
192
133
|
code: str | None = None,
|
193
134
|
date: str | datetime.date | None = None,
|
194
135
|
) -> DataFrame:
|
195
|
-
"""
|
136
|
+
"""銘柄情報を取得する。
|
196
137
|
|
197
138
|
Args:
|
198
|
-
code
|
199
|
-
date
|
200
|
-
or datetime.date object).
|
139
|
+
code (str, optional): 情報を取得する銘柄のコード。
|
140
|
+
date (str | datetime.date, optional): 情報を取得する日付。
|
201
141
|
|
202
142
|
Returns:
|
203
|
-
|
143
|
+
銘柄情報を含むPolars DataFrame。
|
204
144
|
|
205
145
|
Raises:
|
206
|
-
|
207
|
-
HTTPStatusError: If the API request fails.
|
146
|
+
HTTPStatusError: APIリクエストが失敗した場合。
|
208
147
|
"""
|
209
|
-
params =
|
148
|
+
params = get_params(code=code, date=date)
|
210
149
|
url = "/listed/info"
|
211
|
-
data = self.get(url, params)
|
212
|
-
|
213
|
-
return df.with_columns(pl.col("Date").str.to_date())
|
150
|
+
data = await self.get(url, params)
|
151
|
+
return DataFrame(data["info"]).pipe(info.clean)
|
214
152
|
|
215
|
-
def
|
153
|
+
async def iter_pages(
|
216
154
|
self,
|
217
155
|
url: str,
|
218
156
|
params: dict[str, Any] | None,
|
219
157
|
name: str,
|
220
|
-
) ->
|
221
|
-
"""
|
158
|
+
) -> AsyncIterator[DataFrame]:
|
159
|
+
"""ページ分割されたAPIレスポンスを反復処理する。
|
222
160
|
|
223
161
|
Args:
|
224
|
-
url:
|
225
|
-
params
|
226
|
-
name:
|
162
|
+
url (str): APIエンドポイントのベースURL。
|
163
|
+
params (dict[str, Any]): クエリパラメータの辞書。
|
164
|
+
name (str): アイテムのリストを含むJSONレスポンスのキー。
|
227
165
|
|
228
166
|
Yields:
|
229
|
-
|
167
|
+
データの各ページに対応するPolars DataFrame。
|
230
168
|
|
231
169
|
Raises:
|
232
|
-
|
233
|
-
HTTPStatusError: If the API request fails.
|
170
|
+
HTTPStatusError: APIリクエストが失敗した場合。
|
234
171
|
"""
|
235
172
|
params = params or {}
|
236
173
|
|
237
174
|
while True:
|
238
|
-
data = self.get(url, params)
|
175
|
+
data = await self.get(url, params)
|
239
176
|
yield DataFrame(data[name])
|
240
177
|
if "pagination_key" in data:
|
241
178
|
params["pagination_key"] = data["pagination_key"]
|
242
179
|
else:
|
243
180
|
break
|
244
181
|
|
245
|
-
def get_prices(
|
182
|
+
async def get_prices(
|
246
183
|
self,
|
247
184
|
code: str | None = None,
|
248
185
|
date: str | datetime.date | None = None,
|
249
186
|
from_: str | datetime.date | None = None,
|
250
187
|
to: str | datetime.date | None = None,
|
251
188
|
) -> DataFrame:
|
252
|
-
"""
|
189
|
+
"""日々の株価四本値を取得する。
|
190
|
+
|
191
|
+
株価は分割・併合を考慮した調整済み株価(小数点第2位四捨五入)と調整前の株価を取得できる。
|
253
192
|
|
254
193
|
Args:
|
255
|
-
code
|
256
|
-
date
|
257
|
-
|
258
|
-
from_
|
259
|
-
|
260
|
-
to
|
261
|
-
|
194
|
+
code (str, optional): 株価を取得する銘柄のコード。
|
195
|
+
date (str | datetime.date, optional): 株価を取得する日付。
|
196
|
+
`from_`または`to`とは併用不可。
|
197
|
+
from_ (str | datetime.date, optional): 取得期間の開始日。
|
198
|
+
`date`とは併用不可。
|
199
|
+
to (str | datetime.date, optional): 取得期間の終了日。
|
200
|
+
`date`とは併用不可。
|
262
201
|
|
263
202
|
Returns:
|
264
|
-
|
203
|
+
日々の株価四本値を含むPolars DataFrame。
|
265
204
|
|
266
205
|
Raises:
|
267
|
-
ValueError:
|
268
|
-
|
269
|
-
HTTPStatusError: If the API request fails.
|
206
|
+
ValueError: `date`と`from_`/`to`の両方が指定された場合。
|
207
|
+
HTTPStatusError: APIリクエストが失敗した場合。
|
270
208
|
"""
|
271
|
-
|
209
|
+
if not date and not code:
|
210
|
+
return await self.get_latest_available_prices()
|
272
211
|
|
273
212
|
if date and (from_ or to):
|
274
|
-
msg = "
|
213
|
+
msg = "dateとfrom/toの両方を指定することはできません。"
|
275
214
|
raise ValueError(msg)
|
276
215
|
|
277
|
-
|
278
|
-
params["from"] = date_to_str(from_)
|
279
|
-
if not date and to:
|
280
|
-
params["to"] = date_to_str(to)
|
216
|
+
params = get_params(code=code, date=date, from_=from_, to=to)
|
281
217
|
|
282
218
|
url = "/prices/daily_quotes"
|
283
219
|
name = "daily_quotes"
|
284
220
|
|
285
|
-
|
221
|
+
dfs = [df async for df in self.iter_pages(url, params, name)]
|
222
|
+
df = pl.concat(dfs)
|
223
|
+
|
286
224
|
if df.is_empty():
|
287
225
|
return df
|
288
226
|
|
289
|
-
return
|
227
|
+
return prices.clean(df)
|
290
228
|
|
229
|
+
async def get_latest_available_prices(self, num_days: int = 30) -> DataFrame:
|
230
|
+
"""直近利用可能な日付の株価を取得する。"""
|
231
|
+
today = datetime.date.today() # noqa: DTZ011
|
291
232
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
) -> dict[str, str]:
|
296
|
-
"""Constructs a dictionary of parameters for code and date filtering.
|
233
|
+
for days in range(num_days):
|
234
|
+
date = today - datetime.timedelta(days)
|
235
|
+
df = await self.get_prices(date=date)
|
297
236
|
|
298
|
-
|
299
|
-
|
300
|
-
date: Optional. The date (string or datetime.date object).
|
237
|
+
if not df.is_empty():
|
238
|
+
return df
|
301
239
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
240
|
+
return DataFrame()
|
241
|
+
|
242
|
+
async def get_statements(
|
243
|
+
self,
|
244
|
+
code: str | None = None,
|
245
|
+
date: str | datetime.date | None = None,
|
246
|
+
) -> DataFrame:
|
247
|
+
"""四半期毎の決算短信サマリーおよび業績・配当の修正に関する開示情報を取得する。
|
248
|
+
|
249
|
+
Args:
|
250
|
+
code (str, optional): 財務情報を取得する銘柄のコード。
|
251
|
+
date (str | datetime.date, optional): 財務情報を取得する日付。
|
252
|
+
|
253
|
+
Returns:
|
254
|
+
財務情報を含むDataFrame。
|
255
|
+
|
256
|
+
Raises:
|
257
|
+
ValueError: `code`と`date`が両方とも指定されない場合。
|
258
|
+
HTTPStatusError: APIリクエストが失敗した場合。
|
259
|
+
"""
|
260
|
+
if not code and not date:
|
261
|
+
msg = "codeまたはdateのどちらかを指定する必要があります。"
|
262
|
+
raise ValueError(msg)
|
311
263
|
|
264
|
+
params = get_params(code=code, date=date)
|
265
|
+
url = "/fins/statements"
|
266
|
+
name = "statements"
|
312
267
|
|
313
|
-
|
314
|
-
|
268
|
+
dfs = [df async for df in self.iter_pages(url, params, name)]
|
269
|
+
df = pl.concat(dfs)
|
315
270
|
|
316
|
-
|
317
|
-
|
271
|
+
if df.is_empty():
|
272
|
+
return df
|
318
273
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
274
|
+
return statements.clean(df)
|
275
|
+
|
276
|
+
async def get_announcement(self) -> DataFrame:
|
277
|
+
"""翌日発表予定の決算情報を取得する。
|
278
|
+
|
279
|
+
Returns:
|
280
|
+
開示情報を含むPolars DataFrame。
|
281
|
+
|
282
|
+
Raises:
|
283
|
+
HTTPStatusError: APIリクエストが失敗した場合。
|
284
|
+
"""
|
285
|
+
url = "fins/announcement"
|
286
|
+
name = "announcement"
|
287
|
+
|
288
|
+
dfs = [df async for df in self.iter_pages(url, {}, name)]
|
289
|
+
df = pl.concat(dfs)
|
290
|
+
if df.is_empty():
|
291
|
+
return df
|
292
|
+
|
293
|
+
return df.with_columns(pl.col("Date").str.to_date("%Y-%m-%d", strict=False))
|
294
|
+
|
295
|
+
async def get_trades_spec(
|
296
|
+
self,
|
297
|
+
section: str | None = None,
|
298
|
+
from_: str | datetime.date | None = None,
|
299
|
+
to: str | datetime.date | None = None,
|
300
|
+
) -> DataFrame:
|
301
|
+
"""投資部門別の情報を取得する。
|
302
|
+
|
303
|
+
Args:
|
304
|
+
section: 絞り込み対象のセクション。
|
305
|
+
from_: 取得期間の開始日。
|
306
|
+
to: 取得期間の終了日。
|
307
|
+
|
308
|
+
Returns:
|
309
|
+
投資部門別の情報を含むPolars DataFrame。
|
310
|
+
|
311
|
+
Raises:
|
312
|
+
HTTPStatusError: APIリクエストが失敗した場合。
|
313
|
+
"""
|
314
|
+
params = get_params(section=section, from_=from_, to=to)
|
315
|
+
|
316
|
+
url = "/markets/trades_spec"
|
317
|
+
name = "trades_spec"
|
318
|
+
|
319
|
+
dfs = [df async for df in self.iter_pages(url, params, name)]
|
320
|
+
df = pl.concat(dfs)
|
321
|
+
if df.is_empty():
|
322
|
+
return df
|
323
|
+
|
324
|
+
return df.with_columns(pl.col("^.*Date$").str.to_date("%Y-%m-%d", strict=False))
|
@@ -0,0 +1,91 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from typing import TYPE_CHECKING
|
4
|
+
|
5
|
+
from kabukit.utils import concurrent
|
6
|
+
|
7
|
+
from .client import JQuantsClient
|
8
|
+
from .info import get_codes
|
9
|
+
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from collections.abc import Iterable
|
12
|
+
|
13
|
+
from polars import DataFrame
|
14
|
+
|
15
|
+
from kabukit.utils.concurrent import Callback, Progress
|
16
|
+
|
17
|
+
|
18
|
+
async def fetch(
|
19
|
+
resource: str,
|
20
|
+
codes: Iterable[str],
|
21
|
+
/,
|
22
|
+
max_concurrency: int | None = None,
|
23
|
+
progress: Progress | None = None,
|
24
|
+
callback: Callback | None = None,
|
25
|
+
) -> DataFrame:
|
26
|
+
"""全銘柄の各種データを取得し、単一のDataFrameにまとめて返す。
|
27
|
+
|
28
|
+
Args:
|
29
|
+
resource (str): 取得するデータの種類。JQuantsClientのメソッド名から"get_"を
|
30
|
+
除いたものを指定する。
|
31
|
+
codes (Iterable[str]): 取得対象の銘柄コードのリスト。
|
32
|
+
max_concurrency (int | None, optional): 同時に実行するリクエストの最大数。
|
33
|
+
指定しないときはデフォルト値が使用される。
|
34
|
+
progress (Progress | None, optional): 進捗表示のための関数。
|
35
|
+
tqdm, marimoなどのライブラリを使用できる。
|
36
|
+
指定しないときは進捗表示は行われない。
|
37
|
+
callback (Callback | None, optional): 各DataFrameに対して適用する
|
38
|
+
コールバック関数。指定しないときはそのままのDataFrameが使用される。
|
39
|
+
|
40
|
+
Returns:
|
41
|
+
DataFrame:
|
42
|
+
すべての銘柄の財務情報を含む単一のDataFrame。
|
43
|
+
"""
|
44
|
+
return await concurrent.fetch(
|
45
|
+
JQuantsClient,
|
46
|
+
resource,
|
47
|
+
codes,
|
48
|
+
max_concurrency=max_concurrency,
|
49
|
+
progress=progress,
|
50
|
+
callback=callback,
|
51
|
+
)
|
52
|
+
|
53
|
+
|
54
|
+
async def fetch_all(
|
55
|
+
resource: str,
|
56
|
+
/,
|
57
|
+
limit: int | None = None,
|
58
|
+
max_concurrency: int | None = None,
|
59
|
+
progress: Progress | None = None,
|
60
|
+
callback: Callback | None = None,
|
61
|
+
) -> DataFrame:
|
62
|
+
"""全銘柄の各種データを取得し、単一のDataFrameにまとめて返す。
|
63
|
+
|
64
|
+
Args:
|
65
|
+
resource (str): 取得するデータの種類。JQuantsClientのメソッド名から"get_"を
|
66
|
+
除いたものを指定する。
|
67
|
+
limit (int | None, optional): 取得する銘柄数の上限。
|
68
|
+
指定しないときはすべての銘柄が対象となる。
|
69
|
+
max_concurrency (int | None, optional): 同時に実行するリクエストの最大数。
|
70
|
+
指定しないときはデフォルト値が使用される。
|
71
|
+
progress (Progress | None, optional): 進捗表示のための関数。
|
72
|
+
tqdm, marimoなどのライブラリを使用できる。
|
73
|
+
指定しないときは進捗表示は行われない。
|
74
|
+
callback (Callback | None, optional): 各DataFrameに対して適用する
|
75
|
+
コールバック関数。指定しないときはそのままのDataFrameが使用される。
|
76
|
+
|
77
|
+
Returns:
|
78
|
+
DataFrame:
|
79
|
+
すべての銘柄の財務情報を含む単一のDataFrame。
|
80
|
+
"""
|
81
|
+
|
82
|
+
codes = await get_codes()
|
83
|
+
codes = codes[:limit]
|
84
|
+
|
85
|
+
return await fetch(
|
86
|
+
resource,
|
87
|
+
codes,
|
88
|
+
max_concurrency=max_concurrency,
|
89
|
+
progress=progress,
|
90
|
+
callback=callback,
|
91
|
+
)
|
kabukit/jquants/info.py
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import polars as pl
|
4
|
+
from polars import DataFrame
|
5
|
+
|
6
|
+
|
7
|
+
def clean(df: DataFrame) -> DataFrame:
|
8
|
+
return df.with_columns(
|
9
|
+
pl.col("Date").str.to_date("%Y-%m-%d"),
|
10
|
+
pl.col("^.*CodeName$", "ScaleCategory").cast(pl.Categorical),
|
11
|
+
).drop("^.+Code$", "CompanyNameEnglish")
|
12
|
+
|
13
|
+
|
14
|
+
async def get_codes() -> list[str]:
|
15
|
+
"""銘柄コードのリストを返す。
|
16
|
+
|
17
|
+
市場「TOKYO PRO MARKET」と業種「その他」を除外した銘柄を対象とする。
|
18
|
+
"""
|
19
|
+
from .client import JQuantsClient
|
20
|
+
|
21
|
+
async with JQuantsClient() as client:
|
22
|
+
info = await client.get_info()
|
23
|
+
|
24
|
+
return (
|
25
|
+
info.filter(
|
26
|
+
pl.col("MarketCodeName") != "TOKYO PRO MARKET",
|
27
|
+
pl.col("Sector17CodeName") != "その他",
|
28
|
+
)
|
29
|
+
.get_column("Code")
|
30
|
+
.to_list()
|
31
|
+
)
|