alphafeed 0.1.0.dev0__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.
- alphafeed/__init__.py +53 -0
- alphafeed/__version__.py +3 -0
- alphafeed/_base_client.py +305 -0
- alphafeed/_batch.py +87 -0
- alphafeed/_cache.py +130 -0
- alphafeed/_exceptions.py +140 -0
- alphafeed/_types.py +55 -0
- alphafeed/client.py +140 -0
- alphafeed/models.py +101 -0
- alphafeed/resources/__init__.py +13 -0
- alphafeed/resources/_base.py +17 -0
- alphafeed/resources/depth.py +44 -0
- alphafeed/resources/instruments.py +99 -0
- alphafeed/resources/klines.py +724 -0
- alphafeed/resources/quotes.py +257 -0
- alphafeed/utils.py +53 -0
- alphafeed-0.1.0.dev0.dist-info/METADATA +175 -0
- alphafeed-0.1.0.dev0.dist-info/RECORD +20 -0
- alphafeed-0.1.0.dev0.dist-info/WHEEL +5 -0
- alphafeed-0.1.0.dev0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,724 @@
|
|
|
1
|
+
"""K-line (OHLCV) data resources for AlphaFeed API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import concurrent.futures
|
|
6
|
+
from typing import (
|
|
7
|
+
TYPE_CHECKING,
|
|
8
|
+
Any,
|
|
9
|
+
Dict,
|
|
10
|
+
List,
|
|
11
|
+
Literal,
|
|
12
|
+
Optional,
|
|
13
|
+
Tuple,
|
|
14
|
+
Union,
|
|
15
|
+
overload,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
import pandas as pd
|
|
19
|
+
|
|
20
|
+
from .._batch import _chunk_list, _get_progress_bar, batched_get_sync
|
|
21
|
+
from .._cache import InstrumentNameCache
|
|
22
|
+
from .._types import NOT_GIVEN, NotGiven
|
|
23
|
+
from ._base import SyncResource
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from ..models import AdjustType, CompactKlineData, ExFactorEntry, Period
|
|
27
|
+
|
|
28
|
+
MAX_SYMBOLS_PER_BATCH = 100
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _klines_to_dataframe(
|
|
32
|
+
data: "CompactKlineData",
|
|
33
|
+
symbol: Optional[str] = None,
|
|
34
|
+
name: Optional[str] = None,
|
|
35
|
+
) -> "pd.DataFrame":
|
|
36
|
+
"""Convert compact K-line data to a pandas DataFrame.
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
data : CompactKlineData
|
|
41
|
+
Compact columnar K-line data from the API.
|
|
42
|
+
symbol : str, optional
|
|
43
|
+
Symbol code to include as a column.
|
|
44
|
+
name : str, optional
|
|
45
|
+
Instrument name to include as a column.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
pd.DataFrame
|
|
50
|
+
DataFrame with columns: timestamp, open, high, low, close, volume, amount.
|
|
51
|
+
"""
|
|
52
|
+
import datetime
|
|
53
|
+
|
|
54
|
+
from ..utils import get_instrument_region, get_region_timezone
|
|
55
|
+
|
|
56
|
+
timestamps = data["timestamp"]
|
|
57
|
+
|
|
58
|
+
if not timestamps:
|
|
59
|
+
trade_dates = []
|
|
60
|
+
trade_times = []
|
|
61
|
+
else:
|
|
62
|
+
region = get_instrument_region(symbol) if symbol else None
|
|
63
|
+
tz = get_region_timezone(region) if region else None
|
|
64
|
+
|
|
65
|
+
if tz:
|
|
66
|
+
trade_dates = []
|
|
67
|
+
trade_times = []
|
|
68
|
+
append_date = trade_dates.append
|
|
69
|
+
append_time = trade_times.append
|
|
70
|
+
fromtimestamp = datetime.datetime.fromtimestamp
|
|
71
|
+
|
|
72
|
+
for ts in timestamps:
|
|
73
|
+
dt = fromtimestamp(ts / 1000, tz)
|
|
74
|
+
append_date(f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d}")
|
|
75
|
+
append_time(
|
|
76
|
+
f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} {dt.hour:02d}:{dt.minute:02d}:{dt.second:02d}"
|
|
77
|
+
)
|
|
78
|
+
else:
|
|
79
|
+
n = len(timestamps)
|
|
80
|
+
trade_dates = [None] * n
|
|
81
|
+
trade_times = [None] * n
|
|
82
|
+
|
|
83
|
+
df = pd.DataFrame(
|
|
84
|
+
{
|
|
85
|
+
"symbol": symbol,
|
|
86
|
+
"name": name,
|
|
87
|
+
"timestamp": timestamps,
|
|
88
|
+
"trade_date": trade_dates,
|
|
89
|
+
"trade_time": trade_times,
|
|
90
|
+
"open": data["open"],
|
|
91
|
+
"high": data["high"],
|
|
92
|
+
"low": data["low"],
|
|
93
|
+
"close": data["close"],
|
|
94
|
+
"volume": data["volume"],
|
|
95
|
+
"amount": (data["amount"] if "amount" in data else [0.0] * len(timestamps)),
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
return df
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _batch_klines_to_dataframes(
|
|
103
|
+
data: Dict[str, "CompactKlineData"],
|
|
104
|
+
names: Optional[Dict[str, str]] = None,
|
|
105
|
+
) -> Dict[str, "pd.DataFrame"]:
|
|
106
|
+
"""Convert batch K-line data to DataFrames with optional name column.
|
|
107
|
+
|
|
108
|
+
Parameters
|
|
109
|
+
----------
|
|
110
|
+
data : dict
|
|
111
|
+
Dictionary mapping symbol codes to compact K-line data.
|
|
112
|
+
names : dict, optional
|
|
113
|
+
Dictionary mapping symbol codes to instrument names.
|
|
114
|
+
|
|
115
|
+
Returns
|
|
116
|
+
-------
|
|
117
|
+
dict of str to pd.DataFrame
|
|
118
|
+
Dictionary mapping symbol codes to pandas DataFrames.
|
|
119
|
+
"""
|
|
120
|
+
names = names or {}
|
|
121
|
+
dfs: Dict[str, "pd.DataFrame"] = {}
|
|
122
|
+
for symbol, kline_data in data.items():
|
|
123
|
+
df = _klines_to_dataframe(kline_data, symbol=symbol, name=names.get(symbol))
|
|
124
|
+
dfs[symbol] = df
|
|
125
|
+
|
|
126
|
+
return dfs
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _factors_to_dataframe(
|
|
130
|
+
data: Dict[str, List["ExFactorEntry"]],
|
|
131
|
+
) -> "pd.DataFrame":
|
|
132
|
+
"""Convert factor response to a single long-format DataFrame."""
|
|
133
|
+
from ..utils import get_instrument_region, get_region_timezone
|
|
134
|
+
|
|
135
|
+
if not data:
|
|
136
|
+
return pd.DataFrame(columns=["symbol", "timestamp", "trade_date", "ex_factor"])
|
|
137
|
+
|
|
138
|
+
rows = []
|
|
139
|
+
for symbol, entries in data.items():
|
|
140
|
+
if not entries:
|
|
141
|
+
continue
|
|
142
|
+
|
|
143
|
+
region = get_instrument_region(symbol)
|
|
144
|
+
tz = get_region_timezone(region) if region else None
|
|
145
|
+
|
|
146
|
+
timestamps = [e["timestamp"] for e in entries]
|
|
147
|
+
|
|
148
|
+
if tz:
|
|
149
|
+
ts_series = pd.to_datetime(timestamps, unit="ms", utc=True).tz_convert(tz)
|
|
150
|
+
trade_dates = ts_series.strftime("%Y-%m-%d").tolist()
|
|
151
|
+
else:
|
|
152
|
+
trade_dates = [None] * len(timestamps)
|
|
153
|
+
|
|
154
|
+
for i, e in enumerate(entries):
|
|
155
|
+
rows.append(
|
|
156
|
+
{
|
|
157
|
+
"symbol": symbol,
|
|
158
|
+
"timestamp": e["timestamp"],
|
|
159
|
+
"trade_date": trade_dates[i],
|
|
160
|
+
"ex_factor": e["ex_factor"],
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
return (
|
|
165
|
+
pd.DataFrame(rows)
|
|
166
|
+
if rows
|
|
167
|
+
else pd.DataFrame(columns=["symbol", "timestamp", "trade_date", "ex_factor"])
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class Klines(SyncResource):
|
|
172
|
+
"""Synchronous interface for K-line (OHLCV) data endpoints.
|
|
173
|
+
|
|
174
|
+
Supports returning data as raw dicts or pandas DataFrames.
|
|
175
|
+
When returning DataFrames, instrument names are automatically resolved
|
|
176
|
+
from a local cache (fetched from the instruments API on first access).
|
|
177
|
+
|
|
178
|
+
Examples
|
|
179
|
+
--------
|
|
180
|
+
>>> client = AlphaFeed(api_key="your-key")
|
|
181
|
+
>>>
|
|
182
|
+
>>> # Get raw K-line data
|
|
183
|
+
>>> klines = client.klines.get("600000.SH", count=100)
|
|
184
|
+
>>>
|
|
185
|
+
>>> # Get as DataFrame (includes name column)
|
|
186
|
+
>>> df = client.klines.get("600000.SH", count=100, to_dataframe=True)
|
|
187
|
+
>>> print(df.head())
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
_instrument_cache: Optional[InstrumentNameCache]
|
|
191
|
+
|
|
192
|
+
def __init__(
|
|
193
|
+
self, client: Any, instrument_cache: Optional[InstrumentNameCache] = None
|
|
194
|
+
) -> None:
|
|
195
|
+
super().__init__(client)
|
|
196
|
+
self._instrument_cache = instrument_cache
|
|
197
|
+
|
|
198
|
+
def _resolve_name(self, symbol: str) -> Optional[str]:
|
|
199
|
+
if not self._instrument_cache:
|
|
200
|
+
return None
|
|
201
|
+
names = self._instrument_cache.resolve_sync([symbol], self._client)
|
|
202
|
+
return names.get(symbol)
|
|
203
|
+
|
|
204
|
+
def _resolve_names(self, symbols: List[str]) -> Dict[str, str]:
|
|
205
|
+
if not self._instrument_cache:
|
|
206
|
+
return {}
|
|
207
|
+
return self._instrument_cache.resolve_sync(symbols, self._client)
|
|
208
|
+
|
|
209
|
+
@overload
|
|
210
|
+
def get(
|
|
211
|
+
self,
|
|
212
|
+
symbol: str,
|
|
213
|
+
*,
|
|
214
|
+
period: Union["Period", NotGiven] = NOT_GIVEN,
|
|
215
|
+
count: Union[int, NotGiven] = NOT_GIVEN,
|
|
216
|
+
start_time: Union[int, None, NotGiven] = NOT_GIVEN,
|
|
217
|
+
end_time: Union[int, None, NotGiven] = NOT_GIVEN,
|
|
218
|
+
adjust: Union["AdjustType", NotGiven] = NOT_GIVEN,
|
|
219
|
+
to_dataframe: Literal[False] = False,
|
|
220
|
+
) -> "CompactKlineData": ...
|
|
221
|
+
|
|
222
|
+
@overload
|
|
223
|
+
def get(
|
|
224
|
+
self,
|
|
225
|
+
symbol: str,
|
|
226
|
+
*,
|
|
227
|
+
period: Union["Period", NotGiven] = NOT_GIVEN,
|
|
228
|
+
count: Union[int, NotGiven] = NOT_GIVEN,
|
|
229
|
+
start_time: Union[int, None, NotGiven] = NOT_GIVEN,
|
|
230
|
+
end_time: Union[int, None, NotGiven] = NOT_GIVEN,
|
|
231
|
+
adjust: Union["AdjustType", NotGiven] = NOT_GIVEN,
|
|
232
|
+
to_dataframe: Literal[True],
|
|
233
|
+
) -> "pd.DataFrame": ...
|
|
234
|
+
|
|
235
|
+
def get(
|
|
236
|
+
self,
|
|
237
|
+
symbol: str,
|
|
238
|
+
*,
|
|
239
|
+
period: Union["Period", NotGiven] = NOT_GIVEN,
|
|
240
|
+
count: Union[int, NotGiven] = NOT_GIVEN,
|
|
241
|
+
start_time: Union[int, None, NotGiven] = NOT_GIVEN,
|
|
242
|
+
end_time: Union[int, None, NotGiven] = NOT_GIVEN,
|
|
243
|
+
adjust: Union["AdjustType", NotGiven] = NOT_GIVEN,
|
|
244
|
+
to_dataframe: bool = False,
|
|
245
|
+
) -> Union["CompactKlineData", "pd.DataFrame"]:
|
|
246
|
+
"""Get K-line (OHLCV) data for a single symbol.
|
|
247
|
+
|
|
248
|
+
Parameters
|
|
249
|
+
----------
|
|
250
|
+
symbol : str
|
|
251
|
+
Symbol code (e.g., "600000.SH", "AAPL.US").
|
|
252
|
+
period : str, optional
|
|
253
|
+
K-line period. One of: "1m", "5m", "10m", "15m", "30m", "60m", "1d", "1w", "1M". Defaults to "1d".
|
|
254
|
+
count : int, optional
|
|
255
|
+
Number of K-lines to return. Default 100, max 10000.
|
|
256
|
+
start_time : int, optional
|
|
257
|
+
Start timestamp in milliseconds.
|
|
258
|
+
end_time : int, optional
|
|
259
|
+
End timestamp in milliseconds.
|
|
260
|
+
adjust : str, optional
|
|
261
|
+
Adjustment type: "forward" (前复权, default), "backward" (后复权),
|
|
262
|
+
or "none" (不复权).
|
|
263
|
+
to_dataframe : bool, optional
|
|
264
|
+
If True, return a pandas DataFrame. If False (default), return
|
|
265
|
+
the raw compact columnar data.
|
|
266
|
+
|
|
267
|
+
Returns
|
|
268
|
+
-------
|
|
269
|
+
CompactKlineData or pd.DataFrame
|
|
270
|
+
If to_dataframe=False: dict with keys 'timestamp', 'open', 'high',
|
|
271
|
+
'low', 'close', 'volume', 'amount' (each a list).
|
|
272
|
+
If to_dataframe=True: pandas DataFrame with datetime index.
|
|
273
|
+
|
|
274
|
+
Examples
|
|
275
|
+
--------
|
|
276
|
+
>>> # Get forward-adjusted data (default)
|
|
277
|
+
>>> df = client.klines.get("600519.SH", period="1d", count=100, to_dataframe=True)
|
|
278
|
+
>>>
|
|
279
|
+
>>> # Get unadjusted data
|
|
280
|
+
>>> df_raw = client.klines.get("600519.SH", adjust="none", to_dataframe=True)
|
|
281
|
+
>>>
|
|
282
|
+
>>> # Get backward-adjusted data
|
|
283
|
+
>>> df_hfq = client.klines.get("600519.SH", adjust="backward", to_dataframe=True)
|
|
284
|
+
"""
|
|
285
|
+
params: Dict[str, Any] = {"symbol": symbol}
|
|
286
|
+
if not isinstance(period, NotGiven):
|
|
287
|
+
params["period"] = period
|
|
288
|
+
if not isinstance(count, NotGiven):
|
|
289
|
+
params["count"] = count
|
|
290
|
+
if not isinstance(start_time, NotGiven) and start_time is not None:
|
|
291
|
+
params["start_time"] = start_time
|
|
292
|
+
if not isinstance(end_time, NotGiven) and end_time is not None:
|
|
293
|
+
params["end_time"] = end_time
|
|
294
|
+
if not isinstance(adjust, NotGiven):
|
|
295
|
+
params["adjust"] = adjust
|
|
296
|
+
|
|
297
|
+
response = self._client.get("/v1/klines", params=params)
|
|
298
|
+
data = response["data"]
|
|
299
|
+
|
|
300
|
+
if to_dataframe:
|
|
301
|
+
name = self._resolve_name(symbol)
|
|
302
|
+
return _klines_to_dataframe(data, symbol=symbol, name=name)
|
|
303
|
+
return data
|
|
304
|
+
|
|
305
|
+
def _fetch_batch_chunk(
|
|
306
|
+
self,
|
|
307
|
+
symbols: List[str],
|
|
308
|
+
params: Dict[str, Any],
|
|
309
|
+
endpoint: str = "/v1/klines/batch",
|
|
310
|
+
) -> Tuple[Dict[str, "CompactKlineData"], List[Tuple[str, Exception]]]:
|
|
311
|
+
"""Fetch a single batch chunk.
|
|
312
|
+
|
|
313
|
+
Returns
|
|
314
|
+
-------
|
|
315
|
+
tuple
|
|
316
|
+
(data dict, list of (symbol, error) for failed symbols)
|
|
317
|
+
"""
|
|
318
|
+
symbols_str = ",".join(symbols)
|
|
319
|
+
chunk_params = {**params, "symbols": symbols_str}
|
|
320
|
+
|
|
321
|
+
response = self._client.get(endpoint, params=chunk_params)
|
|
322
|
+
return response["data"], []
|
|
323
|
+
|
|
324
|
+
def _run_batch(
|
|
325
|
+
self,
|
|
326
|
+
symbols: List[str],
|
|
327
|
+
params: Dict[str, Any],
|
|
328
|
+
endpoint: str,
|
|
329
|
+
batch_size: int,
|
|
330
|
+
to_dataframe: bool,
|
|
331
|
+
show_progress: bool,
|
|
332
|
+
max_workers: int,
|
|
333
|
+
progress_desc: str = "Fetching K-lines",
|
|
334
|
+
) -> Union[Dict[str, "CompactKlineData"], "pd.DataFrame"]:
|
|
335
|
+
if not symbols:
|
|
336
|
+
return {} if not to_dataframe else _batch_klines_to_dataframes({})
|
|
337
|
+
|
|
338
|
+
chunks = _chunk_list(symbols, batch_size)
|
|
339
|
+
|
|
340
|
+
if len(chunks) == 1:
|
|
341
|
+
data, errors = self._fetch_batch_chunk(chunks[0], params, endpoint)
|
|
342
|
+
if to_dataframe:
|
|
343
|
+
names = self._resolve_names(list(data.keys()))
|
|
344
|
+
return _batch_klines_to_dataframes(data, names=names)
|
|
345
|
+
return data
|
|
346
|
+
|
|
347
|
+
pbar = _get_progress_bar(len(chunks), progress_desc, show_progress)
|
|
348
|
+
|
|
349
|
+
all_data: Dict[str, "CompactKlineData"] = {}
|
|
350
|
+
all_errors: List[Tuple[str, Exception]] = []
|
|
351
|
+
|
|
352
|
+
try:
|
|
353
|
+
with concurrent.futures.ThreadPoolExecutor(
|
|
354
|
+
max_workers=max_workers
|
|
355
|
+
) as executor:
|
|
356
|
+
futures = {
|
|
357
|
+
executor.submit(
|
|
358
|
+
self._fetch_batch_chunk, chunk, params, endpoint
|
|
359
|
+
): chunk
|
|
360
|
+
for chunk in chunks
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
for future in concurrent.futures.as_completed(futures):
|
|
364
|
+
try:
|
|
365
|
+
data, errors = future.result()
|
|
366
|
+
all_data.update(data)
|
|
367
|
+
all_errors.extend(errors)
|
|
368
|
+
except Exception as e:
|
|
369
|
+
chunk = futures[future]
|
|
370
|
+
all_errors.extend((s, e) for s in chunk)
|
|
371
|
+
|
|
372
|
+
if pbar:
|
|
373
|
+
pbar.update(1)
|
|
374
|
+
finally:
|
|
375
|
+
if pbar:
|
|
376
|
+
pbar.close()
|
|
377
|
+
|
|
378
|
+
if to_dataframe:
|
|
379
|
+
names = self._resolve_names(list(all_data.keys()))
|
|
380
|
+
return _batch_klines_to_dataframes(all_data, names=names)
|
|
381
|
+
return all_data
|
|
382
|
+
|
|
383
|
+
@overload
|
|
384
|
+
def batch(
|
|
385
|
+
self,
|
|
386
|
+
symbols: List[str],
|
|
387
|
+
*,
|
|
388
|
+
period: Union["Period", NotGiven] = NOT_GIVEN,
|
|
389
|
+
count: Union[int, NotGiven] = NOT_GIVEN,
|
|
390
|
+
start_time: Union[int, None, NotGiven] = NOT_GIVEN,
|
|
391
|
+
end_time: Union[int, None, NotGiven] = NOT_GIVEN,
|
|
392
|
+
adjust: Union["AdjustType", NotGiven] = NOT_GIVEN,
|
|
393
|
+
to_dataframe: Literal[False] = False,
|
|
394
|
+
show_progress: bool = False,
|
|
395
|
+
max_workers: int = 5,
|
|
396
|
+
batch_size: int = MAX_SYMBOLS_PER_BATCH,
|
|
397
|
+
) -> Dict[str, "CompactKlineData"]: ...
|
|
398
|
+
|
|
399
|
+
@overload
|
|
400
|
+
def batch(
|
|
401
|
+
self,
|
|
402
|
+
symbols: List[str],
|
|
403
|
+
*,
|
|
404
|
+
period: Union["Period", NotGiven] = NOT_GIVEN,
|
|
405
|
+
count: Union[int, NotGiven] = NOT_GIVEN,
|
|
406
|
+
start_time: Union[int, None, NotGiven] = NOT_GIVEN,
|
|
407
|
+
end_time: Union[int, None, NotGiven] = NOT_GIVEN,
|
|
408
|
+
adjust: Union["AdjustType", NotGiven] = NOT_GIVEN,
|
|
409
|
+
to_dataframe: Literal[True],
|
|
410
|
+
show_progress: bool = False,
|
|
411
|
+
max_workers: int = 5,
|
|
412
|
+
batch_size: int = MAX_SYMBOLS_PER_BATCH,
|
|
413
|
+
) -> "pd.DataFrame": ...
|
|
414
|
+
|
|
415
|
+
def batch(
|
|
416
|
+
self,
|
|
417
|
+
symbols: List[str],
|
|
418
|
+
*,
|
|
419
|
+
period: Union["Period", NotGiven] = NOT_GIVEN,
|
|
420
|
+
count: Union[int, NotGiven] = NOT_GIVEN,
|
|
421
|
+
start_time: Union[int, None, NotGiven] = NOT_GIVEN,
|
|
422
|
+
end_time: Union[int, None, NotGiven] = NOT_GIVEN,
|
|
423
|
+
adjust: Union["AdjustType", NotGiven] = NOT_GIVEN,
|
|
424
|
+
to_dataframe: bool = False,
|
|
425
|
+
show_progress: bool = False,
|
|
426
|
+
max_workers: int = 5,
|
|
427
|
+
batch_size: int = MAX_SYMBOLS_PER_BATCH,
|
|
428
|
+
) -> Union[Dict[str, "CompactKlineData"], "pd.DataFrame"]:
|
|
429
|
+
"""Get K-line data for multiple symbols in batched concurrent requests.
|
|
430
|
+
|
|
431
|
+
Automatically splits large symbol lists into chunks and fetches them
|
|
432
|
+
concurrently. Failed chunks don't affect other chunks.
|
|
433
|
+
|
|
434
|
+
Parameters
|
|
435
|
+
----------
|
|
436
|
+
symbols : list of str
|
|
437
|
+
List of symbol codes.
|
|
438
|
+
period : str, optional
|
|
439
|
+
K-line period. Defaults to "1d".
|
|
440
|
+
count : int, optional
|
|
441
|
+
Number of K-lines per symbol. Default 100.
|
|
442
|
+
start_time : int, optional
|
|
443
|
+
Start timestamp in milliseconds.
|
|
444
|
+
end_time : int, optional
|
|
445
|
+
End timestamp in milliseconds.
|
|
446
|
+
adjust : str, optional
|
|
447
|
+
Adjustment type: "forward" (前复权, default), "backward" (后复权),
|
|
448
|
+
or "none" (不复权).
|
|
449
|
+
to_dataframe : bool, optional
|
|
450
|
+
If True, return dict of DataFrames. Default False.
|
|
451
|
+
show_progress : bool, optional
|
|
452
|
+
If True, display a progress bar (requires tqdm). Default False.
|
|
453
|
+
max_workers : int, optional
|
|
454
|
+
Maximum number of concurrent requests. Default 5.
|
|
455
|
+
batch_size : int, optional
|
|
456
|
+
Number of symbols per request. Default 100.
|
|
457
|
+
Reduce this if the server enforces a lower per-request limit.
|
|
458
|
+
|
|
459
|
+
Returns
|
|
460
|
+
-------
|
|
461
|
+
dict or pd.DataFrame
|
|
462
|
+
If to_dataframe=False: dict mapping symbol codes to CompactKlineData.
|
|
463
|
+
If to_dataframe=True: dict mapping symbol codes to DataFrames.
|
|
464
|
+
|
|
465
|
+
Examples
|
|
466
|
+
--------
|
|
467
|
+
>>> symbols = ["600000.SH", "000001.SZ", "600519.SH"]
|
|
468
|
+
>>> dfs = client.klines.batch(symbols, to_dataframe=True, show_progress=True)
|
|
469
|
+
"""
|
|
470
|
+
params: Dict[str, Any] = {}
|
|
471
|
+
if not isinstance(period, NotGiven):
|
|
472
|
+
params["period"] = period
|
|
473
|
+
if not isinstance(count, NotGiven):
|
|
474
|
+
params["count"] = count
|
|
475
|
+
if not isinstance(start_time, NotGiven) and start_time is not None:
|
|
476
|
+
params["start_time"] = start_time
|
|
477
|
+
if not isinstance(end_time, NotGiven) and end_time is not None:
|
|
478
|
+
params["end_time"] = end_time
|
|
479
|
+
if not isinstance(adjust, NotGiven):
|
|
480
|
+
params["adjust"] = adjust
|
|
481
|
+
|
|
482
|
+
return self._run_batch(
|
|
483
|
+
symbols=symbols,
|
|
484
|
+
params=params,
|
|
485
|
+
endpoint="/v1/klines/batch",
|
|
486
|
+
batch_size=batch_size,
|
|
487
|
+
to_dataframe=to_dataframe,
|
|
488
|
+
show_progress=show_progress,
|
|
489
|
+
max_workers=max_workers,
|
|
490
|
+
progress_desc="Fetching K-lines",
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
@overload
|
|
494
|
+
def intraday(
|
|
495
|
+
self,
|
|
496
|
+
symbol: str,
|
|
497
|
+
*,
|
|
498
|
+
period: Union["Period", NotGiven] = NOT_GIVEN,
|
|
499
|
+
count: Union[int, NotGiven] = NOT_GIVEN,
|
|
500
|
+
to_dataframe: Literal[False] = False,
|
|
501
|
+
) -> "CompactKlineData": ...
|
|
502
|
+
|
|
503
|
+
@overload
|
|
504
|
+
def intraday(
|
|
505
|
+
self,
|
|
506
|
+
symbol: str,
|
|
507
|
+
*,
|
|
508
|
+
period: Union["Period", NotGiven] = NOT_GIVEN,
|
|
509
|
+
count: Union[int, NotGiven] = NOT_GIVEN,
|
|
510
|
+
to_dataframe: Literal[True],
|
|
511
|
+
) -> "pd.DataFrame": ...
|
|
512
|
+
|
|
513
|
+
def intraday(
|
|
514
|
+
self,
|
|
515
|
+
symbol: str,
|
|
516
|
+
*,
|
|
517
|
+
period: Union["Period", NotGiven] = NOT_GIVEN,
|
|
518
|
+
count: Union[int, NotGiven] = NOT_GIVEN,
|
|
519
|
+
to_dataframe: bool = False,
|
|
520
|
+
) -> Union["CompactKlineData", "pd.DataFrame"]:
|
|
521
|
+
"""Get intraday minute K-line data for a single symbol.
|
|
522
|
+
|
|
523
|
+
This endpoint returns today's minute-level K-line data. The data is
|
|
524
|
+
continuously updated during trading hours.
|
|
525
|
+
|
|
526
|
+
Parameters
|
|
527
|
+
----------
|
|
528
|
+
symbol : str
|
|
529
|
+
Symbol code (e.g., "600000.SH", "AAPL.US").
|
|
530
|
+
period : str, optional
|
|
531
|
+
K-line period. One of: "1m", "5m", "15m", "30m", "60m".
|
|
532
|
+
Defaults to "1m".
|
|
533
|
+
count : int, optional
|
|
534
|
+
Number of K-lines to return. If not specified, returns all
|
|
535
|
+
available data for today.
|
|
536
|
+
to_dataframe : bool, optional
|
|
537
|
+
If True, return a pandas DataFrame. If False (default), return
|
|
538
|
+
the raw compact columnar data.
|
|
539
|
+
|
|
540
|
+
Returns
|
|
541
|
+
-------
|
|
542
|
+
CompactKlineData or pd.DataFrame
|
|
543
|
+
If to_dataframe=False: dict with keys 'timestamp', 'open', 'high',
|
|
544
|
+
'low', 'close', 'volume', 'amount' (each a list).
|
|
545
|
+
If to_dataframe=True: pandas DataFrame with datetime index.
|
|
546
|
+
|
|
547
|
+
Examples
|
|
548
|
+
--------
|
|
549
|
+
>>> # Get today's 1-minute K-lines
|
|
550
|
+
>>> data = client.klines.intraday("600000.SH")
|
|
551
|
+
>>> print(f"Got {len(data['timestamp'])} bars")
|
|
552
|
+
|
|
553
|
+
>>> # Get as DataFrame
|
|
554
|
+
>>> df = client.klines.intraday("600000.SH", to_dataframe=True)
|
|
555
|
+
>>> print(df.tail())
|
|
556
|
+
|
|
557
|
+
>>> # Get 5-minute aggregated data
|
|
558
|
+
>>> df = client.klines.intraday("600000.SH", period="5m", to_dataframe=True)
|
|
559
|
+
"""
|
|
560
|
+
params: Dict[str, Any] = {"symbol": symbol}
|
|
561
|
+
if not isinstance(period, NotGiven):
|
|
562
|
+
params["period"] = period
|
|
563
|
+
if not isinstance(count, NotGiven):
|
|
564
|
+
params["count"] = count
|
|
565
|
+
|
|
566
|
+
response = self._client.get("/v1/klines/intraday", params=params)
|
|
567
|
+
data = response["data"]
|
|
568
|
+
|
|
569
|
+
if to_dataframe:
|
|
570
|
+
name = self._resolve_name(symbol)
|
|
571
|
+
return _klines_to_dataframe(data, symbol=symbol, name=name)
|
|
572
|
+
return data
|
|
573
|
+
|
|
574
|
+
@overload
|
|
575
|
+
def intraday_batch(
|
|
576
|
+
self,
|
|
577
|
+
symbols: List[str],
|
|
578
|
+
*,
|
|
579
|
+
period: Union["Period", NotGiven] = NOT_GIVEN,
|
|
580
|
+
count: Union[int, NotGiven] = NOT_GIVEN,
|
|
581
|
+
to_dataframe: Literal[False] = False,
|
|
582
|
+
show_progress: bool = False,
|
|
583
|
+
max_workers: int = 5,
|
|
584
|
+
batch_size: int = MAX_SYMBOLS_PER_BATCH,
|
|
585
|
+
) -> Dict[str, "CompactKlineData"]: ...
|
|
586
|
+
|
|
587
|
+
@overload
|
|
588
|
+
def intraday_batch(
|
|
589
|
+
self,
|
|
590
|
+
symbols: List[str],
|
|
591
|
+
*,
|
|
592
|
+
period: Union["Period", NotGiven] = NOT_GIVEN,
|
|
593
|
+
count: Union[int, NotGiven] = NOT_GIVEN,
|
|
594
|
+
to_dataframe: Literal[True],
|
|
595
|
+
show_progress: bool = False,
|
|
596
|
+
max_workers: int = 5,
|
|
597
|
+
batch_size: int = MAX_SYMBOLS_PER_BATCH,
|
|
598
|
+
) -> "pd.DataFrame": ...
|
|
599
|
+
|
|
600
|
+
def intraday_batch(
|
|
601
|
+
self,
|
|
602
|
+
symbols: List[str],
|
|
603
|
+
*,
|
|
604
|
+
period: Union["Period", NotGiven] = NOT_GIVEN,
|
|
605
|
+
count: Union[int, NotGiven] = NOT_GIVEN,
|
|
606
|
+
to_dataframe: bool = False,
|
|
607
|
+
show_progress: bool = False,
|
|
608
|
+
max_workers: int = 5,
|
|
609
|
+
batch_size: int = MAX_SYMBOLS_PER_BATCH,
|
|
610
|
+
) -> Union[Dict[str, "CompactKlineData"], "pd.DataFrame"]:
|
|
611
|
+
"""Get intraday K-line data for multiple symbols in batched concurrent requests.
|
|
612
|
+
|
|
613
|
+
Automatically splits large symbol lists into chunks and fetches them
|
|
614
|
+
concurrently. Failed chunks don't affect other chunks.
|
|
615
|
+
|
|
616
|
+
Parameters
|
|
617
|
+
----------
|
|
618
|
+
symbols : list of str
|
|
619
|
+
List of symbol codes.
|
|
620
|
+
period : str, optional
|
|
621
|
+
K-line period. One of: "1m", "5m", "15m", "30m", "60m".
|
|
622
|
+
Defaults to "1m".
|
|
623
|
+
count : int, optional
|
|
624
|
+
Number of K-lines per symbol. If not specified, returns all
|
|
625
|
+
available data for today.
|
|
626
|
+
to_dataframe : bool, optional
|
|
627
|
+
If True, return dict of DataFrames. Default False.
|
|
628
|
+
show_progress : bool, optional
|
|
629
|
+
If True, display a progress bar (requires tqdm). Default False.
|
|
630
|
+
max_workers : int, optional
|
|
631
|
+
Maximum number of concurrent requests. Default 5.
|
|
632
|
+
batch_size : int, optional
|
|
633
|
+
Number of symbols per request. Default 100.
|
|
634
|
+
Reduce this if the server enforces a lower per-request limit.
|
|
635
|
+
|
|
636
|
+
Returns
|
|
637
|
+
-------
|
|
638
|
+
dict or pd.DataFrame
|
|
639
|
+
If to_dataframe=False: dict mapping symbol codes to CompactKlineData.
|
|
640
|
+
If to_dataframe=True: dict mapping symbol codes to DataFrames.
|
|
641
|
+
|
|
642
|
+
Examples
|
|
643
|
+
--------
|
|
644
|
+
>>> symbols = ["600000.SH", "000001.SZ", "600519.SH"]
|
|
645
|
+
>>> dfs = client.klines.intraday_batch(symbols, to_dataframe=True)
|
|
646
|
+
"""
|
|
647
|
+
params: Dict[str, Any] = {}
|
|
648
|
+
if not isinstance(period, NotGiven):
|
|
649
|
+
params["period"] = period
|
|
650
|
+
if not isinstance(count, NotGiven):
|
|
651
|
+
params["count"] = count
|
|
652
|
+
|
|
653
|
+
return self._run_batch(
|
|
654
|
+
symbols=symbols,
|
|
655
|
+
params=params,
|
|
656
|
+
endpoint="/v1/klines/intraday/batch",
|
|
657
|
+
batch_size=batch_size,
|
|
658
|
+
to_dataframe=to_dataframe,
|
|
659
|
+
show_progress=show_progress,
|
|
660
|
+
max_workers=max_workers,
|
|
661
|
+
progress_desc="Fetching intraday K-lines",
|
|
662
|
+
)
|
|
663
|
+
|
|
664
|
+
def ex_factors(
|
|
665
|
+
self,
|
|
666
|
+
symbols: List[str],
|
|
667
|
+
*,
|
|
668
|
+
start_time: Union[int, None, NotGiven] = NOT_GIVEN,
|
|
669
|
+
end_time: Union[int, None, NotGiven] = NOT_GIVEN,
|
|
670
|
+
to_dataframe: bool = False,
|
|
671
|
+
batch_size: int = MAX_SYMBOLS_PER_BATCH,
|
|
672
|
+
show_progress: bool = False,
|
|
673
|
+
max_workers: int = 5,
|
|
674
|
+
) -> Union[Dict[str, List["ExFactorEntry"]], "pd.DataFrame"]:
|
|
675
|
+
"""Get dividend/split adjustment factors for one or more symbols.
|
|
676
|
+
|
|
677
|
+
Parameters
|
|
678
|
+
----------
|
|
679
|
+
symbols : list of str
|
|
680
|
+
Symbol codes (e.g., ["600519.SH", "000001.SZ"]).
|
|
681
|
+
start_time : int, optional
|
|
682
|
+
Filter: only factors with timestamp >= start_time (ms).
|
|
683
|
+
end_time : int, optional
|
|
684
|
+
Filter: only factors with timestamp <= end_time (ms).
|
|
685
|
+
to_dataframe : bool, optional
|
|
686
|
+
If True, return a long-format pandas DataFrame with columns:
|
|
687
|
+
symbol, timestamp, ex_factor, trade_date.
|
|
688
|
+
batch_size : int, optional
|
|
689
|
+
Max symbols per request (default 100).
|
|
690
|
+
show_progress : bool, optional
|
|
691
|
+
Show a tqdm progress bar for multi-chunk fetches.
|
|
692
|
+
max_workers : int, optional
|
|
693
|
+
Concurrent request threads (default 5).
|
|
694
|
+
|
|
695
|
+
Returns
|
|
696
|
+
-------
|
|
697
|
+
dict or pd.DataFrame
|
|
698
|
+
If to_dataframe=False: ``{symbol: [{timestamp, ex_factor}, ...]}``.
|
|
699
|
+
If to_dataframe=True: long-format DataFrame.
|
|
700
|
+
|
|
701
|
+
Examples
|
|
702
|
+
--------
|
|
703
|
+
>>> factors = client.klines.ex_factors(["600519.SH"])
|
|
704
|
+
>>> df = client.klines.ex_factors(["600519.SH", "000001.SZ"], to_dataframe=True)
|
|
705
|
+
"""
|
|
706
|
+
params: Dict[str, Any] = {}
|
|
707
|
+
if not isinstance(start_time, NotGiven) and start_time is not None:
|
|
708
|
+
params["start_time"] = start_time
|
|
709
|
+
if not isinstance(end_time, NotGiven) and end_time is not None:
|
|
710
|
+
params["end_time"] = end_time
|
|
711
|
+
|
|
712
|
+
data = batched_get_sync(
|
|
713
|
+
self._client,
|
|
714
|
+
"/v1/klines/ex-factors",
|
|
715
|
+
symbols,
|
|
716
|
+
params,
|
|
717
|
+
batch_size=batch_size,
|
|
718
|
+
max_workers=max_workers,
|
|
719
|
+
show_progress=show_progress,
|
|
720
|
+
progress_desc="Fetching ex-factors",
|
|
721
|
+
)
|
|
722
|
+
if to_dataframe:
|
|
723
|
+
return _factors_to_dataframe(data)
|
|
724
|
+
return data
|