tickflow 0.1.0__py3-none-any.whl → 0.1.0.dev1__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/client.py CHANGED
@@ -11,18 +11,18 @@ from __future__ import annotations
11
11
 
12
12
  from typing import Any, Optional
13
13
 
14
- from ._base_client import AsyncAPIClient, SyncAPIClient
14
+ from ._base_client import DEFAULT_MAX_RETRIES, AsyncAPIClient, SyncAPIClient
15
15
  from ._types import Headers, Timeout
16
16
  from .resources import (
17
17
  AsyncExchanges,
18
+ AsyncInstruments,
18
19
  AsyncKlines,
19
20
  AsyncQuotes,
20
- AsyncSymbols,
21
21
  AsyncUniverses,
22
22
  Exchanges,
23
+ Instruments,
23
24
  Klines,
24
25
  Quotes,
25
- Symbols,
26
26
  Universes,
27
27
  )
28
28
 
@@ -32,7 +32,7 @@ __all__ = ["TickFlow", "AsyncTickFlow"]
32
32
  class TickFlow:
33
33
  """Synchronous client for TickFlow market data API.
34
34
 
35
- Provides access to market data including K-lines, quotes, symbol metadata,
35
+ Provides access to market data including K-lines, quotes, instruments,
36
36
  exchanges, and universes.
37
37
 
38
38
  Parameters
@@ -54,8 +54,8 @@ class TickFlow:
54
54
  K-line (OHLCV) data endpoints. Supports DataFrame conversion.
55
55
  quotes : Quotes
56
56
  Real-time quote endpoints.
57
- symbols : Symbols
58
- Symbol metadata endpoints.
57
+ instruments : Instruments
58
+ Instrument metadata endpoints.
59
59
  exchanges : Exchanges
60
60
  Exchange list endpoints.
61
61
  universes : Universes
@@ -94,7 +94,7 @@ class TickFlow:
94
94
 
95
95
  klines: Klines
96
96
  quotes: Quotes
97
- symbols: Symbols
97
+ instruments: Instruments
98
98
  exchanges: Exchanges
99
99
  universes: Universes
100
100
 
@@ -104,19 +104,21 @@ class TickFlow:
104
104
  *,
105
105
  base_url: Optional[str] = None,
106
106
  timeout: Timeout = 30.0,
107
+ max_retries: int = DEFAULT_MAX_RETRIES,
107
108
  default_headers: Optional[Headers] = None,
108
109
  ) -> None:
109
110
  self._client = SyncAPIClient(
110
111
  api_key=api_key,
111
112
  base_url=base_url,
112
113
  timeout=timeout,
114
+ max_retries=max_retries,
113
115
  default_headers=default_headers,
114
116
  )
115
117
 
116
118
  # Initialize resources
117
119
  self.klines = Klines(self._client)
118
120
  self.quotes = Quotes(self._client)
119
- self.symbols = Symbols(self._client)
121
+ self.instruments = Instruments(self._client)
120
122
  self.exchanges = Exchanges(self._client)
121
123
  self.universes = Universes(self._client)
122
124
 
@@ -148,7 +150,7 @@ class TickFlow:
148
150
  class AsyncTickFlow:
149
151
  """Asynchronous client for TickFlow market data API.
150
152
 
151
- Provides access to market data including K-lines, quotes, symbol metadata,
153
+ Provides access to market data including K-lines, quotes, instruments,
152
154
  exchanges, and universes. All methods are async and must be awaited.
153
155
 
154
156
  Parameters
@@ -161,6 +163,9 @@ class AsyncTickFlow:
161
163
  Can also be set via TICKFLOW_BASE_URL environment variable.
162
164
  timeout : float, optional
163
165
  Request timeout in seconds. Defaults to 30.0.
166
+ max_retries : int, optional
167
+ Maximum number of retry attempts for failed requests. Defaults to 3.
168
+ Retries occur on connection errors, timeouts, and server errors (5xx).
164
169
  default_headers : dict, optional
165
170
  Default headers to include in all requests.
166
171
 
@@ -170,8 +175,8 @@ class AsyncTickFlow:
170
175
  K-line (OHLCV) data endpoints. Supports DataFrame conversion.
171
176
  quotes : AsyncQuotes
172
177
  Real-time quote endpoints.
