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 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,3 @@
1
+ include README.md
2
+ include LICENSE
3
+ recursive-include agualpha *.py
@@ -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,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,2 @@
1
+ [console_scripts]
2
+ agualpha = agualpha.cli:main
@@ -0,0 +1,12 @@
1
+ requests>=2.28.0
2
+
3
+ [async]
4
+ aiohttp>=3.8.0
5
+
6
+ [dev]
7
+ pytest>=7.0.0
8
+ black>=22.0.0
9
+ mypy>=0.950
10
+
11
+ [pandas]
12
+ pandas>=1.5.0
@@ -0,0 +1 @@
1
+ agualpha
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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
+ )