finatic-server-python 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,62 @@
1
+ """Custom exception classes for the Finatic Server SDK."""
2
+
3
+ from typing import Any, Dict, Optional
4
+
5
+
6
+ class FinaticError(Exception):
7
+ """Base exception for all Finatic SDK errors."""
8
+
9
+ def __init__(self, message: str, code: Optional[str] = None):
10
+ self.message = message
11
+ self.code = code or "UNKNOWN_ERROR"
12
+ super().__init__(self.message)
13
+
14
+
15
+ class ApiError(FinaticError):
16
+ """Raised when an API request fails."""
17
+
18
+ def __init__(
19
+ self,
20
+ message: str,
21
+ status_code: Optional[int] = None,
22
+ response_data: Optional[Dict[str, Any]] = None
23
+ ):
24
+ self.status_code = status_code
25
+ self.response_data = response_data or {}
26
+ super().__init__(message, f"API_ERROR_{status_code}" if status_code else "API_ERROR")
27
+
28
+
29
+ class AuthenticationError(FinaticError):
30
+ """Raised when authentication fails."""
31
+ pass
32
+
33
+ class AuthorizationError(FinaticError):
34
+ """Raised when access is denied due to insufficient permissions."""
35
+ pass
36
+
37
+ class ValidationError(FinaticError):
38
+ """Raised when request validation fails."""
39
+ pass
40
+
41
+
42
+ class RateLimitError(ApiError):
43
+ """Raised when rate limits are exceeded."""
44
+
45
+ def __init__(self, message: str, retry_after: Optional[int] = None):
46
+ self.retry_after = retry_after
47
+ super().__init__(message, 429)
48
+ self.code = "RATE_LIMIT_ERROR"
49
+
50
+
51
+ class NetworkError(FinaticError):
52
+ """Raised when network connectivity issues occur."""
53
+
54
+ def __init__(self, message: str):
55
+ super().__init__(message, "NETWORK_ERROR")
56
+
57
+
58
+ class TimeoutError(FinaticError):
59
+ """Raised when requests timeout."""
60
+
61
+ def __init__(self, message: str):
62
+ super().__init__(message, "TIMEOUT_ERROR")
@@ -0,0 +1,330 @@
1
+ Metadata-Version: 2.4
2
+ Name: finatic-server-python
3
+ Version: 0.1.0
4
+ Summary: Python SDK for Finatic Server API
5
+ Author-email: Finatic <support@finatic.dev>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/finatic/finatic-server-python
8
+ Project-URL: Documentation, https://docs.finatic.com/python
9
+ Project-URL: Repository, https://github.com/finatic/finatic-server-python
10
+ Project-URL: Issues, https://github.com/finatic/finatic-server-python/issues
11
+ Keywords: finatic,trading,finance,api,sdk
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Office/Business :: Financial
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+ Requires-Dist: requests>=2.28.0
26
+ Requires-Dist: aiohttp>=3.8.0
27
+ Requires-Dist: pydantic>=2.0.0
28
+ Requires-Dist: typing-extensions>=4.0.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
31
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
32
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
33
+ Requires-Dist: black>=23.0.0; extra == "dev"
34
+ Requires-Dist: isort>=5.12.0; extra == "dev"
35
+ Requires-Dist: flake8>=6.0.0; extra == "dev"
36
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
37
+ Requires-Dist: pre-commit>=3.0.0; extra == "dev"
38
+
39
+ # Finatic Server Python SDK
40
+
41
+ A Python SDK for integrating with Finatic's server-side trading and portfolio management APIs.
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install finatic-server-python
47
+ ```
48
+
49
+ ## Quick Start
50
+
51
+ ```python
52
+ import asyncio
53
+ from finatic_server import FinaticServerClient
54
+
55
+ async def main():
56
+ # Initialize with API key
57
+ client = FinaticServerClient("your-api-key")
58
+
59
+ # Option 1: Portal Authentication
60
+ await client.start_session()
61
+ portal_url = await client.get_portal_url()
62
+ print(f"User should visit: {portal_url}")
63
+
64
+ # After user completes authentication in portal, get user info
65
+ user_info = await client.get_session_user()
66
+ print(f"Authenticated user: {user_info['user_id']}")
67
+
68
+ # Option 2: Direct Authentication (if you know the user ID)
69
+ # client = FinaticServerClient("your-api-key", user_id="user123")
70
+ # await client.start_session()
71
+
72
+ # Now you can access broker data
73
+ brokers = await client.get_broker_list()
74
+ print(f"Available brokers: {len(brokers)}")
75
+
76
+ # Get all orders across all pages
77
+ all_orders = await client.get_all_broker_orders()
78
+ print(f"Total orders: {len(all_orders)}")
79
+
80
+ # Run the example
81
+ asyncio.run(main())
82
+ ```
83
+
84
+ ## Authentication Flow
85
+
86
+ The SDK supports two authentication methods:
87
+
88
+ ### 1. Portal Authentication (User completes auth in browser)
89
+
90
+ ```python
91
+ client = FinaticServerClient("your-api-key")
92
+
93
+ # Start session
94
+ await client.start_session()
95
+
96
+ # Get portal URL for user authentication
97
+ portal_url = await client.get_portal_url()
98
+ print(f"User should visit: {portal_url}")
99
+
100
+ # After user completes authentication in portal
101
+ user_info = await client.get_session_user()
102
+ print(f"User ID: {user_info['user_id']}")
103
+ print(f"Access Token: {user_info['access_token']}")
104
+
105
+ # Now you can make authenticated requests
106
+ brokers = await client.get_broker_list()
107
+ ```
108
+
109
+ ### 2. Direct Authentication (Server-side with known user ID)
110
+
111
+ ```python
112
+ client = FinaticServerClient("your-api-key", user_id="user123")
113
+
114
+ # Start session (automatically authenticates with user ID)
115
+ await client.start_session()
116
+
117
+ # Now you can make authenticated requests immediately
118
+ brokers = await client.get_broker_list()
119
+ ```
120
+
121
+ ## Core Features
122
+
123
+ - **API Key Authentication**: Secure server-side authentication
124
+ - **Portal Integration**: Get portal URLs for user authentication
125
+ - **Automatic Token Management**: Handles access/refresh tokens automatically
126
+ - **Pagination Support**: Built-in pagination for large datasets
127
+ - **Type-safe API**: Full Pydantic model support
128
+ - **Async/await Support**: Non-blocking operations
129
+ - **Comprehensive Error Handling**: Detailed error types
130
+
131
+ ## API Reference
132
+
133
+ ### Initialization
134
+
135
+ ```python
136
+ client = FinaticServerClient(
137
+ api_key="your-api-key",
138
+ user_id="user123", # Optional - for direct authentication
139
+ )
140
+ ```
141
+
142
+ ### Authentication Methods
143
+
144
+ - `start_session()` - Start a new session (authenticates directly if user_id provided)
145
+ - `get_portal_url()` - Get portal URL for user authentication (portal flow only)
146
+ - `get_session_user()` - Get user info and tokens after portal completion (portal flow only)
147
+
148
+ ### Broker Data Methods
149
+
150
+ #### Basic Methods (with pagination support)
151
+ - `get_broker_list()` - Get list of available brokers
152
+ - `get_broker_connections()` - Get broker connections
153
+ - `get_broker_accounts(page=1, per_page=100, options=None, filters=None)` - Get broker accounts
154
+ - `get_broker_orders(page=1, per_page=100, options=None, filters=None)` - Get broker orders
155
+ - `get_broker_positions(page=1, per_page=100, options=None, filters=None)` - Get broker positions
156
+
157
+ #### Get All Methods (automatically handles pagination)
158
+ - `get_all_broker_accounts(options=None, filters=None)` - Get all broker accounts across all pages
159
+ - `get_all_broker_orders(options=None, filters=None)` - Get all broker orders across all pages
160
+ - `get_all_broker_positions(options=None, filters=None)` - Get all broker positions across all pages
161
+
162
+ ### Filter Options
163
+
164
+ ```python
165
+ from finatic_server.types.broker import BrokerDataOptions, OrdersFilter, PositionsFilter, AccountsFilter
166
+
167
+ # Basic filtering
168
+ options = BrokerDataOptions(
169
+ broker_name="robinhood",
170
+ account_id="123456",
171
+ symbol="AAPL"
172
+ )
173
+
174
+ # Advanced filtering for orders
175
+ order_filters = OrdersFilter(
176
+ status="filled",
177
+ side="buy",
178
+ asset_type="stock",
179
+ created_after="2024-01-01T00:00:00Z"
180
+ )
181
+
182
+ # Advanced filtering for positions
183
+ position_filters = PositionsFilter(
184
+ symbol="AAPL",
185
+ side="long",
186
+ asset_type="stock"
187
+ )
188
+
189
+ # Advanced filtering for accounts
190
+ account_filters = AccountsFilter(
191
+ account_type="margin",
192
+ status="active",
193
+ currency="USD"
194
+ )
195
+ ```
196
+
197
+ ## Usage Examples
198
+
199
+ ### Get All Orders with Filtering
200
+
201
+ ```python
202
+ # Get all filled orders for a specific symbol
203
+ all_filled_orders = await client.get_all_broker_orders(
204
+ filters=OrdersFilter(
205
+ status="filled",
206
+ symbol="AAPL"
207
+ )
208
+ )
209
+ print(f"Found {len(all_filled_orders)} filled AAPL orders")
210
+ ```
211
+
212
+ ### Pagination Example
213
+
214
+ ```python
215
+ # Get first page of 10 orders
216
+ first_page = await client.get_broker_orders(page=1, per_page=10)
217
+ print(f"First page: {len(first_page)} orders")
218
+
219
+ # Get second page
220
+ second_page = await client.get_broker_orders(page=2, per_page=10)
221
+ print(f"Second page: {len(second_page)} orders")
222
+ ```
223
+
224
+ ### Get All Data for Analysis
225
+
226
+ ```python
227
+ # Get all accounts, orders, and positions
228
+ all_accounts = await client.get_all_broker_accounts()
229
+ all_orders = await client.get_all_broker_orders()
230
+ all_positions = await client.get_all_broker_positions()
231
+
232
+ print(f"Total accounts: {len(all_accounts)}")
233
+ print(f"Total orders: {len(all_orders)}")
234
+ print(f"Total positions: {len(all_positions)}")
235
+ ```
236
+
237
+ ### Filter by Broker
238
+
239
+ ```python
240
+ # Get all orders from Robinhood
241
+ robinhood_orders = await client.get_all_broker_orders(
242
+ options=BrokerDataOptions(broker_name="robinhood")
243
+ )
244
+
245
+ # Get all positions from Tasty Trade
246
+ tasty_positions = await client.get_all_broker_positions(
247
+ options=BrokerDataOptions(broker_name="tasty_trade")
248
+ )
249
+ ```
250
+
251
+ ## Error Handling
252
+
253
+ The SDK provides comprehensive error handling:
254
+
255
+ ```python
256
+ from finatic_server import AuthenticationError, ApiError, NetworkError
257
+
258
+ try:
259
+ orders = await client.get_broker_orders()
260
+ except AuthenticationError as e:
261
+ print(f"Authentication failed: {e}")
262
+ except NetworkError as e:
263
+ print(f"Network error: {e}")
264
+ except ApiError as e:
265
+ print(f"API error: {e}")
266
+ ```
267
+
268
+ ## Complete Example
269
+
270
+ ```python
271
+ import asyncio
272
+ from finatic_server import FinaticServerClient
273
+ from finatic_server.types.broker import OrdersFilter, BrokerDataOptions
274
+
275
+ async def main():
276
+ # Option 1: Portal Authentication (user completes auth in browser)
277
+ client = FinaticServerClient("your-api-key")
278
+
279
+ try:
280
+ # Start session
281
+ await client.start_session()
282
+
283
+ # Get portal URL
284
+ portal_url = await client.get_portal_url()
285
+ print(f"Please visit: {portal_url}")
286
+
287
+ # Wait for user to complete authentication
288
+ input("Press Enter after completing authentication...")
289
+
290
+ # Get user info
291
+ user_info = await client.get_session_user()
292
+ print(f"Authenticated as: {user_info['user_id']}")
293
+
294
+ # Option 2: Direct Authentication (if you know the user ID)
295
+ # client = FinaticServerClient("your-api-key", user_id="user123")
296
+ # await client.start_session()
297
+ # print("Directly authenticated!")
298
+
299
+ # Get broker information
300
+ brokers = await client.get_broker_list()
301
+ print(f"Available brokers: {[b.name for b in brokers]}")
302
+
303
+ # Get all filled orders
304
+ filled_orders = await client.get_all_broker_orders(
305
+ filters=OrdersFilter(status="filled")
306
+ )
307
+ print(f"Total filled orders: {len(filled_orders)}")
308
+
309
+ # Get all positions
310
+ positions = await client.get_all_broker_positions()
311
+ print(f"Total positions: {len(positions)}")
312
+
313
+ # Get accounts with cash balance
314
+ accounts = await client.get_all_broker_accounts()
315
+ for account in accounts:
316
+ cash = account.cash_balance or 0.0
317
+ print(f"{account.account_name}: ${cash:,.2f}")
318
+
319
+ except Exception as e:
320
+ print(f"Error: {e}")
321
+ finally:
322
+ await client.close()
323
+
324
+ if __name__ == "__main__":
325
+ asyncio.run(main())
326
+ ```
327
+
328
+ ## License
329
+
330
+ MIT License - see [LICENSE](LICENSE) file for details.
@@ -0,0 +1,16 @@
1
+ finatic_server/__init__.py,sha256=M6DZ75v0qK4xOAVLYPzCfCiyNFiFVPTqCIv2yf6LqX8,2558
2
+ finatic_server/core/__init__.py,sha256=j47dRgumMlE0CDAJw-VgFinGwgrxrYeXq1r65gKD3tg,190
3
+ finatic_server/core/api_client.py,sha256=aCGaQFdqd-SggNPptIrNVSeS6eS14N1GrPw_TurU6G0,34131
4
+ finatic_server/core/client.py,sha256=kR9uT1RtjKloDrgDsDtLTSgoR7QInv_j-IuqnZM6SGM,22202
5
+ finatic_server/types/__init__.py,sha256=9tqj5qIUXWmPvvNxdzZ_1ju2dXb6XiV7u986USH66Ew,2002
6
+ finatic_server/types/auth.py,sha256=toeeWxkx_0jLUxJpaANBrqVo7Rys5aQ9DD-biWijXw4,5975
7
+ finatic_server/types/broker.py,sha256=mOA7JKUQpssnji-plJ011U-9izA-K90RHa7wd_PFq2g,8286
8
+ finatic_server/types/common.py,sha256=rrfpA9g3oMZp32sJ7dhhetVGEV442hXYWrEJ-D9ksIc,7472
9
+ finatic_server/types/orders.py,sha256=TW0j6g7eS3cex3SEs1fu8MF9QFViirxMF6S1C3VgQmo,3345
10
+ finatic_server/types/portfolio.py,sha256=_EtUwQy6GmvU9UAMD59d4KePHJkxbQYA0xX5de2D4L8,3031
11
+ finatic_server/utils/__init__.py,sha256=qL0pv3fto3Jy2h8FY3iRg1IMVm9D1-1Oy3w7aNHh_bI,327
12
+ finatic_server/utils/errors.py,sha256=Z_-UVDnorwHfAiZ819BSxki2xVHn6AnOi9_9hpDwW48,1802
13
+ finatic_server_python-0.1.0.dist-info/METADATA,sha256=1q6MBj9arHc9tLGiRAuNTvrv5_T5M9Av8NFGucLPN14,10361
14
+ finatic_server_python-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
+ finatic_server_python-0.1.0.dist-info/top_level.txt,sha256=5eAfjxxwueQwIup4GCHEyKWX8PNvqhx1BV7C7TA4z50,15
16
+ finatic_server_python-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ finatic_server