173
- symbols : AsyncSymbols
174
- Symbol metadata endpoints.
178
+ instruments : AsyncInstruments
179
+ Instrument metadata endpoints.
175
180
  exchanges : AsyncExchanges
176
181
  Exchange list endpoints.
177
182
  universes : AsyncUniverses
@@ -213,7 +218,7 @@ class AsyncTickFlow:
213
218
 
214
219
  klines: AsyncKlines
215
220
  quotes: AsyncQuotes
216
- symbols: AsyncSymbols
221
+ instruments: AsyncInstruments
217
222
  exchanges: AsyncExchanges
218
223
  universes: AsyncUniverses
219
224
 
@@ -223,19 +228,21 @@ class AsyncTickFlow:
223
228
  *,
224
229
  base_url: Optional[str] = None,
225
230
  timeout: Timeout = 30.0,
231
+ max_retries: int = DEFAULT_MAX_RETRIES,
226
232
  default_headers: Optional[Headers] = None,
227
233
  ) -> None:
228
234
  self._client = AsyncAPIClient(
229
235
  api_key=api_key,
230
236
  base_url=base_url,
231
237
  timeout=timeout,
238
+ max_retries=max_retries,
232
239
  default_headers=default_headers,
233
240
  )
234
241
 
235
242
  # Initialize resources
236
243
  self.klines = AsyncKlines(self._client)
237
244
  self.quotes = AsyncQuotes(self._client)
238
- self.symbols = AsyncSymbols(self._client)
245
+ self.instruments = AsyncInstruments(self._client)
239
246
  self.exchanges = AsyncExchanges(self._client)
240
247
  self.universes = AsyncUniverses(self._client)
241
248
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: openapi.json
3
- # timestamp: 2026-02-03T10:15:08+00:00
3
+ # timestamp: 2026-02-03T15:11:44+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -22,14 +22,7 @@ class BidAsk(TypedDict):
22
22
  bid_volumes: List[int]
23
23
 
24
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):
25
+ class CNInstrumentExt(TypedDict):
33
26
  delist_date: NotRequired[Optional[int]]
34
27
  down_limit: NotRequired[Optional[float]]
35
28
  float_shares: NotRequired[Optional[float]]
@@ -40,6 +33,13 @@ class CNSymbolExt(TypedDict):
40
33
  up_limit: NotRequired[Optional[float]]
41
34
 
42
35
 
36
+ class CNQuoteExt(TypedDict):
37
+ bid_ask: NotRequired[Optional[BidAsk]]
38
+ limit_down: float
39
+ limit_up: float
40
+ market_cap: NotRequired[Optional[float]]
41
+
42
+
43
43
  class CompactKlineData(TypedDict):
44
44
  amount: NotRequired[List[float]]
45
45
  close: List[float]
@@ -50,16 +50,21 @@ class CompactKlineData(TypedDict):
50
50
  volume: List[int]
51
51
 
52
52
 
53
- class ExchangeSummary(TypedDict):
53
+ class ExchangeInfo(TypedDict):
54
54
  count: int
55
55
  exchange: str
56
56
  region: str
57
57
 
58
58
 
59
- class ExchangeSymbolsResponse(TypedDict):
60
- count: int
61
- data: List[str]
62
- exchange: str
59
+ class ExchangeListResponse(TypedDict):
60
+ data: List[ExchangeInfo]
61
+
62
+
63
+ class HKInstrumentExt(TypedDict):
64
+ is_trading: NotRequired[bool]
65
+ lot_size: NotRequired[Optional[int]]
66
+ name_cn: NotRequired[Optional[str]]
67
+ prev_close: NotRequired[Optional[float]]
63
68
 
64
69
 
65
70
  class HKQuoteExt(TypedDict):
@@ -68,11 +73,25 @@ class HKQuoteExt(TypedDict):
68
73
  spread: NotRequired[Optional[float]]
69
74
 
70
75
 
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
+ class InstrumentExt1(CNInstrumentExt):
77
+ type: Literal["CN"]
78
+
79
+
80
+ class InstrumentExt3(HKInstrumentExt):
81
+ type: Literal["HK"]
82
+
83
+
84
+ InstrumentType: TypeAlias = Literal[
85
+ "stock", "etf", "index", "bond", "fund", "futures", "options", "other"
86
+ ]
87
+
88
+
89
+ class InstrumentsQuery(TypedDict):
90
+ symbols: str
91
+
92
+
93
+ class InstrumentsRequest(TypedDict):
94
+ symbols: List[str]
76
95
 
