agualphacn 0.1.0__tar.gz
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.
- agualphacn-0.1.0/LICENSE +21 -0
- agualphacn-0.1.0/MANIFEST.in +3 -0
- agualphacn-0.1.0/PKG-INFO +483 -0
- agualphacn-0.1.0/README.md +443 -0
- agualphacn-0.1.0/agualphacn/__init__.py +25 -0
- agualphacn-0.1.0/agualphacn/async_client.py +547 -0
- agualphacn-0.1.0/agualphacn/cli.py +297 -0
- agualphacn-0.1.0/agualphacn/client.py +761 -0
- agualphacn-0.1.0/agualphacn/exceptions.py +28 -0
- agualphacn-0.1.0/agualphacn/models.py +139 -0
- agualphacn-0.1.0/agualphacn/utils.py +132 -0
- agualphacn-0.1.0/agualphacn.egg-info/PKG-INFO +483 -0
- agualphacn-0.1.0/agualphacn.egg-info/SOURCES.txt +17 -0
- agualphacn-0.1.0/agualphacn.egg-info/dependency_links.txt +1 -0
- agualphacn-0.1.0/agualphacn.egg-info/entry_points.txt +2 -0
- agualphacn-0.1.0/agualphacn.egg-info/requires.txt +12 -0
- agualphacn-0.1.0/agualphacn.egg-info/top_level.txt +1 -0
- agualphacn-0.1.0/setup.cfg +4 -0
- agualphacn-0.1.0/setup.py +45 -0
agualphacn-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 AGuAlpha
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agualphacn
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for AGuAlpha Investment Platform API
|
|
5
|
+
Home-page: https://github.com/agualpha/agualpha-python
|
|
6
|
+
Author: AGuAlpha
|
|
7
|
+
Author-email: contact@agualpha.com
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Requires-Python: >=3.8
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: requests>=2.28.0
|
|
21
|
+
Provides-Extra: async
|
|
22
|
+
Requires-Dist: aiohttp>=3.8.0; extra == "async"
|
|
23
|
+
Provides-Extra: pandas
|
|
24
|
+
Requires-Dist: pandas>=1.5.0; extra == "pandas"
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
27
|
+
Requires-Dist: black>=22.0.0; extra == "dev"
|
|
28
|
+
Requires-Dist: mypy>=0.950; extra == "dev"
|
|
29
|
+
Dynamic: author
|
|
30
|
+
Dynamic: author-email
|
|
31
|
+
Dynamic: classifier
|
|
32
|
+
Dynamic: description
|
|
33
|
+
Dynamic: description-content-type
|
|
34
|
+
Dynamic: home-page
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
Dynamic: provides-extra
|
|
37
|
+
Dynamic: requires-dist
|
|
38
|
+
Dynamic: requires-python
|
|
39
|
+
Dynamic: summary
|
|
40
|
+
|
|
41
|
+
# AGuAlpha Python Client
|
|
42
|
+
|
|
43
|
+
Official Python library for accessing AGuAlpha Investment Platform data.
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install agualphacn
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For async support:
|
|
52
|
+
```bash
|
|
53
|
+
pip install agualphacn[async]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
For pandas integration:
|
|
57
|
+
```bash
|
|
58
|
+
pip install agualphacn[pandas]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
|
|
63
|
+
### Synchronous Usage
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from agualphacn import AGuAlphaClient
|
|
67
|
+
|
|
68
|
+
# Initialize client
|
|
69
|
+
client = AGuAlphaClient(api_key="sk-your-api-key-here")
|
|
70
|
+
|
|
71
|
+
# Get positions data
|
|
72
|
+
positions = client.get_positions()
|
|
73
|
+
print(f"Total positions: {positions.total}")
|
|
74
|
+
|
|
75
|
+
for position in positions.data:
|
|
76
|
+
print(f"Date: {position.date}, Outstanding: {position.outstanding}")
|
|
77
|
+
|
|
78
|
+
# Get ideas data
|
|
79
|
+
ideas = client.get_ideas(status="active")
|
|
80
|
+
print(f"Total active ideas: {ideas.total}")
|
|
81
|
+
|
|
82
|
+
for idea in ideas.data:
|
|
83
|
+
print(f"Symbol: {idea.ticker_symbol}, Status: {idea.status}")
|
|
84
|
+
|
|
85
|
+
# Close the connection
|
|
86
|
+
client.close()
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Using Context Manager
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from agualphacn import AGuAlphaClient
|
|
93
|
+
|
|
94
|
+
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
|
|
95
|
+
positions = client.get_positions(
|
|
96
|
+
start_date="2024-01-01",
|
|
97
|
+
end_date="2024-12-31"
|
|
98
|
+
)
|
|
99
|
+
print(f"Found {positions.total} positions")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Asynchronous Usage
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
import asyncio
|
|
106
|
+
from agualphacn import AGuAlphaAsyncClient
|
|
107
|
+
|
|
108
|
+
async def main():
|
|
109
|
+
async with AGuAlphaAsyncClient(api_key="sk-your-api-key-here") as client:
|
|
110
|
+
# Fetch data concurrently
|
|
111
|
+
positions, ideas = await asyncio.gather(
|
|
112
|
+
client.get_positions(),
|
|
113
|
+
client.get_ideas(status="active")
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
print(f"Positions: {positions.total}, Ideas: {ideas.total}")
|
|
117
|
+
|
|
118
|
+
asyncio.run(main())
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Pandas Integration
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from agualphacn import AGuAlphaClient
|
|
125
|
+
from agualphacn.utils import positions_to_dataframe, export_to_csv
|
|
126
|
+
|
|
127
|
+
client = AGuAlphaClient(api_key="sk-your-api-key-here")
|
|
128
|
+
|
|
129
|
+
# Get positions and convert to DataFrame
|
|
130
|
+
positions_response = client.get_positions()
|
|
131
|
+
df = positions_to_dataframe(positions_response.data)
|
|
132
|
+
|
|
133
|
+
# Export to CSV
|
|
134
|
+
export_to_csv(positions_response.data, "positions.csv")
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### CSI Weights
|
|
138
|
+
|
|
139
|
+
Read `csi_weights` rows from the `prices` database filtered by index.
|
|
140
|
+
The `index` parameter is **required** and must be one of these semantic names:
|
|
141
|
+
|
|
142
|
+
| Value | Index |
|
|
143
|
+
|------------|--------------------------------|
|
|
144
|
+
| `CSI300` | CSI 300 |
|
|
145
|
+
| `CSI500` | CSI 500 |
|
|
146
|
+
| `CSI1000` | CSI 1000 |
|
|
147
|
+
| `CSI2000` | CSI 2000 |
|
|
148
|
+
|
|
149
|
+
Numeric codes (e.g. `000300`) are **rejected** with HTTP 400.
|
|
150
|
+
|
|
151
|
+
Three mutually-exclusive date filters are supported:
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from agualphacn import AGuAlphaClient
|
|
155
|
+
|
|
156
|
+
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
|
|
157
|
+
# 1) Single day
|
|
158
|
+
df = client.get_csi_weights_dataframe(index="CSI300", date="2026-07-15")
|
|
159
|
+
|
|
160
|
+
# 2) Inclusive range
|
|
161
|
+
df = client.get_csi_weights_dataframe(
|
|
162
|
+
index="CSI300",
|
|
163
|
+
start_date="2026-07-01",
|
|
164
|
+
end_date="2026-07-15",
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# 3) Rolling window — last 30 days up to today
|
|
168
|
+
df = client.get_csi_weights_dataframe(index="CSI300", days=30)
|
|
169
|
+
|
|
170
|
+
print(df.head())
|
|
171
|
+
print(f"Shape: {df.shape}")
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
If you don't need pandas, drop the `_dataframe` suffix to get a list of dicts:
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
|
|
178
|
+
rows = client.get_csi_weights(index="CSI300", days=30)
|
|
179
|
+
print(f"Total records: {len(rows)}")
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Adjusted Close Prices
|
|
183
|
+
|
|
184
|
+
Read `adj_close` rows from the `prices` database. `membership` and a date
|
|
185
|
+
filter are **both required**. The membership selects a universe of tickers;
|
|
186
|
+
choose from:
|
|
187
|
+
|
|
188
|
+
| Value | Universe |
|
|
189
|
+
|------------|-----------------------------------------------------------|
|
|
190
|
+
| `csi300` | CSI 300 constituents |
|
|
191
|
+
| `csi500` | CSI 500 constituents |
|
|
192
|
+
| `csi1000` | CSI 1000 constituents |
|
|
193
|
+
| `csi2000` | CSI 2000 constituents |
|
|
194
|
+
| `csi800` | CSI 800 universe |
|
|
195
|
+
| `csi1800` | CSI 1800 universe |
|
|
196
|
+
| `csi2800` | CSI 2800 universe |
|
|
197
|
+
| `x-csi` | Cross-listed / uncategorized (NULL membership) |
|
|
198
|
+
| `a-shares` | All A-shares (tickers ending `.SZ`, `.SH`, `.BJ`) |
|
|
199
|
+
| `hk` | Hong Kong listed (tickers ending `.HK`) |
|
|
200
|
+
| `etf` | ETFs |
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
from agualphacn import AGuAlphaClient
|
|
204
|
+
|
|
205
|
+
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
|
|
206
|
+
# Single day for CSI 300 constituents
|
|
207
|
+
df = client.get_adj_close_dataframe(membership="csi300", date="2026-07-15")
|
|
208
|
+
|
|
209
|
+
# Inclusive range for HK tickers
|
|
210
|
+
df = client.get_adj_close_dataframe(
|
|
211
|
+
membership="hk",
|
|
212
|
+
start_date="2026-07-01",
|
|
213
|
+
end_date="2026-07-15",
|
|
214
|
+
)
|
|
215
|
+
print(df.head())
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### P-CIES (HK / CN)
|
|
219
|
+
|
|
220
|
+
Read `p_cies` rows from the `prices` database filtered by zone. `zone` is
|
|
221
|
+
**required** and must be exactly `"hk"` or `"cn"`.
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
from agualphacn import AGuAlphaClient
|
|
225
|
+
|
|
226
|
+
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
|
|
227
|
+
df_hk = client.get_p_cies_dataframe(zone="hk")
|
|
228
|
+
df_cn = client.get_p_cies_dataframe(zone="cn")
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### SP Rolling Index (Commodities)
|
|
232
|
+
|
|
233
|
+
Read commodity rolling-index data from the `sp_rolling_index` table (prices
|
|
234
|
+
database). At least **one** filter is required: a product and/or a date filter.
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
from agualphacn import AGuAlphaClient
|
|
238
|
+
|
|
239
|
+
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
|
|
240
|
+
# List available product codes first (e.g. ["CU", "RB", ...])
|
|
241
|
+
products = client.get_sp_rolling_index_products()
|
|
242
|
+
|
|
243
|
+
# All rows for one product
|
|
244
|
+
rows = client.get_sp_rolling_index(product="CU")
|
|
245
|
+
|
|
246
|
+
# Multiple products at once (no count limit)
|
|
247
|
+
rows = client.get_sp_rolling_index(products=["CU", "RB"])
|
|
248
|
+
|
|
249
|
+
# All products in a date range (no product = all commodities)
|
|
250
|
+
rows = client.get_sp_rolling_index(start_date="2025-06-01", end_date="2025-06-30")
|
|
251
|
+
|
|
252
|
+
# Product + date range (intersection)
|
|
253
|
+
df = client.get_sp_rolling_index_dataframe(
|
|
254
|
+
product="CU", start_date="2025-06-01", end_date="2025-06-30",
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# Single day
|
|
258
|
+
rows = client.get_sp_rolling_index(date="2025-06-15")
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
> `date` and `start_date`/`end_date` are mutually exclusive. With no product
|
|
262
|
+
> and no date filter, the server returns `400 Bad Request`.
|
|
263
|
+
|
|
264
|
+
### Limit Events
|
|
265
|
+
|
|
266
|
+
Read `limit_evts` rows (daily limit-up / limit-down events) from the `prices`
|
|
267
|
+
database. A **date filter is required** — either a single day or an inclusive
|
|
268
|
+
range.
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
from agualphacn import AGuAlphaClient
|
|
272
|
+
|
|
273
|
+
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
|
|
274
|
+
# Single day
|
|
275
|
+
rows = client.get_limit_evts(date="2024-06-15")
|
|
276
|
+
|
|
277
|
+
# Inclusive range as a pandas DataFrame
|
|
278
|
+
df = client.get_limit_evts_dataframe(
|
|
279
|
+
start_date="2024-06-01",
|
|
280
|
+
end_date="2024-06-30",
|
|
281
|
+
)
|
|
282
|
+
print(df.head())
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
> `date` and `start_date`/`end_date` are mutually exclusive. With no date
|
|
286
|
+
> filter, the server returns `400 Bad Request`.
|
|
287
|
+
|
|
288
|
+
## API Reference
|
|
289
|
+
|
|
290
|
+
### AGuAlphaClient
|
|
291
|
+
|
|
292
|
+
#### `__init__(api_key: str, base_url: str = "https://www.agualpha.cn/api")`
|
|
293
|
+
Initialize the client with your API key.
|
|
294
|
+
|
|
295
|
+
#### `get_positions(start_date: Optional[str] = None, end_date: Optional[str] = None) -> PositionsResponse`
|
|
296
|
+
Get position data from subscribed analysts.
|
|
297
|
+
|
|
298
|
+
**Parameters:**
|
|
299
|
+
- `start_date` (str): Filter by start date (YYYY-MM-DD format)
|
|
300
|
+
- `end_date` (str): Filter by end date (YYYY-MM-DD format)
|
|
301
|
+
|
|
302
|
+
**Returns:** `PositionsResponse`
|
|
303
|
+
|
|
304
|
+
#### `get_ideas(status: Optional[str] = None, direction: Optional[str] = None) -> IdeasResponse`
|
|
305
|
+
Get trade ideas from subscribed analysts.
|
|
306
|
+
|
|
307
|
+
**Parameters:**
|
|
308
|
+
- `status` (str): Filter by status ("active", "closed")
|
|
309
|
+
- `direction` (str): Filter by direction ("long", "short")
|
|
310
|
+
|
|
311
|
+
**Returns:** `IdeasResponse`
|
|
312
|
+
|
|
313
|
+
#### `get_csi_weights(index: str, date=None, start_date=None, end_date=None, days=None, page=None, page_size=None) -> list`
|
|
314
|
+
Get CSI weights data filtered by index. `index` is **required** and must be one of
|
|
315
|
+
`CSI1000`, `CSI2000`, `CSI300`, `CSI500`. At most one of the date filters may be
|
|
316
|
+
applied: `date` (single day), `start_date`+`end_date` (range), or `days` (rolling
|
|
317
|
+
window). Auto-paginates unless `page` is given.
|
|
318
|
+
|
|
319
|
+
**Returns:** `list` of dicts, each representing a row from the `csi_weights` table.
|
|
320
|
+
|
|
321
|
+
#### `get_csi_weights_dataframe(index: str, date=None, start_date=None, end_date=None, days=None, page=None, page_size=None) -> pandas.DataFrame`
|
|
322
|
+
Same parameters as `get_csi_weights`. Returns a DataFrame. Requires the `pandas` extra (`pip install agualphacn[pandas]`).
|
|
323
|
+
|
|
324
|
+
**Returns:** `pandas.DataFrame`
|
|
325
|
+
|
|
326
|
+
#### `get_revision_fy2(date=None, start_date=None, end_date=None, days=None, ticker=None, type=None, page=None, page_size=None) -> list`
|
|
327
|
+
Get revision_fy2 data from the `cn_af` database. A date filter is **required** —
|
|
328
|
+
exactly one of `date` (single day), `start_date`+`end_date` (range), or `days`
|
|
329
|
+
(rolling window). Optional: `ticker` (e.g. `"000009.SZ"`) and `type`
|
|
330
|
+
(`"eps"`/`"np"`/`"sales"`, no value = all types). Auto-paginates unless `page` is given.
|
|
331
|
+
|
|
332
|
+
**Returns:** `list` of dicts, each representing a row from the `revision_fy2` table.
|
|
333
|
+
|
|
334
|
+
#### `get_revision_fy2_dataframe(date=None, start_date=None, end_date=None, days=None, ticker=None, type=None, page=None, page_size=None) -> pandas.DataFrame`
|
|
335
|
+
Same parameters as `get_revision_fy2`. A date filter is **required**. Requires the `pandas` extra (`pip install agualphacn[pandas]`).
|
|
336
|
+
|
|
337
|
+
**Returns:** `pandas.DataFrame`
|
|
338
|
+
|
|
339
|
+
#### `get_adj_close(membership: str, date=None, start_date=None, end_date=None, page=None, page_size=None) -> list`
|
|
340
|
+
Get adj_close data from the `prices` database. `membership` is **required**
|
|
341
|
+
(universe selector — see the table above); a date filter is **required** —
|
|
342
|
+
either `date` (single day) or `start_date`+`end_date` (inclusive range, either
|
|
343
|
+
bound optional). Auto-paginates unless `page` is given.
|
|
344
|
+
|
|
345
|
+
**Returns:** `list` of dicts, each representing a row from `adj_close`.
|
|
346
|
+
|
|
347
|
+
#### `get_adj_close_dataframe(membership: str, date=None, start_date=None, end_date=None, page=None, page_size=None) -> pandas.DataFrame`
|
|
348
|
+
Same parameters as `get_adj_close`. `membership` and a date filter are **required**. Requires the `pandas` extra (`pip install agualphacn[pandas]`).
|
|
349
|
+
|
|
350
|
+
**Returns:** `pandas.DataFrame`
|
|
351
|
+
|
|
352
|
+
#### `get_p_cies(zone: str, page=None, page_size=None) -> list`
|
|
353
|
+
Get p_cies data from the `prices` database. `zone` is **required** and must be
|
|
354
|
+
`"hk"` or `"cn"`. Auto-paginates unless `page` is given.
|
|
355
|
+
|
|
356
|
+
**Returns:** `list` of dicts, each representing a row from `p_cies`.
|
|
357
|
+
|
|
358
|
+
#### `get_p_cies_dataframe(zone: str, page=None, page_size=None) -> pandas.DataFrame`
|
|
359
|
+
Same parameters as `get_p_cies`. `zone` is **required**. Requires the `pandas` extra (`pip install agualphacn[pandas]`).
|
|
360
|
+
|
|
361
|
+
#### `get_sp_rolling_index(product=None, products=None, date=None, start_date=None, end_date=None, page=None, page_size=None) -> list`
|
|
362
|
+
Get commodity rolling-index rows from the `prices` database. At least **one**
|
|
363
|
+
of `product(s)` or a date filter is **required**. `date` and `start_date`/`end_date`
|
|
364
|
+
are mutually exclusive.
|
|
365
|
+
|
|
366
|
+
- `product` (single string) and `products` (list) are merged; you can pass either or both.
|
|
367
|
+
- With no `product(s)` and no date filter, the server returns `400`.
|
|
368
|
+
|
|
369
|
+
**Returns:** `list` of dicts, each representing a row from `sp_rolling_index`.
|
|
370
|
+
|
|
371
|
+
#### `get_sp_rolling_index_dataframe(product=None, products=None, date=None, start_date=None, end_date=None, page=None, page_size=None) -> pandas.DataFrame`
|
|
372
|
+
Same parameters as `get_sp_rolling_index`. Requires the `pandas` extra.
|
|
373
|
+
|
|
374
|
+
#### `get_sp_rolling_index_products() -> list`
|
|
375
|
+
Return all distinct product codes available in `sp_rolling_index`, sorted ascending.
|
|
376
|
+
Useful for discovering which values are valid for the `product(s)` parameter.
|
|
377
|
+
|
|
378
|
+
**Returns:** `pandas.DataFrame`
|
|
379
|
+
|
|
380
|
+
#### `get_limit_evts(date=None, start_date=None, end_date=None, page=None, page_size=None) -> list`
|
|
381
|
+
Get `limit_evts` rows (daily limit-up / limit-down events) from the `prices`
|
|
382
|
+
database. A date filter is **required**: either `date` (single day) or
|
|
383
|
+
`start_date`/`end_date` (inclusive range). `date` and `start_date`/`end_date`
|
|
384
|
+
are mutually exclusive.
|
|
385
|
+
|
|
386
|
+
**Returns:** `list` of dicts, each representing a row from `limit_evts`.
|
|
387
|
+
|
|
388
|
+
#### `get_limit_evts_dataframe(date=None, start_date=None, end_date=None, page=None, page_size=None) -> pandas.DataFrame`
|
|
389
|
+
Same parameters as `get_limit_evts`. Requires the `pandas` extra.
|
|
390
|
+
|
|
391
|
+
### Response Models
|
|
392
|
+
|
|
393
|
+
#### `PositionsResponse`
|
|
394
|
+
- `success` (bool): Request success status
|
|
395
|
+
- `total` (int): Total number of records
|
|
396
|
+
- `data` (List[Position]): List of position objects
|
|
397
|
+
- `error` (str, optional): Error message if failed
|
|
398
|
+
|
|
399
|
+
#### `IdeasResponse`
|
|
400
|
+
- `success` (bool): Request success status
|
|
401
|
+
- `total` (int): Total number of records
|
|
402
|
+
- `data` (List[Idea]): List of idea objects
|
|
403
|
+
- `error` (str, optional): Error message if failed
|
|
404
|
+
|
|
405
|
+
## Error Handling
|
|
406
|
+
|
|
407
|
+
```python
|
|
408
|
+
from agualphacn import AGuAlphaClient
|
|
409
|
+
from agualphacn.exceptions import APIError, AuthenticationError, RateLimitError
|
|
410
|
+
|
|
411
|
+
try:
|
|
412
|
+
client = AGuAlphaClient(api_key="invalid-key")
|
|
413
|
+
positions = client.get_positions()
|
|
414
|
+
except AuthenticationError:
|
|
415
|
+
print("Invalid API key")
|
|
416
|
+
except RateLimitError as e:
|
|
417
|
+
print(f"Too many requests: {e}")
|
|
418
|
+
except APIError as e:
|
|
419
|
+
print(f"API error: {e}")
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## Rate Limiting
|
|
423
|
+
|
|
424
|
+
The data API limits each API key to **4 requests per second** (sliding 1-second
|
|
425
|
+
window). When the limit is exceeded, the server returns HTTP `429 Too Many
|
|
426
|
+
Requests` with a `Retry-After` header indicating how many seconds to wait. The
|
|
427
|
+
SDK surfaces this as a `RateLimitError` (subclass of `APIError`), so you can
|
|
428
|
+
catch it and back off:
|
|
429
|
+
|
|
430
|
+
```python
|
|
431
|
+
import time
|
|
432
|
+
from agualphacn import AGuAlphaClient
|
|
433
|
+
from agualphacn.exceptions import RateLimitError
|
|
434
|
+
|
|
435
|
+
client = AGuAlphaClient(api_key="your-api-key")
|
|
436
|
+
while True:
|
|
437
|
+
try:
|
|
438
|
+
data = client.get_positions()
|
|
439
|
+
break
|
|
440
|
+
except RateLimitError as e:
|
|
441
|
+
time.sleep(1)
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
## Pagination
|
|
445
|
+
|
|
446
|
+
The server caps each request at **2000 rows**. By default, the SDK
|
|
447
|
+
**auto-paginates** — calling `get_positions()`, `get_ideas()`,
|
|
448
|
+
`get_csi_weights(index=...)`, or `get_revision_fy2(date=...)` with no page
|
|
449
|
+
argument walks every page and returns the full result set in one call. Each
|
|
450
|
+
underlying page request counts against your 4 req/s limit, so large tables
|
|
451
|
+
cost multiple requests.
|
|
452
|
+
|
|
453
|
+
If you want a single page, pass `page` (1-indexed) and optionally `page_size`
|
|
454
|
+
(server caps at 2000):
|
|
455
|
+
|
|
456
|
+
```python
|
|
457
|
+
# Fetch only the first 500 rows of revision_fy2 in the last 30 days
|
|
458
|
+
rows = client.get_revision_fy2(days=30, page=1, page_size=500)
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
When paginating manually, the response object exposes `page`, `page_size`,
|
|
462
|
+
`total_pages`, and `has_more` so you can loop pages yourself:
|
|
463
|
+
|
|
464
|
+
```python
|
|
465
|
+
page = 1
|
|
466
|
+
all_rows = []
|
|
467
|
+
while True:
|
|
468
|
+
resp = client.get_positions(page=page, page_size=1000)
|
|
469
|
+
all_rows.extend(resp.data)
|
|
470
|
+
if not resp.has_more:
|
|
471
|
+
break
|
|
472
|
+
page += 1
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
## Requirements
|
|
477
|
+
|
|
478
|
+
- Python 3.8+
|
|
479
|
+
- requests 2.28.0+
|
|
480
|
+
|
|
481
|
+
## License
|
|
482
|
+
|
|
483
|
+
MIT License
|