tickflow 0.1.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.
- tickflow/__init__.py +136 -0
- tickflow/_base_client.py +353 -0
- tickflow/_exceptions.py +140 -0
- tickflow/_types.py +60 -0
- tickflow/client.py +264 -0
- tickflow/generated_model.py +261 -0
- tickflow/resources/__init__.py +20 -0
- tickflow/resources/_base.py +29 -0
- tickflow/resources/exchanges.py +116 -0
- tickflow/resources/klines.py +460 -0
- tickflow/resources/quotes.py +397 -0
- tickflow/resources/symbols.py +176 -0
- tickflow/resources/universes.py +138 -0
- tickflow-0.1.0.dist-info/METADATA +36 -0
- tickflow-0.1.0.dist-info/RECORD +17 -0
- tickflow-0.1.0.dist-info/WHEEL +5 -0
- tickflow-0.1.0.dist-info/top_level.txt +1 -0
tickflow/client.py
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"""Main client classes for TickFlow API.
|
|
2
|
+
|
|
3
|
+
This module provides the primary interfaces for interacting with the TickFlow API:
|
|
4
|
+
- `TickFlow`: Synchronous client
|
|
5
|
+
- `AsyncTickFlow`: Asynchronous client
|
|
6
|
+
|
|
7
|
+
Both clients provide access to the same resources with consistent method signatures.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import Any, Optional
|
|
13
|
+
|
|
14
|
+
from ._base_client import AsyncAPIClient, SyncAPIClient
|
|
15
|
+
from ._types import Headers, Timeout
|
|
16
|
+
from .resources import (
|
|
17
|
+
AsyncExchanges,
|
|
18
|
+
AsyncKlines,
|
|
19
|
+
AsyncQuotes,
|
|
20
|
+
AsyncSymbols,
|
|
21
|
+
AsyncUniverses,
|
|
22
|
+
Exchanges,
|
|
23
|
+
Klines,
|
|
24
|
+
Quotes,
|
|
25
|
+
Symbols,
|
|
26
|
+
Universes,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
__all__ = ["TickFlow", "AsyncTickFlow"]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TickFlow:
|
|
33
|
+
"""Synchronous client for TickFlow market data API.
|
|
34
|
+
|
|
35
|
+
Provides access to market data including K-lines, quotes, symbol metadata,
|
|
36
|
+
exchanges, and universes.
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
api_key : str, optional
|
|
41
|
+
API key for authentication. If not provided, reads from TICKFLOW_API_KEY
|
|
42
|
+
environment variable.
|
|
43
|
+
base_url : str, optional
|
|
44
|
+
Base URL for the API. Defaults to https://api.tickflow.org.
|
|
45
|
+
Can also be set via TICKFLOW_BASE_URL environment variable.
|
|
46
|
+
timeout : float, optional
|
|
47
|
+
Request timeout in seconds. Defaults to 30.0.
|
|
48
|
+
default_headers : dict, optional
|
|
49
|
+
Default headers to include in all requests.
|
|
50
|
+
|
|
51
|
+
Attributes
|
|
52
|
+
----------
|
|
53
|
+
klines : Klines
|
|
54
|
+
K-line (OHLCV) data endpoints. Supports DataFrame conversion.
|
|
55
|
+
quotes : Quotes
|
|
56
|
+
Real-time quote endpoints.
|
|
57
|
+
symbols : Symbols
|
|
58
|
+
Symbol metadata endpoints.
|
|
59
|
+
exchanges : Exchanges
|
|
60
|
+
Exchange list endpoints.
|
|
61
|
+
universes : Universes
|
|
62
|
+
Universe (symbol pool) endpoints.
|
|
63
|
+
|
|
64
|
+
Examples
|
|
65
|
+
--------
|
|
66
|
+
Basic usage:
|
|
67
|
+
|
|
68
|
+
>>> from tickflow import TickFlow
|
|
69
|
+
>>>
|
|
70
|
+
>>> # Initialize client
|
|
71
|
+
>>> client = TickFlow(api_key="your-api-key")
|
|
72
|
+
>>>
|
|
73
|
+
>>> # Get K-line data as DataFrame
|
|
74
|
+
>>> df = client.klines.get("600000.SH", period="1d", count=100, as_dataframe=True)
|
|
75
|
+
>>> print(df.tail())
|
|
76
|
+
>>>
|
|
77
|
+
>>> # Get real-time quotes
|
|
78
|
+
>>> quotes = client.quotes.get(symbols=["600000.SH", "AAPL.US"])
|
|
79
|
+
>>> for q in quotes:
|
|
80
|
+
... print(f"{q['symbol']}: {q['last_price']}")
|
|
81
|
+
|
|
82
|
+
Using context manager:
|
|
83
|
+
|
|
84
|
+
>>> with TickFlow(api_key="your-api-key") as client:
|
|
85
|
+
... df = client.klines.get("AAPL.US", as_dataframe=True)
|
|
86
|
+
... print(df.tail())
|
|
87
|
+
|
|
88
|
+
Using environment variable:
|
|
89
|
+
|
|
90
|
+
>>> import os
|
|
91
|
+
>>> os.environ["TICKFLOW_API_KEY"] = "your-api-key"
|
|
92
|
+
>>> client = TickFlow() # Uses TICKFLOW_API_KEY
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
klines: Klines
|
|
96
|
+
quotes: Quotes
|
|
97
|
+
symbols: Symbols
|
|
98
|
+
exchanges: Exchanges
|
|
99
|
+
universes: Universes
|
|
100
|
+
|
|
101
|
+
def __init__(
|
|
102
|
+
self,
|
|
103
|
+
api_key: Optional[str] = None,
|
|
104
|
+
*,
|
|
105
|
+
base_url: Optional[str] = None,
|
|
106
|
+
timeout: Timeout = 30.0,
|
|
107
|
+
default_headers: Optional[Headers] = None,
|
|
108
|
+
) -> None:
|
|
109
|
+
self._client = SyncAPIClient(
|
|
110
|
+
api_key=api_key,
|
|
111
|
+
base_url=base_url,
|
|
112
|
+
timeout=timeout,
|
|
113
|
+
default_headers=default_headers,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Initialize resources
|
|
117
|
+
self.klines = Klines(self._client)
|
|
118
|
+
self.quotes = Quotes(self._client)
|
|
119
|
+
self.symbols = Symbols(self._client)
|
|
120
|
+
self.exchanges = Exchanges(self._client)
|
|
121
|
+
self.universes = Universes(self._client)
|
|
122
|
+
|
|
123
|
+
def __enter__(self) -> "TickFlow":
|
|
124
|
+
return self
|
|
125
|
+
|
|
126
|
+
def __exit__(self, *args: Any) -> None:
|
|
127
|
+
self.close()
|
|
128
|
+
|
|
129
|
+
def close(self) -> None:
|
|
130
|
+
"""Close the underlying HTTP client.
|
|
131
|
+
|
|
132
|
+
This releases any network resources held by the client.
|
|
133
|
+
Called automatically when using the client as a context manager.
|
|
134
|
+
"""
|
|
135
|
+
self._client.close()
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def api_key(self) -> str:
|
|
139
|
+
"""The API key used for authentication."""
|
|
140
|
+
return self._client.api_key
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def base_url(self) -> str:
|
|
144
|
+
"""The base URL for API requests."""
|
|
145
|
+
return self._client.base_url
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class AsyncTickFlow:
|
|
149
|
+
"""Asynchronous client for TickFlow market data API.
|
|
150
|
+
|
|
151
|
+
Provides access to market data including K-lines, quotes, symbol metadata,
|
|
152
|
+
exchanges, and universes. All methods are async and must be awaited.
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
api_key : str, optional
|
|
157
|
+
API key for authentication. If not provided, reads from TICKFLOW_API_KEY
|
|
158
|
+
environment variable.
|
|
159
|
+
base_url : str, optional
|
|
160
|
+
Base URL for the API. Defaults to https://api.tickflow.org.
|
|
161
|
+
Can also be set via TICKFLOW_BASE_URL environment variable.
|
|
162
|
+
timeout : float, optional
|
|
163
|
+
Request timeout in seconds. Defaults to 30.0.
|
|
164
|
+
default_headers : dict, optional
|
|
165
|
+
Default headers to include in all requests.
|
|
166
|
+
|
|
167
|
+
Attributes
|
|
168
|
+
----------
|
|
169
|
+
klines : AsyncKlines
|
|
170
|
+
K-line (OHLCV) data endpoints. Supports DataFrame conversion.
|
|
171
|
+
quotes : AsyncQuotes
|
|
172
|
+
Real-time quote endpoints.
|
|
173
|
+
symbols : AsyncSymbols
|
|
174
|
+
Symbol metadata endpoints.
|
|
175
|
+
exchanges : AsyncExchanges
|
|
176
|
+
Exchange list endpoints.
|
|
177
|
+
universes : AsyncUniverses
|
|
178
|
+
Universe (symbol pool) endpoints.
|
|
179
|
+
|
|
180
|
+
Examples
|
|
181
|
+
--------
|
|
182
|
+
Basic usage:
|
|
183
|
+
|
|
184
|
+
>>> import asyncio
|
|
185
|
+
>>> from tickflow import AsyncTickFlow
|
|
186
|
+
>>>
|
|
187
|
+
>>> async def main():
|
|
188
|
+
... async with AsyncTickFlow(api_key="your-api-key") as client:
|
|
189
|
+
... # Get K-line data as DataFrame
|
|
190
|
+
... df = await client.klines.get("600000.SH", as_dataframe=True)
|
|
191
|
+
... print(df.tail())
|
|
192
|
+
...
|
|
193
|
+
... # Get multiple symbols in parallel
|
|
194
|
+
... import asyncio
|
|
195
|
+
... tasks = [
|
|
196
|
+
... client.klines.get(s, as_dataframe=True)
|
|
197
|
+
... for s in ["600000.SH", "000001.SZ", "AAPL.US"]
|
|
198
|
+
... ]
|
|
199
|
+
... results = await asyncio.gather(*tasks)
|
|
200
|
+
>>>
|
|
201
|
+
>>> asyncio.run(main())
|
|
202
|
+
|
|
203
|
+
Manual resource management:
|
|
204
|
+
|
|
205
|
+
>>> async def main():
|
|
206
|
+
... client = AsyncTickFlow(api_key="your-api-key")
|
|
207
|
+
... try:
|
|
208
|
+
... quotes = await client.quotes.get(symbols=["AAPL.US"])
|
|
209
|
+
... print(quotes)
|
|
210
|
+
... finally:
|
|
211
|
+
... await client.close()
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
klines: AsyncKlines
|
|
215
|
+
quotes: AsyncQuotes
|
|
216
|
+
symbols: AsyncSymbols
|
|
217
|
+
exchanges: AsyncExchanges
|
|
218
|
+
universes: AsyncUniverses
|
|
219
|
+
|
|
220
|
+
def __init__(
|
|
221
|
+
self,
|
|
222
|
+
api_key: Optional[str] = None,
|
|
223
|
+
*,
|
|
224
|
+
base_url: Optional[str] = None,
|
|
225
|
+
timeout: Timeout = 30.0,
|
|
226
|
+
default_headers: Optional[Headers] = None,
|
|
227
|
+
) -> None:
|
|
228
|
+
self._client = AsyncAPIClient(
|
|
229
|
+
api_key=api_key,
|
|
230
|
+
base_url=base_url,
|
|
231
|
+
timeout=timeout,
|
|
232
|
+
default_headers=default_headers,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
# Initialize resources
|
|
236
|
+
self.klines = AsyncKlines(self._client)
|
|
237
|
+
self.quotes = AsyncQuotes(self._client)
|
|
238
|
+
self.symbols = AsyncSymbols(self._client)
|
|
239
|
+
self.exchanges = AsyncExchanges(self._client)
|
|
240
|
+
self.universes = AsyncUniverses(self._client)
|
|
241
|
+
|
|
242
|
+
async def __aenter__(self) -> "AsyncTickFlow":
|
|
243
|
+
return self
|
|
244
|
+
|
|
245
|
+
async def __aexit__(self, *args: Any) -> None:
|
|
246
|
+
await self.close()
|
|
247
|
+
|
|
248
|
+
async def close(self) -> None:
|
|
249
|
+
"""Close the underlying HTTP client.
|
|
250
|
+
|
|
251
|
+
This releases any network resources held by the client.
|
|
252
|
+
Called automatically when using the client as an async context manager.
|
|
253
|
+
"""
|
|
254
|
+
await self._client.close()
|
|
255
|
+
|
|
256
|
+
@property
|
|
257
|
+
def api_key(self) -> str:
|
|
258
|
+
"""The API key used for authentication."""
|
|
259
|
+
return self._client.api_key
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def base_url(self) -> str:
|
|
263
|
+
"""The base URL for API requests."""
|
|
264
|
+
return self._client.base_url
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# generated by datamodel-codegen:
|
|
2
|
+
# filename: openapi.json
|
|
3
|
+
# timestamp: 2026-02-03T10:15:08+00:00
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Any, Dict, List, Literal, Optional, TypedDict, Union
|
|
8
|
+
|
|
9
|
+
from typing_extensions import NotRequired, TypeAlias
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ApiError(TypedDict):
|
|
13
|
+
code: str
|
|
14
|
+
details: NotRequired[Any]
|
|
15
|
+
message: str
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BidAsk(TypedDict):
|
|
19
|
+
ask_prices: List[float]
|
|
20
|
+
ask_volumes: List[int]
|
|
21
|
+
bid_prices: List[float]
|
|
22
|
+
bid_volumes: List[int]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class CNQuoteExt(TypedDict):
|
|
26
|
+
bid_ask: NotRequired[Optional[BidAsk]]
|
|
27
|
+
limit_down: float
|
|
28
|
+
limit_up: float
|
|
29
|
+
market_cap: NotRequired[Optional[float]]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class CNSymbolExt(TypedDict):
|
|
33
|
+
delist_date: NotRequired[Optional[int]]
|
|
34
|
+
down_limit: NotRequired[Optional[float]]
|
|
35
|
+
float_shares: NotRequired[Optional[float]]
|
|
36
|
+
is_trading: NotRequired[bool]
|
|
37
|
+
name_en: NotRequired[Optional[str]]
|
|
38
|
+
prev_close: NotRequired[Optional[float]]
|
|
39
|
+
total_shares: NotRequired[Optional[float]]
|
|
40
|
+
up_limit: NotRequired[Optional[float]]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class CompactKlineData(TypedDict):
|
|
44
|
+
amount: NotRequired[List[float]]
|
|
45
|
+
close: List[float]
|
|
46
|
+
high: List[float]
|
|
47
|
+
low: List[float]
|
|
48
|
+
open: List[float]
|
|
49
|
+
timestamp: List[int]
|
|
50
|
+
volume: List[int]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ExchangeSummary(TypedDict):
|
|
54
|
+
count: int
|
|
55
|
+
exchange: str
|
|
56
|
+
region: str
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ExchangeSymbolsResponse(TypedDict):
|
|
60
|
+
count: int
|
|
61
|
+
data: List[str]
|
|
62
|
+
exchange: str
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class HKQuoteExt(TypedDict):
|
|
66
|
+
dividend_yield: NotRequired[Optional[float]]
|
|
67
|
+
lot_size: int
|
|
68
|
+
spread: NotRequired[Optional[float]]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class HKSymbolExt(TypedDict):
|
|
72
|
+
is_trading: NotRequired[bool]
|
|
73
|
+
lot_size: NotRequired[Optional[int]]
|
|
74
|
+
name_cn: NotRequired[Optional[str]]
|
|
75
|
+
prev_close: NotRequired[Optional[float]]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class Kline(TypedDict):
|
|
79
|
+
amount: NotRequired[float]
|
|
80
|
+
close: float
|
|
81
|
+
high: float
|
|
82
|
+
low: float
|
|
83
|
+
open: float
|
|
84
|
+
timestamp: int
|
|
85
|
+
volume: int
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class KlinesBatchQuery(TypedDict):
|
|
89
|
+
count: NotRequired[int]
|
|
90
|
+
end: NotRequired[Optional[int]]
|
|
91
|
+
period: str
|
|
92
|
+
start: NotRequired[Optional[int]]
|
|
93
|
+
symbols: str
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class KlinesBatchResponse(TypedDict):
|
|
97
|
+
data: Dict[str, CompactKlineData]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class KlinesQuery(TypedDict):
|
|
101
|
+
count: NotRequired[int]
|
|
102
|
+
end: NotRequired[Optional[int]]
|
|
103
|
+
period: NotRequired[str]
|
|
104
|
+
start: NotRequired[Optional[int]]
|
|
105
|
+
symbol: str
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class KlinesResponse(TypedDict):
|
|
109
|
+
data: CompactKlineData
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
Period: TypeAlias = Literal[
|
|
113
|
+
"1m", "5m", "10m", "15m", "30m", "60m", "4h", "1d", "1w", "1M"
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class QuoteExtension1(CNQuoteExt):
|
|
118
|
+
type: Literal["CN"]
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class QuoteExtension3(HKQuoteExt):
|
|
122
|
+
type: Literal["HK"]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class QuotesQuery(TypedDict):
|
|
126
|
+
symbols: str
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class QuotesRequest(TypedDict):
|
|
130
|
+
symbols: List[str]
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
Region: TypeAlias = Literal["CN", "US", "HK"]
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
SessionStatus: TypeAlias = Literal[
|
|
137
|
+
"pre_market", "regular", "after_hours", "closed", "halted", "lunch_break"
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class SymbolMetaExt1(CNSymbolExt):
|
|
142
|
+
type: Literal["CN"]
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class SymbolMetaExt3(HKSymbolExt):
|
|
146
|
+
type: Literal["HK"]
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class SymbolsMetaRequest(TypedDict):
|
|
150
|
+
symbols: List[str]
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class SymbolsQuery(TypedDict):
|
|
154
|
+
symbols: str
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class USQuoteExt(TypedDict):
|
|
158
|
+
after_hours_change_pct: NotRequired[Optional[float]]
|
|
159
|
+
after_hours_price: NotRequired[Optional[float]]
|
|
160
|
+
avg_volume_30d: NotRequired[Optional[int]]
|
|
161
|
+
pre_market_change_pct: NotRequired[Optional[float]]
|
|
162
|
+
pre_market_price: NotRequired[Optional[float]]
|
|
163
|
+
week52_high: NotRequired[Optional[float]]
|
|
164
|
+
week52_low: NotRequired[Optional[float]]
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class USSymbolExt(TypedDict):
|
|
168
|
+
full_name: NotRequired[Optional[str]]
|
|
169
|
+
market_cap: NotRequired[Optional[float]]
|
|
170
|
+
sector: NotRequired[Optional[str]]
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class Universe(TypedDict):
|
|
174
|
+
category: str
|
|
175
|
+
description: NotRequired[Optional[str]]
|
|
176
|
+
id: str
|
|
177
|
+
name: str
|
|
178
|
+
region: str
|
|
179
|
+
symbols: List[str]
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class UniverseQuery(TypedDict):
|
|
183
|
+
universes: str
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class UniverseSummary(TypedDict):
|
|
187
|
+
category: str
|
|
188
|
+
description: NotRequired[Optional[str]]
|
|
189
|
+
id: str
|
|
190
|
+
name: str
|
|
191
|
+
region: str
|
|
192
|
+
symbol_count: int
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class ExchangeListResponse(TypedDict):
|
|
196
|
+
data: List[ExchangeSummary]
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class QuoteExtension2(USQuoteExt):
|
|
200
|
+
type: Literal["US"]
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
QuoteExtension: TypeAlias = Union[QuoteExtension1, QuoteExtension2, QuoteExtension3]
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class SymbolMetaExt2(USSymbolExt):
|
|
207
|
+
type: Literal["US"]
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
SymbolMetaExt: TypeAlias = Union[SymbolMetaExt1, SymbolMetaExt2, SymbolMetaExt3]
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class UniverseDetail(UniverseSummary):
|
|
214
|
+
symbols: List[str]
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class UniverseDetailResponse(TypedDict):
|
|
218
|
+
data: UniverseDetail
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class UniverseListResponse(TypedDict):
|
|
222
|
+
data: List[UniverseSummary]
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class Quote(TypedDict):
|
|
226
|
+
amount: float
|
|
227
|
+
ext: NotRequired[Optional[QuoteExtension]]
|
|
228
|
+
high: float
|
|
229
|
+
last_price: float
|
|
230
|
+
low: float
|
|
231
|
+
name: NotRequired[Optional[str]]
|
|
232
|
+
open: float
|
|
233
|
+
prev_close: float
|
|
234
|
+
region: Region
|
|
235
|
+
session: NotRequired[Optional[SessionStatus]]
|
|
236
|
+
symbol: str
|
|
237
|
+
timestamp: int
|
|
238
|
+
volume: int
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class QuotesResponse(TypedDict):
|
|
242
|
+
data: Dict[str, Quote]
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class SymbolMeta(TypedDict):
|
|
246
|
+
code: str
|
|
247
|
+
exchange: str
|
|
248
|
+
ext: NotRequired[Optional[SymbolMetaExt]]
|
|
249
|
+
list_date: NotRequired[Optional[int]]
|
|
250
|
+
name: NotRequired[Optional[str]]
|
|
251
|
+
region: str
|
|
252
|
+
symbol: str
|
|
253
|
+
symbol_type: NotRequired[Optional[str]]
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class SymbolMetaResponse(TypedDict):
|
|
257
|
+
data: List[SymbolMeta]
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class UniverseSnapshotResponse(TypedDict):
|
|
261
|
+
data: List[Quote]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Resource modules for TickFlow API."""
|
|
2
|
+
|
|
3
|
+
from .exchanges import AsyncExchanges, Exchanges
|
|
4
|
+
from .klines import AsyncKlines, Klines
|
|
5
|
+
from .quotes import AsyncQuotes, Quotes
|
|
6
|
+
from .symbols import AsyncSymbols, Symbols
|
|
7
|
+
from .universes import AsyncUniverses, Universes
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"Exchanges",
|
|
11
|
+
"AsyncExchanges",
|
|
12
|
+
"Klines",
|
|
13
|
+
"AsyncKlines",
|
|
14
|
+
"Quotes",
|
|
15
|
+
"AsyncQuotes",
|
|
16
|
+
"Symbols",
|
|
17
|
+
"AsyncSymbols",
|
|
18
|
+
"Universes",
|
|
19
|
+
"AsyncUniverses",
|
|
20
|
+
]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Base resource class for API resources."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Generic, TypeVar
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from .._base_client import AsyncAPIClient, SyncAPIClient
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
ClientT = TypeVar("ClientT", "SyncAPIClient", "AsyncAPIClient")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SyncResource:
|
|
15
|
+
"""Base class for synchronous API resources."""
|
|
16
|
+
|
|
17
|
+
_client: "SyncAPIClient"
|
|
18
|
+
|
|
19
|
+
def __init__(self, client: "SyncAPIClient") -> None:
|
|
20
|
+
self._client = client
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class AsyncResource:
|
|
24
|
+
"""Base class for asynchronous API resources."""
|
|
25
|
+
|
|
26
|
+
_client: "AsyncAPIClient"
|
|
27
|
+
|
|
28
|
+
def __init__(self, client: "AsyncAPIClient") -> None:
|
|
29
|
+
self._client = client
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Exchange resources for TickFlow API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, List
|
|
6
|
+
|
|
7
|
+
from ._base import AsyncResource, SyncResource
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from ..generated_model import ExchangeSummary
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Exchanges(SyncResource):
|
|
14
|
+
"""Synchronous interface for exchange endpoints.
|
|
15
|
+
|
|
16
|
+
Examples
|
|
17
|
+
--------
|
|
18
|
+
>>> client = TickFlow(api_key="your-key")
|
|
19
|
+
>>> exchanges = client.exchanges.list()
|
|
20
|
+
>>> for exchange in exchanges:
|
|
21
|
+
... print(f"{exchange['exchange']}: {exchange['count']} symbols")
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def list(self) -> List["ExchangeSummary"]:
|
|
25
|
+
"""Get list of all exchanges with symbol counts.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
list of ExchangeSummary
|
|
30
|
+
List of exchange information containing:
|
|
31
|
+
- exchange: Exchange code (e.g., "SH", "SZ", "US")
|
|
32
|
+
- region: Region code (e.g., "CN", "US", "HK")
|
|
33
|
+
- count: Number of symbols in the exchange
|
|
34
|
+
|
|
35
|
+
Examples
|
|
36
|
+
--------
|
|
37
|
+
>>> exchanges = client.exchanges.list()
|
|
38
|
+
>>> print(exchanges)
|
|
39
|
+
[{'exchange': 'SH', 'region': 'CN', 'count': 2100}, ...]
|
|
40
|
+
"""
|
|
41
|
+
response = self._client.get("/v1/exchanges")
|
|
42
|
+
return response["data"]
|
|
43
|
+
|
|
44
|
+
def get_symbols(self, exchange: str) -> List[str]:
|
|
45
|
+
"""Get all symbols for a specific exchange.
|
|
46
|
+
|
|
47
|
+
Parameters
|
|
48
|
+
----------
|
|
49
|
+
exchange : str
|
|
50
|
+
Exchange code (e.g., "SH", "SZ", "BJ", "US", "HK").
|
|
51
|
+
|
|
52
|
+
Returns
|
|
53
|
+
-------
|
|
54
|
+
list of str
|
|
55
|
+
List of symbol codes.
|
|
56
|
+
|
|
57
|
+
Examples
|
|
58
|
+
--------
|
|
59
|
+
>>> symbols = client.exchanges.get_symbols("SH")
|
|
60
|
+
>>> print(symbols[:5])
|
|
61
|
+
['600000.SH', '600001.SH', '600002.SH', ...]
|
|
62
|
+
"""
|
|
63
|
+
response = self._client.get(f"/v1/exchanges/{exchange}/symbols")
|
|
64
|
+
return response["data"]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class AsyncExchanges(AsyncResource):
|
|
68
|
+
"""Asynchronous interface for exchange endpoints.
|
|
69
|
+
|
|
70
|
+
Examples
|
|
71
|
+
--------
|
|
72
|
+
>>> async with AsyncTickFlow(api_key="your-key") as client:
|
|
73
|
+
... exchanges = await client.exchanges.list()
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
async def list(self) -> List["ExchangeSummary"]:
|
|
77
|
+
"""Get list of all exchanges with symbol counts.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
list of ExchangeSummary
|
|
82
|
+
List of exchange information containing:
|
|
83
|
+
- exchange: Exchange code (e.g., "SH", "SZ", "US")
|
|
84
|
+
- region: Region code (e.g., "CN", "US", "HK")
|
|
85
|
+
- count: Number of symbols in the exchange
|
|
86
|
+
|
|
87
|
+
Examples
|
|
88
|
+
--------
|
|
89
|
+
>>> exchanges = await client.exchanges.list()
|
|
90
|
+
>>> print(exchanges)
|
|
91
|
+
[{'exchange': 'SH', 'region': 'CN', 'count': 2100}, ...]
|
|
92
|
+
"""
|
|
93
|
+
response = await self._client.get("/v1/exchanges")
|
|
94
|
+
return response["data"]
|
|
95
|
+
|
|
96
|
+
async def get_symbols(self, exchange: str) -> List[str]:
|
|
97
|
+
"""Get all symbols for a specific exchange.
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
exchange : str
|
|
102
|
+
Exchange code (e.g., "SH", "SZ", "BJ", "US", "HK").
|
|
103
|
+
|
|
104
|
+
Returns
|
|
105
|
+
-------
|
|
106
|
+
list of str
|
|
107
|
+
List of symbol codes.
|
|
108
|
+
|
|
109
|
+
Examples
|
|
110
|
+
--------
|
|
111
|
+
>>> symbols = await client.exchanges.get_symbols("SH")
|
|
112
|
+
>>> print(symbols[:5])
|
|
113
|
+
['600000.SH', '600001.SH', '600002.SH', ...]
|
|
114
|
+
"""
|
|
115
|
+
response = await self._client.get(f"/v1/exchanges/{exchange}/symbols")
|
|
116
|
+
return response["data"]
|