77
96
 
78
97
  class Kline(TypedDict):
@@ -85,26 +104,10 @@ class Kline(TypedDict):
85
104
  volume: int
86
105
 
87
106
 
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
107
  class KlinesBatchResponse(TypedDict):
97
108
  data: Dict[str, CompactKlineData]
98
109
 
99
110
 
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
111
  class KlinesResponse(TypedDict):
109
112
  data: CompactKlineData
110
113
 
@@ -123,11 +126,13 @@ class QuoteExtension3(HKQuoteExt):
123
126
 
124
127
 
125
128
  class QuotesQuery(TypedDict):
126
- symbols: str
129
+ symbols: NotRequired[Optional[str]]
130
+ universes: NotRequired[Optional[str]]
127
131
 
128
132
 
129
133
  class QuotesRequest(TypedDict):
130
- symbols: List[str]
134
+ symbols: NotRequired[List[str]]
135
+ universes: NotRequired[List[str]]
131
136
 
132
137
 
133
138
  Region: TypeAlias = Literal["CN", "US", "HK"]
@@ -138,20 +143,10 @@ SessionStatus: TypeAlias = Literal[
138
143
  ]
139
144
 
140
145
 
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
146
+ class USInstrumentExt(TypedDict):
147
+ full_name: NotRequired[Optional[str]]
148
+ market_cap: NotRequired[Optional[float]]
149
+ sector: NotRequired[Optional[str]]
155
150
 
156
151
 
157
152
  class USQuoteExt(TypedDict):
@@ -164,12 +159,6 @@ class USQuoteExt(TypedDict):
164
159
  week52_low: NotRequired[Optional[float]]
165
160
 
166
161
 
167
- class USSymbolExt(TypedDict):
168
- full_name: NotRequired[Optional[str]]
169
- market_cap: NotRequired[Optional[float]]
170
- sector: NotRequired[Optional[str]]
171
-
172
-
173
162
  class Universe(TypedDict):
174
163
  category: str
175
164
  description: NotRequired[Optional[str]]
@@ -179,10 +168,6 @@ class Universe(TypedDict):
179
168
  symbols: List[str]
180
169
 
181
170
 
182
- class UniverseQuery(TypedDict):
183
- universes: str
184
-
185
-
186
171
  class UniverseSummary(TypedDict):
187
172
  category: str
188
173
  description: NotRequired[Optional[str]]
@@ -192,22 +177,38 @@ class UniverseSummary(TypedDict):
192
177
  symbol_count: int
193
178
 
194
179
 
195
- class ExchangeListResponse(TypedDict):
196
- data: List[ExchangeSummary]
180
+ class ExchangeInstrumentsQuery(TypedDict):
181
+ type: NotRequired[Optional[InstrumentType]]
197
182
 
198
183
 
199
- class QuoteExtension2(USQuoteExt):
184
+ class InstrumentExt2(USInstrumentExt):
200
185
  type: Literal["US"]
201
186
 
202
187
 
203
- QuoteExtension: TypeAlias = Union[QuoteExtension1, QuoteExtension2, QuoteExtension3]
188
+ InstrumentExt: TypeAlias = Union[InstrumentExt1, InstrumentExt2, InstrumentExt3]
204
189
 
205
190
 
206
- class SymbolMetaExt2(USSymbolExt):
191
+ class KlinesBatchQuery(TypedDict):
192
+ count: NotRequired[int]
193
+ end_time: NotRequired[Optional[int]]
194
+ period: NotRequired[Period]
195
+ start_time: NotRequired[Optional[int]]
196
+ symbols: str
197
+
198
+
199
+ class KlinesQuery(TypedDict):
200
+ count: NotRequired[int]
201
+ end_time: NotRequired[Optional[int]]
202
+ period: NotRequired[Period]
203
+ start_time: NotRequired[Optional[int]]
204
+ symbol: str
205
+
206
+
207
+ class QuoteExtension2(USQuoteExt):
207
208
  type: Literal["US"]
208
209
 
209
210
 
210
- SymbolMetaExt: TypeAlias = Union[SymbolMetaExt1, SymbolMetaExt2, SymbolMetaExt3]
211
+ QuoteExtension: TypeAlias = Union[QuoteExtension1, QuoteExtension2, QuoteExtension3]
211
212
 
