Metadata-Version: 2.4
Name: agualpha
Version: 1.3.3
Summary: Python client for AGuAlpha Investment Platform API
Home-page: https://github.com/agualpha/agualpha-python
Author: AGuAlpha
Author-email: contact@agualpha.com
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Office/Business :: Financial
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.28.0
Provides-Extra: async
Requires-Dist: aiohttp>=3.8.0; extra == "async"
Provides-Extra: pandas
Requires-Dist: pandas>=1.5.0; extra == "pandas"
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: black>=22.0.0; extra == "dev"
Requires-Dist: mypy>=0.950; extra == "dev"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: license-file
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# AGuAlpha Python Client

Official Python library for accessing AGuAlpha Investment Platform data.

## Installation

```bash
pip install agualpha
```

For async support:
```bash
pip install agualpha[async]
```

For pandas integration:
```bash
pip install agualpha[pandas]
```

## Quick Start

### Synchronous Usage

```python
from agualpha 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

```python
from agualpha 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

```python
import asyncio
from agualpha 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

```python
from agualpha import AGuAlphaClient
from agualpha.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 the full `csi_weights` table from the `prices` database. The data is returned
as a pandas DataFrame for easy analysis.

```python
from agualpha import AGuAlphaClient

with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
    df = client.get_csi_weights_dataframe()
    print(df.head())
    print(fShape: {df.shape})
```

If you don't need pandas, you can get the raw list of dicts instead:

```python
from agualpha import AGuAlphaClient

with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
    rows = client.get_csi_weights()
    print(f"Total records: {len(rows)}")
    for row in rows:
        print(row)
```

## API Reference

### AGuAlphaClient

#### `__init__(api_key: str, base_url: str = "http://www.agualpha.cn:8090/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() -> list`
Get all CSI weights data from the `prices` database (`csi_weights` table).

**Returns:** `list` of dicts, each representing a row from the `csi_weights` table.

#### `get_csi_weights_dataframe() -> pandas.DataFrame`
Convenience wrapper that returns the CSI weights data directly as a pandas DataFrame. Requires the `pandas` extra (`pip install agualpha[pandas]`).

**Returns:** `pandas.DataFrame`

#### `get_revision_fy2() -> list`
Get all revision_fy2 data from the `cn_af` database (`revision_fy2` table).

**Returns:** `list` of dicts, each representing a row from the `revision_fy2` table.

#### `get_revision_fy2_dataframe() -> pandas.DataFrame`
Convenience wrapper that returns the revision_fy2 data directly as a pandas DataFrame. Requires the `pandas` extra (`pip install agualpha[pandas]`).

**Returns:** `pandas.DataFrame`

### Response Models

#### `PositionsResponse`
- `success` (bool): Request success status
- `total` (int): Total number of records
- `data` (List[Position]): List of position objects
- `error` (str, optional): Error message if failed

#### `IdeasResponse`
- `success` (bool): Request success status
- `total` (int): Total number of records
- `data` (List[Idea]): List of idea objects
- `error` (str, optional): Error message if failed

## Error Handling

```python
from agualpha import AGuAlphaClient
from agualpha.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 **60 requests per minute** (sliding 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:

```python
import time
from agualpha import AGuAlphaClient
from agualpha.exceptions import RateLimitError

client = AGuAlphaClient(api_key="your-api-key")
while True:
    try:
        data = client.get_positions()
        break
    except RateLimitError as e:
        time.sleep(5)
```


## Requirements

- Python 3.8+
- requests 2.28.0+

## License

MIT License
