agualpha 1.0.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.
- agualpha-1.0.0/LICENSE +21 -0
- agualpha-1.0.0/MANIFEST.in +3 -0
- agualpha-1.0.0/PKG-INFO +198 -0
- agualpha-1.0.0/README.md +158 -0
- agualpha-1.0.0/agualpha/__init__.py +22 -0
- agualpha-1.0.0/agualpha/async_client.py +116 -0
- agualpha-1.0.0/agualpha/client.py +109 -0
- agualpha-1.0.0/agualpha/exceptions.py +28 -0
- agualpha-1.0.0/agualpha/models.py +118 -0
- agualpha-1.0.0/agualpha/utils.py +89 -0
- agualpha-1.0.0/agualpha.egg-info/PKG-INFO +198 -0
- agualpha-1.0.0/agualpha.egg-info/SOURCES.txt +16 -0
- agualpha-1.0.0/agualpha.egg-info/dependency_links.txt +1 -0
- agualpha-1.0.0/agualpha.egg-info/entry_points.txt +2 -0
- agualpha-1.0.0/agualpha.egg-info/requires.txt +12 -0
- agualpha-1.0.0/agualpha.egg-info/top_level.txt +1 -0
- agualpha-1.0.0/setup.cfg +4 -0
- agualpha-1.0.0/setup.py +45 -0
agualpha-1.0.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.
|
agualpha-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agualpha
|
|
3
|
+
Version: 1.0.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 agualpha
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For async support:
|
|
52
|
+
```bash
|
|
53
|
+
pip install agualpha[async]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
For pandas integration:
|
|
57
|
+
```bash
|
|
58
|
+
pip install agualpha[pandas]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
|
|
63
|
+
### Synchronous Usage
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from agualpha 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 agualpha 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 agualpha 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 agualpha import AGuAlphaClient
|
|
125
|
+
from agualpha.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
|
+
## API Reference
|
|
138
|
+
|
|
139
|
+
### AGuAlphaClient
|
|
140
|
+
|
|
141
|
+
#### `__init__(api_key: str, base_url: str = "https://api.agualpha.com/api")`
|
|
142
|
+
Initialize the client with your API key.
|
|
143
|
+
|
|
144
|
+
#### `get_positions(start_date: Optional[str] = None, end_date: Optional[str] = None) -> PositionsResponse`
|
|
145
|
+
Get position data from subscribed analysts.
|
|
146
|
+
|
|
147
|
+
**Parameters:**
|
|
148
|
+
- `start_date` (str): Filter by start date (YYYY-MM-DD format)
|
|
149
|
+
- `end_date` (str): Filter by end date (YYYY-MM-DD format)
|
|
150
|
+
|
|
151
|
+
**Returns:** `PositionsResponse`
|
|
152
|
+
|
|
153
|
+
#### `get_ideas(status: Optional[str] = None, direction: Optional[str] = None) -> IdeasResponse`
|
|
154
|
+
Get trade ideas from subscribed analysts.
|
|
155
|
+
|
|
156
|
+
**Parameters:**
|
|
157
|
+
- `status` (str): Filter by status ("active", "closed")
|
|
158
|
+
- `direction` (str): Filter by direction ("long", "short")
|
|
159
|
+
|
|
160
|
+
**Returns:** `IdeasResponse`
|
|
161
|
+
|
|
162
|
+
### Response Models
|
|
163
|
+
|
|
164
|
+
#### `PositionsResponse`
|
|
165
|
+
- `success` (bool): Request success status
|
|
166
|
+
- `total` (int): Total number of records
|
|
167
|
+
- `data` (List[Position]): List of position objects
|
|
168
|
+
- `error` (str, optional): Error message if failed
|
|
169
|
+
|
|
170
|
+
#### `IdeasResponse`
|
|
171
|
+
- `success` (bool): Request success status
|
|
172
|
+
- `total` (int): Total number of records
|
|
173
|
+
- `data` (List[Idea]): List of idea objects
|
|
174
|
+
- `error` (str, optional): Error message if failed
|
|
175
|
+
|
|
176
|
+
## Error Handling
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
from agualpha import AGuAlphaClient
|
|
180
|
+
from agualpha.exceptions import APIError, AuthenticationError
|
|
181
|
+
|
|
182
|
+
try:
|
|
183
|
+
client = AGuAlphaClient(api_key="invalid-key")
|
|
184
|
+
positions = client.get_positions()
|
|
185
|
+
except AuthenticationError:
|
|
186
|
+
print("Invalid API key")
|
|
187
|
+
except APIError as e:
|
|
188
|
+
print(f"API error: {e}")
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Requirements
|
|
192
|
+
|
|
193
|
+
- Python 3.8+
|
|
194
|
+
- requests 2.28.0+
|
|
195
|
+
|
|
196
|
+
## License
|
|
197
|
+
|
|
198
|
+
MIT License
|
agualpha-1.0.0/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# AGuAlpha Python Client
|
|
2
|
+
|
|
3
|
+
Official Python library for accessing AGuAlpha Investment Platform data.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install agualpha
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
For async support:
|
|
12
|
+
```bash
|
|
13
|
+
pip install agualpha[async]
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
For pandas integration:
|
|
17
|
+
```bash
|
|
18
|
+
pip install agualpha[pandas]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### Synchronous Usage
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from agualpha import AGuAlphaClient
|
|
27
|
+
|
|
28
|
+
# Initialize client
|
|
29
|
+
client = AGuAlphaClient(api_key="sk-your-api-key-here")
|
|
30
|
+
|
|
31
|
+
# Get positions data
|
|
32
|
+
positions = client.get_positions()
|
|
33
|
+
print(f"Total positions: {positions.total}")
|
|
34
|
+
|
|
35
|
+
for position in positions.data:
|
|
36
|
+
print(f"Date: {position.date}, Outstanding: {position.outstanding}")
|
|
37
|
+
|
|
38
|
+
# Get ideas data
|
|
39
|
+
ideas = client.get_ideas(status="active")
|
|
40
|
+
print(f"Total active ideas: {ideas.total}")
|
|
41
|
+
|
|
42
|
+
for idea in ideas.data:
|
|
43
|
+
print(f"Symbol: {idea.ticker_symbol}, Status: {idea.status}")
|
|
44
|
+
|
|
45
|
+
# Close the connection
|
|
46
|
+
client.close()
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Using Context Manager
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from agualpha import AGuAlphaClient
|
|
53
|
+
|
|
54
|
+
with AGuAlphaClient(api_key="sk-your-api-key-here") as client:
|
|
55
|
+
positions = client.get_positions(
|
|
56
|
+
start_date="2024-01-01",
|
|
57
|
+
end_date="2024-12-31"
|
|
58
|
+
)
|
|
59
|
+
print(f"Found {positions.total} positions")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Asynchronous Usage
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import asyncio
|
|
66
|
+
from agualpha import AGuAlphaAsyncClient
|
|
67
|
+
|
|
68
|
+
async def main():
|
|
69
|
+
async with AGuAlphaAsyncClient(api_key="sk-your-api-key-here") as client:
|
|
70
|
+
# Fetch data concurrently
|
|
71
|
+
positions, ideas = await asyncio.gather(
|
|
72
|
+
client.get_positions(),
|
|
73
|
+
client.get_ideas(status="active")
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
print(f"Positions: {positions.total}, Ideas: {ideas.total}")
|
|
77
|
+
|
|
78
|
+
asyncio.run(main())
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Pandas Integration
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from agualpha import AGuAlphaClient
|
|
85
|
+
from agualpha.utils import positions_to_dataframe, export_to_csv
|
|
86
|
+
|
|
87
|
+
client = AGuAlphaClient(api_key="sk-your-api-key-here")
|
|
88
|
+
|
|
89
|
+
# Get positions and convert to DataFrame
|
|
90
|
+
positions_response = client.get_positions()
|
|
91
|
+
df = positions_to_dataframe(positions_response.data)
|
|
92
|
+
|
|
93
|
+
# Export to CSV
|
|
94
|
+
export_to_csv(positions_response.data, "positions.csv")
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## API Reference
|
|
98
|
+
|
|
99
|
+
### AGuAlphaClient
|
|
100
|
+
|
|
101
|
+
#### `__init__(api_key: str, base_url: str = "https://api.agualpha.com/api")`
|
|
102
|
+
Initialize the client with your API key.
|
|
103
|
+
|
|
104
|
+
#### `get_positions(start_date: Optional[str] = None, end_date: Optional[str] = None) -> PositionsResponse`
|
|
105
|
+
Get position data from subscribed analysts.
|
|
106
|
+
|
|
107
|
+
**Parameters:**
|
|
108
|
+
- `start_date` (str): Filter by start date (YYYY-MM-DD format)
|
|
109
|
+
- `end_date` (str): Filter by end date (YYYY-MM-DD format)
|
|
110
|
+
|
|
111
|
+
**Returns:** `PositionsResponse`
|
|
112
|
+
|
|
113
|
+
#### `get_ideas(status: Optional[str] = None, direction: Optional[str] = None) -> IdeasResponse`
|
|
114
|
+
Get trade ideas from subscribed analysts.
|
|
115
|
+
|
|
116
|
+
**Parameters:**
|
|
117
|
+
- `status` (str): Filter by status ("active", "closed")
|
|
118
|
+
- `direction` (str): Filter by direction ("long", "short")
|
|
119
|
+
|
|
120
|
+
**Returns:** `IdeasResponse`
|
|
121
|
+
|
|
122
|
+
### Response Models
|
|
123
|
+
|
|
124
|
+
#### `PositionsResponse`
|
|
125
|
+
- `success` (bool): Request success status
|
|
126
|
+
- `total` (int): Total number of records
|
|
127
|
+
- `data` (List[Position]): List of position objects
|
|
128
|
+
- `error` (str, optional): Error message if failed
|
|
129
|
+
|
|
130
|
+
#### `IdeasResponse`
|
|
131
|
+
- `success` (bool): Request success status
|
|
132
|
+
- `total` (int): Total number of records
|
|
133
|
+
- `data` (List[Idea]): List of idea objects
|
|
134
|
+
- `error` (str, optional): Error message if failed
|
|
135
|
+
|
|
136
|
+
## Error Handling
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from agualpha import AGuAlphaClient
|
|
140
|
+
from agualpha.exceptions import APIError, AuthenticationError
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
client = AGuAlphaClient(api_key="invalid-key")
|
|
144
|
+
positions = client.get_positions()
|
|
145
|
+
except AuthenticationError:
|
|
146
|
+
print("Invalid API key")
|
|
147
|
+
except APIError as e:
|
|
148
|
+
print(f"API error: {e}")
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Requirements
|
|
152
|
+
|
|
153
|
+
- Python 3.8+
|
|
154
|
+
- requests 2.28.0+
|
|
155
|
+
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
MIT License
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AGuAlpha API Client Library
|
|
3
|
+
A Python library for accessing AGuAlpha investment platform data
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .client import AGuAlphaClient
|
|
7
|
+
from .async_client import AGuAlphaAsyncClient
|
|
8
|
+
from .models import PositionsResponse, IdeasResponse, Position, Idea
|
|
9
|
+
from .exceptions import APIError, AuthenticationError, RateLimitError
|
|
10
|
+
|
|
11
|
+
__version__ = "1.0.0"
|
|
12
|
+
__all__ = [
|
|
13
|
+
"AGuAlphaClient",
|
|
14
|
+
"AGuAlphaAsyncClient",
|
|
15
|
+
"PositionsResponse",
|
|
16
|
+
"IdeasResponse",
|
|
17
|
+
"Position",
|
|
18
|
+
"Idea",
|
|
19
|
+
"APIError",
|
|
20
|
+
"AuthenticationError",
|
|
21
|
+
"RateLimitError",
|
|
22
|
+
]
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Asynchronous API client for AGuAlpha
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import aiohttp
|
|
6
|
+
from typing import Optional
|
|
7
|
+
from .models import PositionsResponse, IdeasResponse
|
|
8
|
+
from .exceptions import APIError, AuthenticationError, ServerError
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AGuAlphaAsyncClient:
|
|
12
|
+
"""Asynchronous client for AGuAlpha API"""
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
api_key: str,
|
|
17
|
+
base_url: str = "https://api.agualpha.com/api"
|
|
18
|
+
):
|
|
19
|
+
"""
|
|
20
|
+
Initialize the AGuAlpha async client
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
api_key: Your API key
|
|
24
|
+
base_url: Base URL for the API (default: https://api.agualpha.com/api)
|
|
25
|
+
"""
|
|
26
|
+
self.api_key = api_key
|
|
27
|
+
self.base_url = base_url.rstrip("/")
|
|
28
|
+
self._session = None
|
|
29
|
+
|
|
30
|
+
async def __aenter__(self):
|
|
31
|
+
"""Async context manager entry"""
|
|
32
|
+
self._session = aiohttp.ClientSession(
|
|
33
|
+
headers={"X-API-Key": self.api_key}
|
|
34
|
+
)
|
|
35
|
+
return self
|
|
36
|
+
|
|
37
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
38
|
+
"""Async context manager exit"""
|
|
39
|
+
if self._session:
|
|
40
|
+
await self._session.close()
|
|
41
|
+
|
|
42
|
+
async def get_positions(
|
|
43
|
+
self,
|
|
44
|
+
start_date: Optional[str] = None,
|
|
45
|
+
end_date: Optional[str] = None
|
|
46
|
+
) -> PositionsResponse:
|
|
47
|
+
"""
|
|
48
|
+
Get position data from subscribed analysts
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
start_date: Filter by start date (YYYY-MM-DD format)
|
|
52
|
+
end_date: Filter by end date (YYYY-MM-DD format)
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
PositionsResponse: Response containing position data
|
|
56
|
+
"""
|
|
57
|
+
if not self._session:
|
|
58
|
+
raise RuntimeError("Client not initialized. Use 'async with' or call _ensure_session()")
|
|
59
|
+
|
|
60
|
+
url = f"{self.base_url}/investor/data/positions"
|
|
61
|
+
params = {}
|
|
62
|
+
if start_date:
|
|
63
|
+
params["startDate"] = start_date
|
|
64
|
+
if end_date:
|
|
65
|
+
params["endDate"] = end_date
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
async with self._session.get(url, params=params) as response:
|
|
69
|
+
if response.status == 401:
|
|
70
|
+
raise AuthenticationError("Invalid API key")
|
|
71
|
+
response.raise_for_status()
|
|
72
|
+
data = await response.json()
|
|
73
|
+
return PositionsResponse.from_dict(data)
|
|
74
|
+
except aiohttp.ClientError as e:
|
|
75
|
+
raise APIError(f"Request failed: {e}")
|
|
76
|
+
|
|
77
|
+
async def get_ideas(
|
|
78
|
+
self,
|
|
79
|
+
status: Optional[str] = None,
|
|
80
|
+
direction: Optional[str] = None
|
|
81
|
+
) -> IdeasResponse:
|
|
82
|
+
"""
|
|
83
|
+
Get trade ideas from subscribed analysts
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
status: Filter by status (active, closed)
|
|
87
|
+
direction: Filter by direction (long, short)
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
IdeasResponse: Response containing trade ideas data
|
|
91
|
+
"""
|
|
92
|
+
if not self._session:
|
|
93
|
+
raise RuntimeError("Client not initialized. Use 'async with' or call _ensure_session()")
|
|
94
|
+
|
|
95
|
+
url = f"{self.base_url}/investor/data/ideas"
|
|
96
|
+
params = {}
|
|
97
|
+
if status:
|
|
98
|
+
params["status"] = status
|
|
99
|
+
if direction:
|
|
100
|
+
params["direction"] = direction
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
async with self._session.get(url, params=params) as response:
|
|
104
|
+
if response.status == 401:
|
|
105
|
+
raise AuthenticationError("Invalid API key")
|
|
106
|
+
response.raise_for_status()
|
|
107
|
+
data = await response.json()
|
|
108
|
+
return IdeasResponse.from_dict(data)
|
|
109
|
+
except aiohttp.ClientError as e:
|
|
110
|
+
raise APIError(f"Request failed: {e}")
|
|
111
|
+
|
|
112
|
+
async def close(self):
|
|
113
|
+
"""Close the session"""
|
|
114
|
+
if self._session:
|
|
115
|
+
await self._session.close()
|
|
116
|
+
self._session = None
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Synchronous API client for AGuAlpha
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
from typing import Optional
|
|
7
|
+
from .models import PositionsResponse, IdeasResponse
|
|
8
|
+
from .exceptions import APIError, AuthenticationError, ServerError
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AGuAlphaClient:
|
|
12
|
+
"""Synchronous client for AGuAlpha API"""
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
api_key: str,
|
|
17
|
+
base_url: str = "https://api.agualpha.com/api"
|
|
18
|
+
):
|
|
19
|
+
"""
|
|
20
|
+
Initialize the AGuAlpha client
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
api_key: Your API key
|
|
24
|
+
base_url: Base URL for the API (default: https://api.agualpha.com/api)
|
|
25
|
+
"""
|
|
26
|
+
self.api_key = api_key
|
|
27
|
+
self.base_url = base_url.rstrip("/")
|
|
28
|
+
self.session = requests.Session()
|
|
29
|
+
self.session.headers.update({"X-API-Key": api_key})
|
|
30
|
+
|
|
31
|
+
def get_positions(
|
|
32
|
+
self,
|
|
33
|
+
start_date: Optional[str] = None,
|
|
34
|
+
end_date: Optional[str] = None
|
|
35
|
+
) -> PositionsResponse:
|
|
36
|
+
"""
|
|
37
|
+
Get position data from subscribed analysts
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
start_date: Filter by start date (YYYY-MM-DD format)
|
|
41
|
+
end_date: Filter by end date (YYYY-MM-DD format)
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
PositionsResponse: Response containing position data
|
|
45
|
+
"""
|
|
46
|
+
url = f"{self.base_url}/investor/data/positions"
|
|
47
|
+
params = {}
|
|
48
|
+
if start_date:
|
|
49
|
+
params["startDate"] = start_date
|
|
50
|
+
if end_date:
|
|
51
|
+
params["endDate"] = end_date
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
response = self.session.get(url, params=params)
|
|
55
|
+
response.raise_for_status()
|
|
56
|
+
data = response.json()
|
|
57
|
+
return PositionsResponse.from_dict(data)
|
|
58
|
+
except requests.HTTPError as e:
|
|
59
|
+
if e.response.status_code == 401:
|
|
60
|
+
raise AuthenticationError("Invalid API key")
|
|
61
|
+
raise ServerError(f"Server error: {e}")
|
|
62
|
+
except requests.RequestException as e:
|
|
63
|
+
raise APIError(f"Request failed: {e}")
|
|
64
|
+
|
|
65
|
+
def get_ideas(
|
|
66
|
+
self,
|
|
67
|
+
status: Optional[str] = None,
|
|
68
|
+
direction: Optional[str] = None
|
|
69
|
+
) -> IdeasResponse:
|
|
70
|
+
"""
|
|
71
|
+
Get trade ideas from subscribed analysts
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
status: Filter by status (active, closed)
|
|
75
|
+
direction: Filter by direction (long, short)
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
IdeasResponse: Response containing trade ideas data
|
|
79
|
+
"""
|
|
80
|
+
url = f"{self.base_url}/investor/data/ideas"
|
|
81
|
+
params = {}
|
|
82
|
+
if status:
|
|
83
|
+
params["status"] = status
|
|
84
|
+
if direction:
|
|
85
|
+
params["direction"] = direction
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
response = self.session.get(url, params=params)
|
|
89
|
+
response.raise_for_status()
|
|
90
|
+
data = response.json()
|
|
91
|
+
return IdeasResponse.from_dict(data)
|
|
92
|
+
except requests.HTTPError as e:
|
|
93
|
+
if e.response.status_code == 401:
|
|
94
|
+
raise AuthenticationError("Invalid API key")
|
|
95
|
+
raise ServerError(f"Server error: {e}")
|
|
96
|
+
except requests.RequestException as e:
|
|
97
|
+
raise APIError(f"Request failed: {e}")
|
|
98
|
+
|
|
99
|
+
def close(self):
|
|
100
|
+
"""Close the session"""
|
|
101
|
+
self.session.close()
|
|
102
|
+
|
|
103
|
+
def __enter__(self):
|
|
104
|
+
"""Context manager entry"""
|
|
105
|
+
return self
|
|
106
|
+
|
|
107
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
108
|
+
"""Context manager exit"""
|
|
109
|
+
self.close()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Custom exceptions for AGuAlpha API client
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class APIError(Exception):
|
|
7
|
+
"""Base exception for API errors"""
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AuthenticationError(APIError):
|
|
12
|
+
"""Raised when API key authentication fails"""
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RateLimitError(APIError):
|
|
17
|
+
"""Raised when API rate limit is exceeded"""
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class InvalidRequestError(APIError):
|
|
22
|
+
"""Raised when request parameters are invalid"""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ServerError(APIError):
|
|
27
|
+
"""Raised when server returns an error"""
|
|
28
|
+
pass
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Data models for AGuAlpha API responses
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import List, Any, Optional
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class Position:
|
|
11
|
+
"""Position data model"""
|
|
12
|
+
date: str
|
|
13
|
+
time: str
|
|
14
|
+
price: Optional[float]
|
|
15
|
+
buy_sell: Optional[int]
|
|
16
|
+
outstanding: Optional[int]
|
|
17
|
+
value: Optional[float]
|
|
18
|
+
af_backward: Optional[float]
|
|
19
|
+
money_flow: Optional[float]
|
|
20
|
+
operation_type: Optional[str]
|
|
21
|
+
execution_status: Optional[str]
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def from_dict(cls, data: dict) -> "Position":
|
|
25
|
+
return cls(
|
|
26
|
+
date=data.get("date", ""),
|
|
27
|
+
time=data.get("time", ""),
|
|
28
|
+
price=data.get("price"),
|
|
29
|
+
buy_sell=data.get("buy_sell"),
|
|
30
|
+
outstanding=data.get("outstanding"),
|
|
31
|
+
value=data.get("value"),
|
|
32
|
+
af_backward=data.get("af_backward"),
|
|
33
|
+
money_flow=data.get("money_flow"),
|
|
34
|
+
operation_type=data.get("operation_type"),
|
|
35
|
+
execution_status=data.get("execution_status"),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class Idea:
|
|
41
|
+
"""Trade idea data model"""
|
|
42
|
+
ticker_symbol: str
|
|
43
|
+
company_name: str
|
|
44
|
+
direction: str
|
|
45
|
+
hedge_instrument: Optional[str]
|
|
46
|
+
target_amount: Optional[float]
|
|
47
|
+
calculated_shares: Optional[int]
|
|
48
|
+
actual_cost: Optional[float]
|
|
49
|
+
target_price: Optional[float]
|
|
50
|
+
stop_loss_price: Optional[float]
|
|
51
|
+
thesis: Optional[str]
|
|
52
|
+
catalysts: Optional[str]
|
|
53
|
+
status: str
|
|
54
|
+
position_open_date: Optional[str]
|
|
55
|
+
position_close_date: Optional[str]
|
|
56
|
+
close_price: Optional[float]
|
|
57
|
+
close_reason: Optional[str]
|
|
58
|
+
idea_created_at: Optional[str]
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def from_dict(cls, data: dict) -> "Idea":
|
|
62
|
+
return cls(
|
|
63
|
+
ticker_symbol=data.get("ticker_symbol", ""),
|
|
64
|
+
company_name=data.get("company_name", ""),
|
|
65
|
+
direction=data.get("direction", ""),
|
|
66
|
+
hedge_instrument=data.get("hedge_instrument"),
|
|
67
|
+
target_amount=data.get("target_amount"),
|
|
68
|
+
calculated_shares=data.get("calculated_shares"),
|
|
69
|
+
actual_cost=data.get("actual_cost"),
|
|
70
|
+
target_price=data.get("target_price"),
|
|
71
|
+
stop_loss_price=data.get("stop_loss_price"),
|
|
72
|
+
thesis=data.get("thesis"),
|
|
73
|
+
catalysts=data.get("catalysts"),
|
|
74
|
+
status=data.get("status", ""),
|
|
75
|
+
position_open_date=data.get("position_open_date"),
|
|
76
|
+
position_close_date=data.get("position_close_date"),
|
|
77
|
+
close_price=data.get("close_price"),
|
|
78
|
+
close_reason=data.get("close_reason"),
|
|
79
|
+
idea_created_at=data.get("idea_created_at"),
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@dataclass
|
|
84
|
+
class PositionsResponse:
|
|
85
|
+
"""Response model for positions endpoint"""
|
|
86
|
+
success: bool
|
|
87
|
+
total: int
|
|
88
|
+
data: List[Position]
|
|
89
|
+
error: Optional[str] = None
|
|
90
|
+
|
|
91
|
+
@classmethod
|
|
92
|
+
def from_dict(cls, data: dict) -> "PositionsResponse":
|
|
93
|
+
positions = [Position.from_dict(item) for item in data.get("data", [])]
|
|
94
|
+
return cls(
|
|
95
|
+
success=data.get("success", False),
|
|
96
|
+
total=data.get("total", 0),
|
|
97
|
+
data=positions,
|
|
98
|
+
error=data.get("error"),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@dataclass
|
|
103
|
+
class IdeasResponse:
|
|
104
|
+
"""Response model for ideas endpoint"""
|
|
105
|
+
success: bool
|
|
106
|
+
total: int
|
|
107
|
+
data: List[Idea]
|
|
108
|
+
error: Optional[str] = None
|
|
109
|
+
|
|
110
|
+
@classmethod
|
|
111
|
+
def from_dict(cls, data: dict) -> "IdeasResponse":
|
|
112
|
+
ideas = [Idea.from_dict(item) for item in data.get("data", [])]
|
|
113
|
+
return cls(
|
|
114
|
+
success=data.get("success", False),
|
|
115
|
+
total=data.get("total", 0),
|
|
116
|
+
data=ideas,
|
|
117
|
+
error=data.get("error"),
|
|
118
|
+
)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utility functions for AGuAlpha library
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
from typing import List, Union
|
|
7
|
+
from .models import Position, Idea
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def positions_to_dataframe(positions: List[Position]) -> pd.DataFrame:
|
|
11
|
+
"""
|
|
12
|
+
Convert list of Position objects to pandas DataFrame
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
positions: List of Position objects
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
pd.DataFrame: DataFrame containing position data
|
|
19
|
+
"""
|
|
20
|
+
data = [
|
|
21
|
+
{
|
|
22
|
+
"date": p.date,
|
|
23
|
+
"time": p.time,
|
|
24
|
+
"price": p.price,
|
|
25
|
+
"buy_sell": p.buy_sell,
|
|
26
|
+
"outstanding": p.outstanding,
|
|
27
|
+
"value": p.value,
|
|
28
|
+
"af_backward": p.af_backward,
|
|
29
|
+
"money_flow": p.money_flow,
|
|
30
|
+
"operation_type": p.operation_type,
|
|
31
|
+
"execution_status": p.execution_status,
|
|
32
|
+
}
|
|
33
|
+
for p in positions
|
|
34
|
+
]
|
|
35
|
+
return pd.DataFrame(data)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def ideas_to_dataframe(ideas: List[Idea]) -> pd.DataFrame:
|
|
39
|
+
"""
|
|
40
|
+
Convert list of Idea objects to pandas DataFrame
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
ideas: List of Idea objects
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
pd.DataFrame: DataFrame containing idea data
|
|
47
|
+
"""
|
|
48
|
+
data = [
|
|
49
|
+
{
|
|
50
|
+
"ticker_symbol": i.ticker_symbol,
|
|
51
|
+
"company_name": i.company_name,
|
|
52
|
+
"direction": i.direction,
|
|
53
|
+
"hedge_instrument": i.hedge_instrument,
|
|
54
|
+
"target_amount": i.target_amount,
|
|
55
|
+
"calculated_shares": i.calculated_shares,
|
|
56
|
+
"actual_cost": i.actual_cost,
|
|
57
|
+
"target_price": i.target_price,
|
|
58
|
+
"stop_loss_price": i.stop_loss_price,
|
|
59
|
+
"thesis": i.thesis,
|
|
60
|
+
"catalysts": i.catalysts,
|
|
61
|
+
"status": i.status,
|
|
62
|
+
"position_open_date": i.position_open_date,
|
|
63
|
+
"position_close_date": i.position_close_date,
|
|
64
|
+
"close_price": i.close_price,
|
|
65
|
+
"close_reason": i.close_reason,
|
|
66
|
+
"idea_created_at": i.idea_created_at,
|
|
67
|
+
}
|
|
68
|
+
for i in ideas
|
|
69
|
+
]
|
|
70
|
+
return pd.DataFrame(data)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def export_to_csv(data: Union[List[Position], List[Idea]], filename: str):
|
|
74
|
+
"""
|
|
75
|
+
Export data to CSV file
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
data: List of Position or Idea objects
|
|
79
|
+
filename: Output CSV filename
|
|
80
|
+
"""
|
|
81
|
+
if isinstance(data[0], Position):
|
|
82
|
+
df = positions_to_dataframe(data)
|
|
83
|
+
elif isinstance(data[0], Idea):
|
|
84
|
+
df = ideas_to_dataframe(data)
|
|
85
|
+
else:
|
|
86
|
+
raise ValueError("Data must be list of Position or Idea objects")
|
|
87
|
+
|
|
88
|
+
df.to_csv(filename, index=False)
|
|
89
|
+
print(f"Data exported to {filename}")
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agualpha
|
|
3
|
+
Version: 1.0.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 agualpha
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For async support:
|
|
52
|
+
```bash
|
|
53
|
+
pip install agualpha[async]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
For pandas integration:
|
|
57
|
+
```bash
|
|
58
|
+
pip install agualpha[pandas]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
|
|
63
|
+
### Synchronous Usage
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from agualpha 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 agualpha 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 agualpha 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 agualpha import AGuAlphaClient
|
|
125
|
+
from agualpha.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
|
+
## API Reference
|
|
138
|
+
|
|
139
|
+
### AGuAlphaClient
|
|
140
|
+
|
|
141
|
+
#### `__init__(api_key: str, base_url: str = "https://api.agualpha.com/api")`
|
|
142
|
+
Initialize the client with your API key.
|
|
143
|
+
|
|
144
|
+
#### `get_positions(start_date: Optional[str] = None, end_date: Optional[str] = None) -> PositionsResponse`
|
|
145
|
+
Get position data from subscribed analysts.
|
|
146
|
+
|
|
147
|
+
**Parameters:**
|
|
148
|
+
- `start_date` (str): Filter by start date (YYYY-MM-DD format)
|
|
149
|
+
- `end_date` (str): Filter by end date (YYYY-MM-DD format)
|
|
150
|
+
|
|
151
|
+
**Returns:** `PositionsResponse`
|
|
152
|
+
|
|
153
|
+
#### `get_ideas(status: Optional[str] = None, direction: Optional[str] = None) -> IdeasResponse`
|
|
154
|
+
Get trade ideas from subscribed analysts.
|
|
155
|
+
|
|
156
|
+
**Parameters:**
|
|
157
|
+
- `status` (str): Filter by status ("active", "closed")
|
|
158
|
+
- `direction` (str): Filter by direction ("long", "short")
|
|
159
|
+
|
|
160
|
+
**Returns:** `IdeasResponse`
|
|
161
|
+
|
|
162
|
+
### Response Models
|
|
163
|
+
|
|
164
|
+
#### `PositionsResponse`
|
|
165
|
+
- `success` (bool): Request success status
|
|
166
|
+
- `total` (int): Total number of records
|
|
167
|
+
- `data` (List[Position]): List of position objects
|
|
168
|
+
- `error` (str, optional): Error message if failed
|
|
169
|
+
|
|
170
|
+
#### `IdeasResponse`
|
|
171
|
+
- `success` (bool): Request success status
|
|
172
|
+
- `total` (int): Total number of records
|
|
173
|
+
- `data` (List[Idea]): List of idea objects
|
|
174
|
+
- `error` (str, optional): Error message if failed
|
|
175
|
+
|
|
176
|
+
## Error Handling
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
from agualpha import AGuAlphaClient
|
|
180
|
+
from agualpha.exceptions import APIError, AuthenticationError
|
|
181
|
+
|
|
182
|
+
try:
|
|
183
|
+
client = AGuAlphaClient(api_key="invalid-key")
|
|
184
|
+
positions = client.get_positions()
|
|
185
|
+
except AuthenticationError:
|
|
186
|
+
print("Invalid API key")
|
|
187
|
+
except APIError as e:
|
|
188
|
+
print(f"API error: {e}")
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Requirements
|
|
192
|
+
|
|
193
|
+
- Python 3.8+
|
|
194
|
+
- requests 2.28.0+
|
|
195
|
+
|
|
196
|
+
## License
|
|
197
|
+
|
|
198
|
+
MIT License
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
setup.py
|
|
5
|
+
agualpha/__init__.py
|
|
6
|
+
agualpha/async_client.py
|
|
7
|
+
agualpha/client.py
|
|
8
|
+
agualpha/exceptions.py
|
|
9
|
+
agualpha/models.py
|
|
10
|
+
agualpha/utils.py
|
|
11
|
+
agualpha.egg-info/PKG-INFO
|
|
12
|
+
agualpha.egg-info/SOURCES.txt
|
|
13
|
+
agualpha.egg-info/dependency_links.txt
|
|
14
|
+
agualpha.egg-info/entry_points.txt
|
|
15
|
+
agualpha.egg-info/requires.txt
|
|
16
|
+
agualpha.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
agualpha
|
agualpha-1.0.0/setup.cfg
ADDED
agualpha-1.0.0/setup.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Setup configuration for agualpha package
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from setuptools import setup, find_packages
|
|
6
|
+
|
|
7
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
8
|
+
long_description = fh.read()
|
|
9
|
+
|
|
10
|
+
setup(
|
|
11
|
+
name="agualpha",
|
|
12
|
+
version="1.0.0",
|
|
13
|
+
author="AGuAlpha",
|
|
14
|
+
author_email="contact@agualpha.com",
|
|
15
|
+
description="Python client for AGuAlpha Investment Platform API",
|
|
16
|
+
long_description=long_description,
|
|
17
|
+
long_description_content_type="text/markdown",
|
|
18
|
+
url="https://github.com/agualpha/agualpha-python",
|
|
19
|
+
packages=find_packages(),
|
|
20
|
+
classifiers=[
|
|
21
|
+
"Development Status :: 4 - Beta",
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"Topic :: Office/Business :: Financial",
|
|
24
|
+
"License :: OSI Approved :: MIT License",
|
|
25
|
+
"Programming Language :: Python :: 3",
|
|
26
|
+
"Programming Language :: Python :: 3.8",
|
|
27
|
+
"Programming Language :: Python :: 3.9",
|
|
28
|
+
"Programming Language :: Python :: 3.10",
|
|
29
|
+
"Programming Language :: Python :: 3.11",
|
|
30
|
+
],
|
|
31
|
+
python_requires=">=3.8",
|
|
32
|
+
install_requires=[
|
|
33
|
+
"requests>=2.28.0",
|
|
34
|
+
],
|
|
35
|
+
extras_require={
|
|
36
|
+
"async": ["aiohttp>=3.8.0"],
|
|
37
|
+
"pandas": ["pandas>=1.5.0"],
|
|
38
|
+
"dev": ["pytest>=7.0.0", "black>=22.0.0", "mypy>=0.950"],
|
|
39
|
+
},
|
|
40
|
+
entry_points={
|
|
41
|
+
"console_scripts": [
|
|
42
|
+
"agualpha=agualpha.cli:main",
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
)
|