212
213
 
213
214
  class UniverseDetail(UniverseSummary):
@@ -222,6 +223,20 @@ class UniverseListResponse(TypedDict):
222
223
  data: List[UniverseSummary]
223
224
 
224
225
 
226
+ class Instrument(TypedDict):
227
+ code: str
228
+ exchange: str
229
+ ext: NotRequired[Optional[InstrumentExt]]
230
+ instrument_type: NotRequired[Optional[InstrumentType]]
231
+ name: NotRequired[Optional[str]]
232
+ region: str
233
+ symbol: str
234
+
235
+
236
+ class InstrumentsResponse(TypedDict):
237
+ data: List[Instrument]
238
+
239
+
225
240
  class Quote(TypedDict):
226
241
  amount: float
227
242
  ext: NotRequired[Optional[QuoteExtension]]
@@ -239,23 +254,10 @@ class Quote(TypedDict):
239
254
 
240
255
 
241
256
  class QuotesResponse(TypedDict):
242
- data: Dict[str, Quote]
257
+ data: List[Quote]
243
258
 
244
259
 
245
- class SymbolMeta(TypedDict):
246
- code: str
260
+ class ExchangeInstrumentsResponse(TypedDict):
261
+ count: int
262
+ data: List[Instrument]
247
263
  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]
@@ -1,20 +1,20 @@
1
1
  """Resource modules for TickFlow API."""
2
2
 
3
3
  from .exchanges import AsyncExchanges, Exchanges
4
+ from .instruments import AsyncInstruments, Instruments
4
5
  from .klines import AsyncKlines, Klines
5
6
  from .quotes import AsyncQuotes, Quotes
6
- from .symbols import AsyncSymbols, Symbols
7
7
  from .universes import AsyncUniverses, Universes
8
8
 
9
9
  __all__ = [
10
10
  "Exchanges",
11
11
  "AsyncExchanges",
12
+ "Instruments",
13
+ "AsyncInstruments",
12
14
  "Klines",
13
15
  "AsyncKlines",
14
16
  "Quotes",
15
17
  "AsyncQuotes",
16
- "Symbols",
17
- "AsyncSymbols",
18
18
  "Universes",
19
19
  "AsyncUniverses",
20
20
  ]
@@ -2,12 +2,12 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import TYPE_CHECKING, List
5
+ from typing import TYPE_CHECKING, List, Optional
6
6
 
7
7
  from ._base import AsyncResource, SyncResource
8
8
 
9
9
  if TYPE_CHECKING:
10
- from ..generated_model import ExchangeSummary
10
+ from ..generated_model import ExchangeSummary, Instrument, InstrumentType
11
11
 
12
12
 
13
13
  class Exchanges(SyncResource):
@@ -18,11 +18,11 @@ class Exchanges(SyncResource):
18
18
  >>> client = TickFlow(api_key="your-key")
19
19
  >>> exchanges = client.exchanges.list()
20
20
  >>> for exchange in exchanges:
21
- ... print(f"{exchange['exchange']}: {exchange['count']} symbols")
21
+ ... print(f"{exchange['exchange']}: {exchange['count']} instruments")
22
22
  """
23
23
 
24
24
  def list(self) -> List["ExchangeSummary"]:
25
- """Get list of all exchanges with symbol counts.
25
+ """Get list of all exchanges with instrument counts.
26
26
 
27
27
  Returns
28
28
  -------
@@ -30,7 +30,7 @@ class Exchanges(SyncResource):
30
30
  List of exchange information containing:
31
31
  - exchange: Exchange code (e.g., "SH", "SZ", "US")
32
32
  - region: Region code (e.g., "CN", "US", "HK")
33
- - count: Number of symbols in the exchange
33
+ - count: Number of instruments in the exchange
34
34
 
35
35
  Examples
36
36
  --------
@@ -41,26 +41,39 @@ class Exchanges(SyncResource):
41
41
  response = self._client.get("/v1/exchanges")
42
42
  return response["data"]
43
43
 
44
- def get_symbols(self, exchange: str) -> List[str]:
45
- """Get all symbols for a specific exchange.
44
+ def get_instruments(
45
+ self, exchange: str, instrument_type: Optional["InstrumentType"] = None
46
+ ) -> List["Instrument"]:
47
+ """Get all instruments for a specific exchange.
46
48
 
47
49
  Parameters
48
50
  ----------
49
51
  exchange : str
50
52
  Exchange code (e.g., "SH", "SZ", "BJ", "US", "HK").
53
+ instrument_type : InstrumentType, optional
54
+ Filter by instrument type (stock, etf, index, bond, fund, etc.).
51
55
 
52
56
  Returns
53
57
  -------
54
- list of str
55
- List of symbol codes.
58
+ list of Instrument
59
+ List of instrument metadata.
56
60
 
57
61
  Examples
58
62
  --------
59
- >>> symbols = client.exchanges.get_symbols("SH")
60
- >>> print(symbols[:5])
61
- ['600000.SH', '600001.SH', '600002.SH', ...]
63
+ >>> # Get all instruments
64
+ >>> instruments = client.exchanges.get_instruments("SH")
65
+ >>> print(f"Found {len(instruments)} instruments")
66
+
67
+ >>> # Get only ETFs
68
+ >>> etfs = client.exchanges.get_instruments("SH", instrument_type="etf")
69
+ >>> print(f"Found {len(etfs)} ETFs")
62
70
  """
