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.
@@ -0,0 +1,397 @@
1
+ """Real-time quote resources for TickFlow API."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Dict, List, Literal, Optional, Union, overload
6
+
7
+ from .._types import NOT_GIVEN, NotGiven
8
+ from ._base import AsyncResource, SyncResource
9
+
10
+ if TYPE_CHECKING:
11
+ import pandas as pd
12
+
13
+ from ..generated_model import Quote
14
+
15
+
16
+ def _quotes_to_dataframe(data: List["Quote"]) -> "pd.DataFrame":
17
+ """Convert quote data to a pandas DataFrame.
18
+
19
+ Parameters
20
+ ----------
21
+ data : list of Quote
22
+ List of quote dictionaries.
23
+
24
+ Returns
25
+ -------
26
+ pd.DataFrame
27
+ DataFrame with symbol as index.
28
+ """
29
+ import pandas as pd
30
+
31
+ if not data:
32
+ return pd.DataFrame()
33
+
34
+ df = pd.DataFrame(data)
35
+ df["timestamp"] = pd.to_datetime(df["timestamp"], unit="ms")
36
+ df.set_index("symbol", inplace=True)
37
+
38
+ return df
39
+
40
+
41
+ class Quotes(SyncResource):
42
+ """Synchronous interface for real-time quote endpoints.
43
+
44
+ Supports querying quotes by symbol codes or universe IDs.
45
+
46
+ Examples
47
+ --------
48
+ >>> client = TickFlow(api_key="your-key")
49
+ >>>
50
+ >>> # Get quotes by symbols
51
+ >>> quotes = client.quotes.get(symbols=["600000.SH", "AAPL.US"])
52
+ >>>
53
+ >>> # Get quotes by universe
54
+ >>> quotes = client.quotes.get(universes=["CN_Equity_A"])
55
+ """
56
+
57
+ @overload
58
+ def get(
59
+ self,
60
+ *,
61
+ symbols: Union[List[str], str, None] = None,
62
+ universes: Union[List[str], str, None] = None,
63
+ as_dataframe: Literal[False] = False,
64
+ ) -> List["Quote"]: ...
65
+
66
+ @overload
67
+ def get(
68
+ self,
69
+ *,
70
+ symbols: Union[List[str], str, None] = None,
71
+ universes: Union[List[str], str, None] = None,
72
+ as_dataframe: Literal[True],
73
+ ) -> "pd.DataFrame": ...
74
+
75
+ def get(
76
+ self,
77
+ *,
78
+ symbols: Union[List[str], str, None] = None,
79
+ universes: Union[List[str], str, None] = None,
80
+ as_dataframe: bool = False,
81
+ ) -> Union[List["Quote"], "pd.DataFrame"]:
82
+ """Get real-time quotes for symbols or universes.
83
+
84
+ Must provide either `symbols` or `universes`, but not both.
85
+
86
+ Parameters
87
+ ----------
88
+ symbols : str or list of str, optional
89
+ Symbol code(s) to query. Can be a single symbol, comma-separated
90
+ string, or list of symbols.
91
+ universes : str or list of str, optional
92
+ Universe ID(s) to query. Can be a single ID, comma-separated
93
+ string, or list of IDs.
94
+ as_dataframe : bool, optional
95
+ If True, return a pandas DataFrame indexed by symbol.
96
+ If False (default), return a list of Quote dicts.
97
+
98
+ Returns
99
+ -------
100
+ list of Quote or pd.DataFrame
101
+ Quote data for the requested symbols.
102
+
103
+ Each Quote contains:
104
+ - symbol: Symbol code
105
+ - name: Symbol name
106
+ - region: Region code
107
+ - last_price: Latest price
108
+ - prev_close: Previous close
109
+ - open, high, low: OHLC prices
110
+ - volume: Trading volume
111
+ - amount: Trading amount
112
+ - timestamp: Quote timestamp (milliseconds)
113
+ - session: Trading session status
114
+ - ext: Market-specific extension data
115
+
116
+ Raises
117
+ ------
118
+ ValueError
119
+ If neither or both of `symbols` and `universes` are provided.
120
+
121
+ Examples
122
+ --------
123
+ >>> # Query by symbols
124
+ >>> quotes = client.quotes.get(symbols=["600000.SH", "AAPL.US"])
125
+ >>> for q in quotes:
126
+ ... print(f"{q['symbol']}: {q['last_price']}")
127
+
128
+ >>> # Query by universe, as DataFrame
129
+ >>> df = client.quotes.get(universes="CN_Equity_A", as_dataframe=True)
130
+ >>> print(df[["last_price", "volume"]].head())
131
+
132
+ >>> # Find top gainers
133
+ >>> df["change_pct"] = (df["last_price"] - df["prev_close"]) / df["prev_close"] * 100
134
+ >>> top_gainers = df.nlargest(10, "change_pct")
135
+ """
136
+ if (symbols is None) == (universes is None):
137
+ raise ValueError(
138
+ "Must provide either 'symbols' or 'universes', but not both"
139
+ )
140
+
141
+ # Determine whether to use GET (small query) or POST (large query)
142
+ if symbols is not None:
143
+ if isinstance(symbols, str):
144
+ symbols_list = [s.strip() for s in symbols.split(",")]
145
+ else:
146
+ symbols_list = symbols
147
+
148
+ if len(symbols_list) <= 20:
149
+ # Use GET for small queries
150
+ response = self._client.get(
151
+ "/v1/quotes", params={"symbols": ",".join(symbols_list)}
152
+ )
153
+ else:
154
+ # Use POST for large queries
155
+ response = self._client.post(
156
+ "/v1/quotes", json={"symbols": symbols_list}
157
+ )
158
+ else:
159
+ # Universe query
160
+ if isinstance(universes, str):
161
+ universes_list = [u.strip() for u in universes.split(",")]
162
+ else:
163
+ universes_list = universes
164
+
165
+ if len(universes_list) <= 5:
166
+ response = self._client.get(
167
+ "/v1/quotes", params={"universes": ",".join(universes_list)}
168
+ )
169
+ else:
170
+ response = self._client.post(
171
+ "/v1/quotes", json={"universes": universes_list}
172
+ )
173
+
174
+ data = response["data"]
175
+
176
+ if as_dataframe:
177
+ return _quotes_to_dataframe(data)
178
+ return data
179
+
180
+ def get_by_symbols(
181
+ self,
182
+ symbols: List[str],
183
+ *,
184
+ as_dataframe: bool = False,
185
+ ) -> Union[List["Quote"], "pd.DataFrame"]:
186
+ """Get real-time quotes for a list of symbols.
187
+
188
+ This is a convenience method that always uses POST for batch queries.
189
+
190
+ Parameters
191
+ ----------
192
+ symbols : list of str
193
+ List of symbol codes.
194
+ as_dataframe : bool, optional
195
+ If True, return a pandas DataFrame.
196
+
197
+ Returns
198
+ -------
199
+ list of Quote or pd.DataFrame
200
+ Quote data for the requested symbols.
201
+
202
+ Examples
203
+ --------
204
+ >>> quotes = client.quotes.get_by_symbols(["600000.SH", "000001.SZ", "AAPL.US"])
205
+ """
206
+ response = self._client.post("/v1/quotes", json={"symbols": symbols})
207
+ data = response["data"]
208
+
209
+ if as_dataframe:
210
+ return _quotes_to_dataframe(data)
211
+ return data
212
+
213
+ def get_by_universes(
214
+ self,
215
+ universes: List[str],
216
+ *,
217
+ as_dataframe: bool = False,
218
+ ) -> Union[List["Quote"], "pd.DataFrame"]:
219
+ """Get real-time quotes for all symbols in the specified universes.
220
+
221
+ Parameters
222
+ ----------
223
+ universes : list of str
224
+ List of universe IDs.
225
+ as_dataframe : bool, optional
226
+ If True, return a pandas DataFrame.
227
+
228
+ Returns
229
+ -------
230
+ list of Quote or pd.DataFrame
231
+ Quote data for all symbols in the universes.
232
+
233
+ Examples
234
+ --------
235
+ >>> # Get all A-share quotes
236
+ >>> quotes = client.quotes.get_by_universes(["CN_Equity_A"], as_dataframe=True)
237
+ """
238
+ response = self._client.post("/v1/quotes", json={"universes": universes})
239
+ data = response["data"]
240
+
241
+ if as_dataframe:
242
+ return _quotes_to_dataframe(data)
243
+ return data
244
+
245
+
246
+ class AsyncQuotes(AsyncResource):
247
+ """Asynchronous interface for real-time quote endpoints.
248
+
249
+ Supports querying quotes by symbol codes or universe IDs.
250
+
251
+ Examples
252
+ --------
253
+ >>> async with AsyncTickFlow(api_key="your-key") as client:
254
+ ... quotes = await client.quotes.get(symbols=["600000.SH", "AAPL.US"])
255
+ """
256
+
257
+ @overload
258
+ async def get(
259
+ self,
260
+ *,
261
+ symbols: Union[List[str], str, None] = None,
262
+ universes: Union[List[str], str, None] = None,
263
+ as_dataframe: Literal[False] = False,
264
+ ) -> List["Quote"]: ...
265
+
266
+ @overload
267
+ async def get(
268
+ self,
269
+ *,
270
+ symbols: Union[List[str], str, None] = None,
271
+ universes: Union[List[str], str, None] = None,
272
+ as_dataframe: Literal[True],
273
+ ) -> "pd.DataFrame": ...
274
+
275
+ async def get(
276
+ self,
277
+ *,
278
+ symbols: Union[List[str], str, None] = None,
279
+ universes: Union[List[str], str, None] = None,
280
+ as_dataframe: bool = False,
281
+ ) -> Union[List["Quote"], "pd.DataFrame"]:
282
+ """Get real-time quotes for symbols or universes.
283
+
284
+ Must provide either `symbols` or `universes`, but not both.
285
+
286
+ Parameters
287
+ ----------
288
+ symbols : str or list of str, optional
289
+ Symbol code(s) to query.
290
+ universes : str or list of str, optional
291
+ Universe ID(s) to query.
292
+ as_dataframe : bool, optional
293
+ If True, return a pandas DataFrame indexed by symbol.
294
+
295
+ Returns
296
+ -------
297
+ list of Quote or pd.DataFrame
298
+ Quote data for the requested symbols.
299
+
300
+ Examples
301
+ --------
302
+ >>> quotes = await client.quotes.get(symbols=["600000.SH", "AAPL.US"])
303
+ >>> df = await client.quotes.get(universes="CN_Equity_A", as_dataframe=True)
304
+ """
305
+ if (symbols is None) == (universes is None):
306
+ raise ValueError(
307
+ "Must provide either 'symbols' or 'universes', but not both"
308
+ )
309
+
310
+ if symbols is not None:
311
+ if isinstance(symbols, str):
312
+ symbols_list = [s.strip() for s in symbols.split(",")]
313
+ else:
314
+ symbols_list = symbols
315
+
316
+ if len(symbols_list) <= 20:
317
+ response = await self._client.get(
318
+ "/v1/quotes", params={"symbols": ",".join(symbols_list)}
319
+ )
320
+ else:
321
+ response = await self._client.post(
322
+ "/v1/quotes", json={"symbols": symbols_list}
323
+ )
324
+ else:
325
+ if isinstance(universes, str):
326
+ universes_list = [u.strip() for u in universes.split(",")]
327
+ else:
328
+ universes_list = universes
329
+
330
+ if len(universes_list) <= 5:
331
+ response = await self._client.get(
332
+ "/v1/quotes", params={"universes": ",".join(universes_list)}
333
+ )
334
+ else:
335
+ response = await self._client.post(
336
+ "/v1/quotes", json={"universes": universes_list}
337
+ )
338
+
339
+ data = response["data"]
340
+
341
+ if as_dataframe:
342
+ return _quotes_to_dataframe(data)
343
+ return data
344
+
345
+ async def get_by_symbols(
346
+ self,
347
+ symbols: List[str],
348
+ *,
349
+ as_dataframe: bool = False,
350
+ ) -> Union[List["Quote"], "pd.DataFrame"]:
351
+ """Get real-time quotes for a list of symbols.
352
+
353
+ Parameters
354
+ ----------
355
+ symbols : list of str
356
+ List of symbol codes.
357
+ as_dataframe : bool, optional
358
+ If True, return a pandas DataFrame.
359
+
360
+ Returns
361
+ -------
362
+ list of Quote or pd.DataFrame
363
+ Quote data for the requested symbols.
364
+ """
365
+ response = await self._client.post("/v1/quotes", json={"symbols": symbols})
366
+ data = response["data"]
367
+
368
+ if as_dataframe:
369
+ return _quotes_to_dataframe(data)
370
+ return data
371
+
372
+ async def get_by_universes(
373
+ self,
374
+ universes: List[str],
375
+ *,
376
+ as_dataframe: bool = False,
377
+ ) -> Union[List["Quote"], "pd.DataFrame"]:
378
+ """Get real-time quotes for all symbols in the specified universes.
379
+
380
+ Parameters
381
+ ----------
382
+ universes : list of str
383
+ List of universe IDs.
384
+ as_dataframe : bool, optional
385
+ If True, return a pandas DataFrame.
386
+
387
+ Returns
388
+ -------
389
+ list of Quote or pd.DataFrame
390
+ Quote data for all symbols in the universes.
391
+ """
392
+ response = await self._client.post("/v1/quotes", json={"universes": universes})
393
+ data = response["data"]
394
+
395
+ if as_dataframe:
396
+ return _quotes_to_dataframe(data)
397
+ return data
@@ -0,0 +1,176 @@
1
+ """Symbol metadata resources for TickFlow API."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, List, Union, overload
6
+
7
+ from ._base import AsyncResource, SyncResource
8
+
9
+ if TYPE_CHECKING:
10
+ from ..generated_model import SymbolMeta
11
+
12
+
13
+ class Symbols(SyncResource):
14
+ """Synchronous interface for symbol metadata endpoints.
15
+
16
+ Examples
17
+ --------
18
+ >>> client = TickFlow(api_key="your-key")
19
+ >>> meta = client.symbols.get("600000.SH")
20
+ >>> print(f"{meta['symbol']}: {meta['name']}")
21
+ """
22
+
23
+ @overload
24
+ def get(self, symbol: str) -> "SymbolMeta": ...
25
+
26
+ @overload
27
+ def get(self, symbol: List[str]) -> List["SymbolMeta"]: ...
28
+
29
+ def get(
30
+ self, symbol: Union[str, List[str]]
31
+ ) -> Union["SymbolMeta", List["SymbolMeta"]]:
32
+ """Get metadata for one or more symbols.
33
+
34
+ Parameters
35
+ ----------
36
+ symbol : str or list of str
37
+ Symbol code(s). Can be a single symbol string or a list of symbols.
38
+
39
+ Returns
40
+ -------
41
+ SymbolMeta or list of SymbolMeta
42
+ If a single symbol is provided, returns a single SymbolMeta dict.
43
+ If a list is provided, returns a list of SymbolMeta dicts.
44
+
45
+ Each SymbolMeta contains:
46
+ - symbol: Full symbol code (e.g., "600000.SH")
47
+ - code: Exchange-specific code (e.g., "600000")
48
+ - exchange: Exchange code (e.g., "SH")
49
+ - region: Region code (e.g., "CN")
50
+ - name: Symbol name
51
+ - symbol_type: Type (stock, etf, index, etc.)
52
+ - ext: Market-specific extension data
53
+
54
+ Examples
55
+ --------
56
+ >>> # Single symbol
57
+ >>> meta = client.symbols.get("600000.SH")
58
+ >>> print(meta['name'])
59
+
60
+ >>> # Multiple symbols
61
+ >>> metas = client.symbols.get(["600000.SH", "AAPL.US"])
62
+ >>> for m in metas:
63
+ ... print(f"{m['symbol']}: {m['name']}")
64
+ """
65
+ if isinstance(symbol, str):
66
+ response = self._client.get("/v1/symbols", params={"symbols": symbol})
67
+ data = response["data"]
68
+ return data[0] if data else {}
69
+ else:
70
+ # Use POST for batch queries
71
+ response = self._client.post("/v1/symbols", json={"symbols": symbol})
72
+ return response["data"]
73
+
74
+ def batch(self, symbols: List[str]) -> List["SymbolMeta"]:
75
+ """Get metadata for multiple symbols.
76
+
77
+ This method uses POST to handle large batches without URL length limits.
78
+
79
+ Parameters
80
+ ----------
81
+ symbols : list of str
82
+ List of symbol codes (up to 1000).
83
+
84
+ Returns
85
+ -------
86
+ list of SymbolMeta
87
+ List of symbol metadata dicts.
88
+
89
+ Examples
90
+ --------
91
+ >>> metas = client.symbols.batch(["600000.SH", "000001.SZ", "AAPL.US"])
92
+ >>> for m in metas:
93
+ ... print(f"{m['symbol']}: {m['name']}")
94
+ """
95
+ response = self._client.post("/v1/symbols", json={"symbols": symbols})
96
+ return response["data"]
97
+
98
+
99
+ class AsyncSymbols(AsyncResource):
100
+ """Asynchronous interface for symbol metadata endpoints.
101
+
102
+ Examples
103
+ --------
104
+ >>> async with AsyncTickFlow(api_key="your-key") as client:
105
+ ... meta = await client.symbols.get("600000.SH")
106
+ """
107
+
108
+ @overload
109
+ async def get(self, symbol: str) -> "SymbolMeta": ...
110
+
111
+ @overload
112
+ async def get(self, symbol: List[str]) -> List["SymbolMeta"]: ...
113
+
114
+ async def get(
115
+ self, symbol: Union[str, List[str]]
116
+ ) -> Union["SymbolMeta", List["SymbolMeta"]]:
117
+ """Get metadata for one or more symbols.
118
+
119
+ Parameters
120
+ ----------
121
+ symbol : str or list of str
122
+ Symbol code(s). Can be a single symbol string or a list of symbols.
123
+
124
+ Returns
125
+ -------
126
+ SymbolMeta or list of SymbolMeta
127
+ If a single symbol is provided, returns a single SymbolMeta dict.
128
+ If a list is provided, returns a list of SymbolMeta dicts.
129
+
130
+ Each SymbolMeta contains:
131
+ - symbol: Full symbol code (e.g., "600000.SH")
132
+ - code: Exchange-specific code (e.g., "600000")
133
+ - exchange: Exchange code (e.g., "SH")
134
+ - region: Region code (e.g., "CN")
135
+ - name: Symbol name
136
+ - symbol_type: Type (stock, etf, index, etc.)
137
+ - ext: Market-specific extension data
138
+
139
+ Examples
140
+ --------
141
+ >>> # Single symbol
142
+ >>> meta = await client.symbols.get("600000.SH")
143
+ >>> print(meta['name'])
144
+
145
+ >>> # Multiple symbols
146
+ >>> metas = await client.symbols.get(["600000.SH", "AAPL.US"])
147
+ """
148
+ if isinstance(symbol, str):
149
+ response = await self._client.get("/v1/symbols", params={"symbols": symbol})
150
+ data = response["data"]
151
+ return data[0] if data else {}
152
+ else:
153
+ response = await self._client.post("/v1/symbols", json={"symbols": symbol})
154
+ return response["data"]
155
+
156
+ async def batch(self, symbols: List[str]) -> List["SymbolMeta"]:
157
+ """Get metadata for multiple symbols.
158
+
159
+ This method uses POST to handle large batches without URL length limits.
160
+
161
+ Parameters
162
+ ----------
163
+ symbols : list of str
164
+ List of symbol codes (up to 1000).
165
+
166
+ Returns
167
+ -------
168
+ list of SymbolMeta
169
+ List of symbol metadata dicts.
170
+
171
+ Examples
172
+ --------
173
+ >>> metas = await client.symbols.batch(["600000.SH", "000001.SZ", "AAPL.US"])
174
+ """
175
+ response = await self._client.post("/v1/symbols", json={"symbols": symbols})
176
+ return response["data"]
@@ -0,0 +1,138 @@
1
+ """Universe 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 UniverseDetail, UniverseSummary
11
+
12
+
13
+ class Universes(SyncResource):
14
+ """Synchronous interface for universe (symbol pool) endpoints.
15
+
16
+ Universes are predefined collections of symbols, such as "A-shares" or "US equities".
17
+
18
+ Examples
19
+ --------
20
+ >>> client = TickFlow(api_key="your-key")
21
+ >>> universes = client.universes.list()
22
+ >>> for u in universes:
23
+ ... print(f"{u['id']}: {u['name']} ({u['symbol_count']} symbols)")
24
+ """
25
+
26
+ def list(self) -> List["UniverseSummary"]:
27
+ """Get list of all available universes.
28
+
29
+ Returns
30
+ -------
31
+ list of UniverseSummary
32
+ List of universe summaries containing:
33
+ - id: Unique identifier (e.g., "CN_Equity_A")
34
+ - name: Display name
35
+ - region: Region code
36
+ - category: Category (equity, etf, index, etc.)
37
+ - symbol_count: Number of symbols
38
+ - description: Optional description
39
+
40
+ Examples
41
+ --------
42
+ >>> universes = client.universes.list()
43
+ >>> cn_equity = next(u for u in universes if u['id'] == 'CN_Equity_A')
44
+ >>> print(f"A-shares: {cn_equity['symbol_count']} symbols")
45
+ """
46
+ response = self._client.get("/v1/universes")
47
+ return response["data"]
48
+
49
+ def get(self, universe_id: str) -> "UniverseDetail":
50
+ """Get detailed information for a specific universe.
51
+
52
+ Parameters
53
+ ----------
54
+ universe_id : str
55
+ Universe identifier (e.g., "CN_Equity_A", "US_Equity").
56
+
57
+ Returns
58
+ -------
59
+ UniverseDetail
60
+ Universe details including the full list of symbols:
61
+ - id: Unique identifier
62
+ - name: Display name
63
+ - region: Region code
64
+ - category: Category
65
+ - symbol_count: Number of symbols
66
+ - symbols: List of symbol codes
67
+ - description: Optional description
68
+
69
+ Examples
70
+ --------
71
+ >>> universe = client.universes.get("CN_Equity_A")
72
+ >>> print(f"Found {len(universe['symbols'])} A-share symbols")
73
+ """
74
+ response = self._client.get(f"/v1/universes/{universe_id}")
75
+ return response["data"]
76
+
77
+
78
+ class AsyncUniverses(AsyncResource):
79
+ """Asynchronous interface for universe (symbol pool) endpoints.
80
+
81
+ Universes are predefined collections of symbols, such as "A-shares" or "US equities".
82
+
83
+ Examples
84
+ --------
85
+ >>> async with AsyncTickFlow(api_key="your-key") as client:
86
+ ... universes = await client.universes.list()
87
+ """
88
+
89
+ async def list(self) -> List["UniverseSummary"]:
90
+ """Get list of all available universes.
91
+
92
+ Returns
93
+ -------
94
+ list of UniverseSummary
95
+ List of universe summaries containing:
96
+ - id: Unique identifier (e.g., "CN_Equity_A")
97
+ - name: Display name
98
+ - region: Region code
99
+ - category: Category (equity, etf, index, etc.)
100
+ - symbol_count: Number of symbols
101
+ - description: Optional description
102
+
103
+ Examples
104
+ --------
105
+ >>> universes = await client.universes.list()
106
+ >>> cn_equity = next(u for u in universes if u['id'] == 'CN_Equity_A')
107
+ >>> print(f"A-shares: {cn_equity['symbol_count']} symbols")
108
+ """
109
+ response = await self._client.get("/v1/universes")
110
+ return response["data"]
111
+
112
+ async def get(self, universe_id: str) -> "UniverseDetail":
113
+ """Get detailed information for a specific universe.
114
+
115
+ Parameters
116
+ ----------
117
+ universe_id : str
118
+ Universe identifier (e.g., "CN_Equity_A", "US_Equity").
119
+
120
+ Returns
121
+ -------
122
+ UniverseDetail
123
+ Universe details including the full list of symbols:
124
+ - id: Unique identifier
125
+ - name: Display name
126
+ - region: Region code
127
+ - category: Category
128
+ - symbol_count: Number of symbols
129
+ - symbols: List of symbol codes
130
+ - description: Optional description
131
+
132
+ Examples
133
+ --------
134
+ >>> universe = await client.universes.get("CN_Equity_A")
135
+ >>> print(f"Found {len(universe['symbols'])} A-share symbols")
136
+ """
137
+ response = await self._client.get(f"/v1/universes/{universe_id}")
138
+ return response["data"]