AGuAlpha Python Client
Official Python library for accessing AGuAlpha Investment Platform data.
Installation
pip install agualphacn
For async support:
pip install agualphacn[async]
For pandas integration:
pip install agualphacn[pandas]
Quick Start
Synchronous Usage
from agualphacn import AGuAlphaClient
# Initialize client
client = AGuAlphaClient(api_key="sk-your-api-key-here")
# Get positions data
positions = client.get_positions()
print(f"Total positions: {positions.total}")
for position in positions.data:
print(f"Date: {position.date}, Outstanding: {position.outstanding}")
# Get ideas data
ideas = client.get_ideas(status="active")
print(f"Total active ideas: {ideas.total}")
for idea in ideas.data:
print(f"Symbol: {idea.ticker_symbol}, Status: {idea.status}")
# Close the connection
client.close()
Using Context Manager
from agualphacn import AGuAlphaClient
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
positions = client.get_positions(
start_date="2024-01-01",
end_date="2024-12-31"
)
print(f"Found {positions.total} positions")
Asynchronous Usage
import asyncio
from agualphacn import AGuAlphaAsyncClient
async def main():
async with AGuAlphaAsyncClient(api_key="sk-your-api-key-here") as client:
# Fetch data concurrently
positions, ideas = await asyncio.gather(
client.get_positions(),
client.get_ideas(status="active")
)
print(f"Positions: {positions.total}, Ideas: {ideas.total}")
asyncio.run(main())
Pandas Integration
from agualphacn import AGuAlphaClient
from agualphacn.utils import positions_to_dataframe, export_to_csv
client = AGuAlphaClient(api_key="sk-your-api-key-here")
# Get positions and convert to DataFrame
positions_response = client.get_positions()
df = positions_to_dataframe(positions_response.data)
# Export to CSV
export_to_csv(positions_response.data, "positions.csv")
CSI Weights
Read csi_weights rows from the prices database filtered by index.
The index parameter is required and must be one of these semantic names:
| Value | Index |
|---|---|
CSI300 |
CSI 300 |
CSI500 |
CSI 500 |
CSI1000 |
CSI 1000 |
CSI2000 |
CSI 2000 |
Numeric codes (e.g. 000300) are rejected with HTTP 400.
Three mutually-exclusive date filters are supported:
from agualphacn import AGuAlphaClient
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
# 1) Single day
df = client.get_csi_weights_dataframe(index="CSI300", date="2026-07-15")
# 2) Inclusive range
df = client.get_csi_weights_dataframe(
index="CSI300",
start_date="2026-07-01",
end_date="2026-07-15",
)
# 3) Rolling window — last 30 days up to today
df = client.get_csi_weights_dataframe(index="CSI300", days=30)
print(df.head())
print(f"Shape: {df.shape}")
If you don't need pandas, drop the _dataframe suffix to get a list of dicts:
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
rows = client.get_csi_weights(index="CSI300", days=30)
print(f"Total records: {len(rows)}")
Adjusted Close Prices
Read adj_close rows from the prices database. membership and a date
filter are both required. The membership selects a universe of tickers;
choose from:
| Value | Universe |
|---|---|
csi300 |
CSI 300 constituents |
csi500 |
CSI 500 constituents |
csi1000 |
CSI 1000 constituents |
csi2000 |
CSI 2000 constituents |
csi800 |
CSI 800 universe |
csi1800 |
CSI 1800 universe |
csi2800 |
CSI 2800 universe |
x-csi |
Cross-listed / uncategorized (NULL membership) |
a-shares |
All A-shares (tickers ending .SZ, .SH, .BJ) |
hk |
Hong Kong listed (tickers ending .HK) |
etf |
ETFs |
from agualphacn import AGuAlphaClient
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
# Single day for CSI 300 constituents
df = client.get_adj_close_dataframe(membership="csi300", date="2026-07-15")
# Inclusive range for HK tickers
df = client.get_adj_close_dataframe(
membership="hk",
start_date="2026-07-01",
end_date="2026-07-15",
)
print(df.head())
P-CIES (HK / CN)
Read p_cies rows from the prices database filtered by zone. zone is
required and must be exactly "hk" or "cn".
from agualphacn import AGuAlphaClient
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
df_hk = client.get_p_cies_dataframe(zone="hk")
df_cn = client.get_p_cies_dataframe(zone="cn")
SP Rolling Index (Commodities)
Read commodity rolling-index data from the sp_rolling_index table (prices
database). At least one filter is required: a product and/or a date filter.
from agualphacn import AGuAlphaClient
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
# List available product codes first (e.g. ["CU", "RB", ...])
products = client.get_sp_rolling_index_products()
# All rows for one product
rows = client.get_sp_rolling_index(product="CU")
# Multiple products at once (no count limit)
rows = client.get_sp_rolling_index(products=["CU", "RB"])
# All products in a date range (no product = all commodities)
rows = client.get_sp_rolling_index(start_date="2025-06-01", end_date="2025-06-30")
# Product + date range (intersection)
df = client.get_sp_rolling_index_dataframe(
product="CU", start_date="2025-06-01", end_date="2025-06-30",
)
# Single day
rows = client.get_sp_rolling_index(date="2025-06-15")
dateandstart_date/end_dateare mutually exclusive. With no product and no date filter, the server returns400 Bad Request.
Limit Events
Read limit_evts rows (daily limit-up / limit-down events) from the prices
database. A date filter is required — either a single day or an inclusive
range.
from agualphacn import AGuAlphaClient
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
# Single day
rows = client.get_limit_evts(date="2024-06-15")
# Inclusive range as a pandas DataFrame
df = client.get_limit_evts_dataframe(
start_date="2024-06-01",
end_date="2024-06-30",
)
print(df.head())
dateandstart_date/end_dateare mutually exclusive. With no date filter, the server returns400 Bad Request.
API Reference
AGuAlphaClient
__init__(api_key: str, base_url: str = "https://www.agualpha.cn/api")
Initialize the client with your API key.
get_positions(start_date: Optional[str] = None, end_date: Optional[str] = None) -> PositionsResponse
Get position data from subscribed analysts.
Parameters:
start_date(str): Filter by start date (YYYY-MM-DD format)end_date(str): Filter by end date (YYYY-MM-DD format)
Returns: PositionsResponse
get_ideas(status: Optional[str] = None, direction: Optional[str] = None) -> IdeasResponse
Get trade ideas from subscribed analysts.
Parameters:
status(str): Filter by status ("active", "closed")direction(str): Filter by direction ("long", "short")
Returns: IdeasResponse
get_csi_weights(index: str, date=None, start_date=None, end_date=None, days=None, page=None, page_size=None) -> list
Get CSI weights data filtered by index. index is required and must be one of
CSI1000, CSI2000, CSI300, CSI500. At most one of the date filters may be
applied: date (single day), start_date+end_date (range), or days (rolling
window). Auto-paginates unless page is given.
Returns: list of dicts, each representing a row from the csi_weights table.
get_csi_weights_dataframe(index: str, date=None, start_date=None, end_date=None, days=None, page=None, page_size=None) -> pandas.DataFrame
Same parameters as get_csi_weights. Returns a DataFrame. Requires the pandas extra (pip install agualphacn[pandas]).
Returns: pandas.DataFrame
get_revision_fy2(date=None, start_date=None, end_date=None, days=None, ticker=None, type=None, page=None, page_size=None) -> list
Get revision_fy2 data from the cn_af database. A date filter is required —
exactly one of date (single day), start_date+end_date (range), or days
(rolling window). Optional: ticker (e.g. "000009.SZ") and type
("eps"/"np"/"sales", no value = all types). Auto-paginates unless page is given.
Returns: list of dicts, each representing a row from the revision_fy2 table.
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
Same parameters as get_revision_fy2. A date filter is required. Requires the pandas extra (pip install agualphacn[pandas]).
Returns: pandas.DataFrame
get_adj_close(membership: str, date=None, start_date=None, end_date=None, page=None, page_size=None) -> list
Get adj_close data from the prices database. membership is required
(universe selector — see the table above); a date filter is required —
either date (single day) or start_date+end_date (inclusive range, either
bound optional). Auto-paginates unless page is given.
Returns: list of dicts, each representing a row from adj_close.
get_adj_close_dataframe(membership: str, date=None, start_date=None, end_date=None, page=None, page_size=None) -> pandas.DataFrame
Same parameters as get_adj_close. membership and a date filter are required. Requires the pandas extra (pip install agualphacn[pandas]).
Returns: pandas.DataFrame
get_p_cies(zone: str, page=None, page_size=None) -> list
Get p_cies data from the prices database. zone is required and must be
"hk" or "cn". Auto-paginates unless page is given.
Returns: list of dicts, each representing a row from p_cies.
get_p_cies_dataframe(zone: str, page=None, page_size=None) -> pandas.DataFrame
Same parameters as get_p_cies. zone is required. Requires the pandas extra (pip install agualphacn[pandas]).
get_sp_rolling_index(product=None, products=None, date=None, start_date=None, end_date=None, page=None, page_size=None) -> list
Get commodity rolling-index rows from the prices database. At least one
of product(s) or a date filter is required. date and start_date/end_date
are mutually exclusive.
product(single string) andproducts(list) are merged; you can pass either or both.- With no
product(s)and no date filter, the server returns400.
Returns: list of dicts, each representing a row from sp_rolling_index.
get_sp_rolling_index_dataframe(product=None, products=None, date=None, start_date=None, end_date=None, page=None, page_size=None) -> pandas.DataFrame
Same parameters as get_sp_rolling_index. Requires the pandas extra.
get_sp_rolling_index_products() -> list
Return all distinct product codes available in sp_rolling_index, sorted ascending.
Useful for discovering which values are valid for the product(s) parameter.
Returns: pandas.DataFrame
get_limit_evts(date=None, start_date=None, end_date=None, page=None, page_size=None) -> list
Get limit_evts rows (daily limit-up / limit-down events) from the prices
database. A date filter is required: either date (single day) or
start_date/end_date (inclusive range). date and start_date/end_date
are mutually exclusive.
Returns: list of dicts, each representing a row from limit_evts.
get_limit_evts_dataframe(date=None, start_date=None, end_date=None, page=None, page_size=None) -> pandas.DataFrame
Same parameters as get_limit_evts. Requires the pandas extra.
Response Models
PositionsResponse
success(bool): Request success statustotal(int): Total number of recordsdata(List[Position]): List of position objectserror(str, optional): Error message if failed
IdeasResponse
success(bool): Request success statustotal(int): Total number of recordsdata(List[Idea]): List of idea objectserror(str, optional): Error message if failed
Error Handling
from agualphacn import AGuAlphaClient
from agualphacn.exceptions import APIError, AuthenticationError, RateLimitError
try:
client = AGuAlphaClient(api_key="invalid-key")
positions = client.get_positions()
except AuthenticationError:
print("Invalid API key")
except RateLimitError as e:
print(f"Too many requests: {e}")
except APIError as e:
print(f"API error: {e}")
Rate Limiting
The data API limits each API key to 4 requests per second (sliding 1-second
window). When the limit is exceeded, the server returns HTTP 429 Too Many
Requests with a Retry-After header indicating how many seconds to wait. The
SDK surfaces this as a RateLimitError (subclass of APIError), so you can
catch it and back off:
import time
from agualphacn import AGuAlphaClient
from agualphacn.exceptions import RateLimitError
client = AGuAlphaClient(api_key="your-api-key")
while True:
try:
data = client.get_positions()
break
except RateLimitError as e:
time.sleep(1)
Pagination
The server caps each request at 2000 rows. By default, the SDK
auto-paginates — calling get_positions(), get_ideas(),
get_csi_weights(index=...), or get_revision_fy2(date=...) with no page
argument walks every page and returns the full result set in one call. Each
underlying page request counts against your rate limit (2 req/s standard, 10 req/s VIP; 429 responses are retried automatically), so large tables
cost multiple requests.
If you want a single page, pass page (1-indexed) and optionally page_size
(server caps at 2000):
# Fetch only the first 500 rows of revision_fy2 in the last 30 days
rows = client.get_revision_fy2(days=30, page=1, page_size=500)
When paginating manually, the response object exposes page, page_size,
total_pages, and has_more so you can loop pages yourself:
page = 1
all_rows = []
while True:
resp = client.get_positions(page=page, page_size=1000)
all_rows.extend(resp.data)
if not resp.has_more:
break
page += 1
Requirements
- Python 3.8+
- requests 2.28.0+
License
MIT License
Metadata
Release files for agualphacn 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| agualphacn-0.2.1.tar.gz | 24.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agualphacn-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 46.3 kB
Release files / agualphacn-0.2.1.tar.gz
| Download URL | agualphacn-0.2.1.tar.gz |
|---|---|
| Size | 24.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7e4cb2959e40d939c954f941f606bab702a3387dbb01c6a7fa031518f0985c5b
|
|
BLAKE2b-256 checksum How to use checksums |
0380fb76a08558ae5be5926a889e7ffd00e9cfefc40b6dbe4f5fc096ce374f6b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / agualphacn-0.2.1-py3-none-any.whl
| Download URL | agualphacn-0.2.1-py3-none-any.whl |
|---|---|
| Size | 22.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
25bb8595e6bebb15b828373f4cac6b7f2bf810e6054e6c35d6b23adbed1ca0aa
|
|
BLAKE2b-256 checksum How to use checksums |
e736d420a87e44017756800e95c685f61c79208ff10b7f6587edc61a11edbb6c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Security for agualphacn 0.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.