63
- response = self._client.get(f"/v1/exchanges/{exchange}/symbols")
71
+ params = {}
72
+ if instrument_type is not None:
73
+ params["type"] = instrument_type
74
+ response = self._client.get(
75
+ f"/v1/exchanges/{exchange}/instruments", params=params or None
76
+ )
64
77
  return response["data"]
65
78
 
66
79
 
@@ -74,7 +87,7 @@ class AsyncExchanges(AsyncResource):
74
87
  """
75
88
 
76
89
  async def list(self) -> List["ExchangeSummary"]:
77
- """Get list of all exchanges with symbol counts.
90
+ """Get list of all exchanges with instrument counts.
78
91
 
79
92
  Returns
80
93
  -------
@@ -82,7 +95,7 @@ class AsyncExchanges(AsyncResource):
82
95
  List of exchange information containing:
83
96
  - exchange: Exchange code (e.g., "SH", "SZ", "US")
84
97
  - region: Region code (e.g., "CN", "US", "HK")
85
- - count: Number of symbols in the exchange
98
+ - count: Number of instruments in the exchange
86
99
 
87
100
  Examples
88
101
  --------
@@ -93,24 +106,37 @@ class AsyncExchanges(AsyncResource):
93
106
  response = await self._client.get("/v1/exchanges")
94
107
  return response["data"]
95
108
 
96
- async def get_symbols(self, exchange: str) -> List[str]:
97
- """Get all symbols for a specific exchange.
109
+ async def get_instruments(
110
+ self, exchange: str, instrument_type: Optional["InstrumentType"] = None
111
+ ) -> List["Instrument"]:
112
+ """Get all instruments for a specific exchange.
98
113
 
99
114
  Parameters
100
115
  ----------
101
116
  exchange : str
102
117
  Exchange code (e.g., "SH", "SZ", "BJ", "US", "HK").
118
+ instrument_type : InstrumentType, optional
119
+ Filter by instrument type (stock, etf, index, bond, fund, etc.).
103
120
 
104
121
  Returns
105
122
  -------
106
- list of str
107
- List of symbol codes.
123
+ list of Instrument
124
+ List of instrument metadata.
108
125
 
109
126
  Examples
110
127
  --------
111
- >>> symbols = await client.exchanges.get_symbols("SH")
112
- >>> print(symbols[:5])
113
- ['600000.SH', '600001.SH', '600002.SH', ...]
128
+ >>> # Get all instruments
129
+ >>> instruments = await client.exchanges.get_instruments("SH")
130
+ >>> print(f"Found {len(instruments)} instruments")
131
+
132
+ >>> # Get only ETFs
133
+ >>> etfs = await client.exchanges.get_instruments("SH", instrument_type="etf")
134
+ >>> print(f"Found {len(etfs)} ETFs")
114
135
  """
115
- response = await self._client.get(f"/v1/exchanges/{exchange}/symbols")
136
+ params = {}
137
+ if instrument_type is not None:
138
+ params["type"] = instrument_type
139
+ response = await self._client.get(
140
+ f"/v1/exchanges/{exchange}/instruments", params=params or None
141
+ )
116
142
  return response["data"]