alvaindes 0.1.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.
- alvaindes-0.1.0/.gitignore +33 -0
- alvaindes-0.1.0/LICENSE +21 -0
- alvaindes-0.1.0/PKG-INFO +598 -0
- alvaindes-0.1.0/README.md +565 -0
- alvaindes-0.1.0/assets/alvaindes.png +0 -0
- alvaindes-0.1.0/pyproject.toml +73 -0
- alvaindes-0.1.0/src/alvaindes/__init__.py +8 -0
- alvaindes-0.1.0/src/alvaindes/client.py +152 -0
- alvaindes-0.1.0/src/alvaindes/config.py +44 -0
- alvaindes-0.1.0/src/alvaindes/errors.py +19 -0
- alvaindes-0.1.0/src/alvaindes/http/__init__.py +0 -0
- alvaindes-0.1.0/src/alvaindes/http/async_transport.py +95 -0
- alvaindes-0.1.0/src/alvaindes/http/sync_transport.py +95 -0
- alvaindes-0.1.0/src/alvaindes/http/transport.py +12 -0
- alvaindes-0.1.0/src/alvaindes/resources/__init__.py +69 -0
- alvaindes-0.1.0/src/alvaindes/resources/accounts.py +95 -0
- alvaindes-0.1.0/src/alvaindes/resources/assets.py +31 -0
- alvaindes-0.1.0/src/alvaindes/resources/async_base.py +32 -0
- alvaindes-0.1.0/src/alvaindes/resources/base.py +32 -0
- alvaindes-0.1.0/src/alvaindes/resources/broker_agreements.py +120 -0
- alvaindes-0.1.0/src/alvaindes/resources/broker_disclosures.py +87 -0
- alvaindes-0.1.0/src/alvaindes/resources/deposits.py +66 -0
- alvaindes-0.1.0/src/alvaindes/resources/funding_sources.py +155 -0
- alvaindes-0.1.0/src/alvaindes/resources/holdings.py +44 -0
- alvaindes-0.1.0/src/alvaindes/resources/kyc.py +98 -0
- alvaindes-0.1.0/src/alvaindes/resources/market_data.py +22 -0
- alvaindes-0.1.0/src/alvaindes/resources/orders.py +130 -0
- alvaindes-0.1.0/src/alvaindes/resources/portfolios.py +44 -0
- alvaindes-0.1.0/src/alvaindes/resources/transactions.py +44 -0
- alvaindes-0.1.0/src/alvaindes/resources/users.py +76 -0
- alvaindes-0.1.0/src/alvaindes/resources/withdrawals.py +66 -0
- alvaindes-0.1.0/src/alvaindes/types/__init__.py +89 -0
- alvaindes-0.1.0/src/alvaindes/types/accounts.py +15 -0
- alvaindes-0.1.0/src/alvaindes/types/assets.py +15 -0
- alvaindes-0.1.0/src/alvaindes/types/broker_agreements.py +24 -0
- alvaindes-0.1.0/src/alvaindes/types/broker_disclosures.py +26 -0
- alvaindes-0.1.0/src/alvaindes/types/deposits.py +22 -0
- alvaindes-0.1.0/src/alvaindes/types/funding_sources.py +34 -0
- alvaindes-0.1.0/src/alvaindes/types/holdings.py +9 -0
- alvaindes-0.1.0/src/alvaindes/types/kyc.py +66 -0
- alvaindes-0.1.0/src/alvaindes/types/market_data.py +8 -0
- alvaindes-0.1.0/src/alvaindes/types/orders.py +39 -0
- alvaindes-0.1.0/src/alvaindes/types/portfolios.py +11 -0
- alvaindes-0.1.0/src/alvaindes/types/transactions.py +13 -0
- alvaindes-0.1.0/src/alvaindes/types/users.py +24 -0
- alvaindes-0.1.0/src/alvaindes/types/withdrawals.py +22 -0
- alvaindes-0.1.0/tests/test_assets.py +61 -0
- alvaindes-0.1.0/tests/test_async_assets.py +67 -0
- alvaindes-0.1.0/tests/test_async_broker_agreements.py +146 -0
- alvaindes-0.1.0/tests/test_async_broker_disclosures.py +104 -0
- alvaindes-0.1.0/tests/test_async_deposits.py +105 -0
- alvaindes-0.1.0/tests/test_async_funding_sources.py +201 -0
- alvaindes-0.1.0/tests/test_async_holdings.py +47 -0
- alvaindes-0.1.0/tests/test_async_market_data.py +70 -0
- alvaindes-0.1.0/tests/test_async_orders.py +136 -0
- alvaindes-0.1.0/tests/test_async_portfolios.py +40 -0
- alvaindes-0.1.0/tests/test_async_transactions.py +65 -0
- alvaindes-0.1.0/tests/test_async_users.py +66 -0
- alvaindes-0.1.0/tests/test_async_withdrawals.py +107 -0
- alvaindes-0.1.0/tests/test_broker_agreements.py +136 -0
- alvaindes-0.1.0/tests/test_broker_disclosures.py +101 -0
- alvaindes-0.1.0/tests/test_deposits.py +97 -0
- alvaindes-0.1.0/tests/test_funding_sources.py +201 -0
- alvaindes-0.1.0/tests/test_holdings.py +47 -0
- alvaindes-0.1.0/tests/test_market_data.py +67 -0
- alvaindes-0.1.0/tests/test_orders.py +136 -0
- alvaindes-0.1.0/tests/test_portfolios.py +40 -0
- alvaindes-0.1.0/tests/test_transactions.py +59 -0
- alvaindes-0.1.0/tests/test_users.py +64 -0
- alvaindes-0.1.0/tests/test_withdrawals.py +99 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Virtual environments
|
|
2
|
+
.venv/
|
|
3
|
+
venv/
|
|
4
|
+
env/
|
|
5
|
+
|
|
6
|
+
# Python cache
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[cod]
|
|
9
|
+
*$py.class
|
|
10
|
+
|
|
11
|
+
# Test and coverage
|
|
12
|
+
.pytest_cache/
|
|
13
|
+
.coverage
|
|
14
|
+
htmlcov/
|
|
15
|
+
|
|
16
|
+
# Build artifacts
|
|
17
|
+
build/
|
|
18
|
+
dist/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
|
|
21
|
+
# Type checking
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
.pyright/
|
|
24
|
+
|
|
25
|
+
# Environment variables and secrets
|
|
26
|
+
.env
|
|
27
|
+
.env.*
|
|
28
|
+
!.env.example
|
|
29
|
+
|
|
30
|
+
# IDE and OS files
|
|
31
|
+
.DS_Store
|
|
32
|
+
.idea/
|
|
33
|
+
.vscode/
|
alvaindes-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alvaindes
|
|
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.
|
alvaindes-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: alvaindes
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for the Alvaindes brokerage infrastructure API
|
|
5
|
+
Project-URL: Homepage, https://alvaindes.com
|
|
6
|
+
Project-URL: Repository, https://github.com/davidokani/alvaindes-python-sdk
|
|
7
|
+
Project-URL: Documentation, https://alvaindes.com/docs
|
|
8
|
+
Author: Alvaindes
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: alvaindes,brokerage,brokerage-api,fintech,investment,trading
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: httpx<1.0,>=0.27.0
|
|
25
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: hatchling; extra == 'dev'
|
|
28
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# Alvaindes Python SDK
|
|
35
|
+
|
|
36
|
+
<p align="center">
|
|
37
|
+
<img src="./assets/alvaindes.png" alt="Alvaindes Logo" width="140">
|
|
38
|
+
</p>
|
|
39
|
+
|
|
40
|
+
<h1 align="center">Alvaindes SDK</h1>
|
|
41
|
+
|
|
42
|
+
<p align="center">
|
|
43
|
+
Official Python SDK for integrating Alvaindes brokerage infrastructure API.
|
|
44
|
+
</p>
|
|
45
|
+
|
|
46
|
+
<p align="center">
|
|
47
|
+
The SDK provides synchronous and asynchronous Python clients for interacting with the public, versioned Alvaindes API. Use the SDK to work with users, investment accounts, KYC, assets, funding sources, portfolios, holdings, orders, deposits, withdrawals, transactions, broker agreements, broker disclosures, and market data.
|
|
48
|
+
</p>
|
|
49
|
+
|
|
50
|
+
## Features
|
|
51
|
+
|
|
52
|
+
- Synchronous and asynchronous clients.
|
|
53
|
+
- Python 3.10 and newer.
|
|
54
|
+
- Typed request parameters and response objects.
|
|
55
|
+
- HTTP communication powered by [httpx](https://www.python-httpx.org/).
|
|
56
|
+
- Consistent API error handling.
|
|
57
|
+
- Context-manager support for client lifecycle management.
|
|
58
|
+
- Optional idempotency keys for supported financial operations.
|
|
59
|
+
- No automatic retries.
|
|
60
|
+
|
|
61
|
+
## Requirements
|
|
62
|
+
|
|
63
|
+
- Python 3.10+
|
|
64
|
+
- An Alvaindes API key.
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
Install the SDK using pip:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install alvaindes
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
### Synchronous Client
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from alvaindes import Alvaindes
|
|
80
|
+
|
|
81
|
+
with Alvaindes(api_key="YOUR_API_KEY") as client:
|
|
82
|
+
user = client.users.get(
|
|
83
|
+
application_id="YOUR_APPLICATION_ID",
|
|
84
|
+
user_id="YOUR_USER_ID",
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
print(user)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Asynchronous Client
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
import asyncio
|
|
94
|
+
|
|
95
|
+
from alvaindes import AsyncAlvaindes
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
async def main():
|
|
99
|
+
async with AsyncAlvaindes(api_key="YOUR_API_KEY") as client:
|
|
100
|
+
user = await client.users.get(
|
|
101
|
+
application_id="YOUR_APPLICATION_ID",
|
|
102
|
+
user_id="YOUR_USER_ID",
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
print(user)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
asyncio.run(main())
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Both clients expose the same resource capabilities. The asynchronous client uses `await` for API operations.
|
|
112
|
+
|
|
113
|
+
## Configuration
|
|
114
|
+
|
|
115
|
+
Both clients accept the following keyword arguments:
|
|
116
|
+
|
|
117
|
+
| Parameter | Type | Default | Description |
|
|
118
|
+
| ---------- | ------- | --------------------------- | -------------------------------- |
|
|
119
|
+
| `api_key` | `str` | Required | Your Alvaindes API key. |
|
|
120
|
+
| `base_url` | `str` | `https://api.alvaindes.com` | API origin. |
|
|
121
|
+
| `timeout` | `float` | `30.0` | HTTP request timeout in seconds. |
|
|
122
|
+
|
|
123
|
+
Example:
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
from alvaindes import Alvaindes
|
|
127
|
+
|
|
128
|
+
client = Alvaindes(
|
|
129
|
+
api_key="YOUR_API_KEY",
|
|
130
|
+
base_url="https://api.alvaindes.com",
|
|
131
|
+
timeout=45.0,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
user = client.users.get("YOUR_APPLICATION_ID", "YOUR_USER_ID")
|
|
136
|
+
print(user)
|
|
137
|
+
finally:
|
|
138
|
+
client.close()
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The `base_url` must be an HTTP or HTTPS origin. Do not append `/v1`; the SDK includes the API version in its resource paths.
|
|
142
|
+
|
|
143
|
+
The API key is sent using the `x-api-key` HTTP header. The API determines the environment and permissions associated with the key.
|
|
144
|
+
|
|
145
|
+
Keep API keys private. Do not commit them to source control or expose them in client-side applications.
|
|
146
|
+
|
|
147
|
+
## Available Resources
|
|
148
|
+
|
|
149
|
+
The SDK exposes the following resources through both `Alvaindes` and `AsyncAlvaindes`.
|
|
150
|
+
|
|
151
|
+
| Resource | Available Methods |
|
|
152
|
+
| -------------------- | --------------------------------------------- |
|
|
153
|
+
| `users` | `create`, `get` |
|
|
154
|
+
| `accounts` | `create`, `list`, `get` |
|
|
155
|
+
| `kyc` | `submit`, `get`, `update` |
|
|
156
|
+
| `funding_sources` | `create`, `list`, `refresh`, `disable` |
|
|
157
|
+
| `portfolios` | `get` |
|
|
158
|
+
| `holdings` | `list` |
|
|
159
|
+
| `orders` | `create`, `list`, `get` |
|
|
160
|
+
| `deposits` | `create` |
|
|
161
|
+
| `withdrawals` | `create` |
|
|
162
|
+
| `transactions` | `list` |
|
|
163
|
+
| `assets` | `list` |
|
|
164
|
+
| `market_data` | `get_quote` |
|
|
165
|
+
| `broker_agreements` | `get_requirements`, `list_accepted`, `accept` |
|
|
166
|
+
| `broker_disclosures` | `get`, `create` |
|
|
167
|
+
|
|
168
|
+
## Resource Examples
|
|
169
|
+
|
|
170
|
+
All examples below use the synchronous client. The same operations are available through `AsyncAlvaindes` using `await`.
|
|
171
|
+
|
|
172
|
+
### 1. Users
|
|
173
|
+
|
|
174
|
+
Create and retrieve users associated with an application.
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
user = client.users.create(
|
|
178
|
+
application_id="YOUR_APPLICATION_ID",
|
|
179
|
+
params={
|
|
180
|
+
"firstName": "Jane",
|
|
181
|
+
"lastName": "Doe",
|
|
182
|
+
"email": "jane@example.com",
|
|
183
|
+
"phoneNumber": "+1234567890",
|
|
184
|
+
"country": "US",
|
|
185
|
+
},
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
user = client.users.get(
|
|
189
|
+
application_id="YOUR_APPLICATION_ID",
|
|
190
|
+
user_id=user["id"],
|
|
191
|
+
)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 2. Investment Accounts
|
|
195
|
+
|
|
196
|
+
Create, list, and retrieve investment accounts belonging to a user.
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
account = client.accounts.create(
|
|
200
|
+
user_id="YOUR_USER_ID",
|
|
201
|
+
params={
|
|
202
|
+
"currency": "USD",
|
|
203
|
+
"brokerConnectionId": "YOUR_BROKER_CONNECTION_ID",
|
|
204
|
+
},
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
accounts = client.accounts.list("YOUR_USER_ID")
|
|
208
|
+
|
|
209
|
+
account = client.accounts.get(
|
|
210
|
+
user_id="YOUR_USER_ID",
|
|
211
|
+
account_id="YOUR_ACCOUNT_ID",
|
|
212
|
+
)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### 3. KYC
|
|
216
|
+
|
|
217
|
+
Submit, retrieve, and update a user's Know Your Customer information.
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
kyc = client.kyc.submit(
|
|
221
|
+
user_id="YOUR_USER_ID",
|
|
222
|
+
params={
|
|
223
|
+
"countryOfResidence": "US",
|
|
224
|
+
"dateOfBirth": "1990-01-15",
|
|
225
|
+
"addressLine1": "123 Main Street",
|
|
226
|
+
"addressCity": "New York",
|
|
227
|
+
"documentType": "PASSPORT",
|
|
228
|
+
},
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
kyc = client.kyc.get("YOUR_USER_ID")
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Accepted document types:
|
|
235
|
+
|
|
236
|
+
- `PASSPORT`
|
|
237
|
+
- `NATIONAL_ID`
|
|
238
|
+
- `DRIVERS_LICENSE`
|
|
239
|
+
- `VOTERS_CARD`
|
|
240
|
+
|
|
241
|
+
Refer to the API documentation for the complete KYC submission and update fields.
|
|
242
|
+
|
|
243
|
+
### 4. Funding Sources
|
|
244
|
+
|
|
245
|
+
Create, list, refresh, and disable funding sources associated with an investment account.
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
funding_source = client.funding_sources.create(
|
|
249
|
+
user_id="YOUR_USER_ID",
|
|
250
|
+
account_id="YOUR_ACCOUNT_ID",
|
|
251
|
+
params={
|
|
252
|
+
"type": "ACH",
|
|
253
|
+
"ownerName": "Jane Doe",
|
|
254
|
+
"bankAccountNumber": "YOUR_BANK_ACCOUNT_NUMBER",
|
|
255
|
+
"bankAccountType": "checking",
|
|
256
|
+
"routingNumber": "YOUR_ROUTING_NUMBER",
|
|
257
|
+
"currency": "USD",
|
|
258
|
+
},
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
funding_sources = client.funding_sources.list(
|
|
262
|
+
"YOUR_USER_ID",
|
|
263
|
+
"YOUR_ACCOUNT_ID",
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
funding_source = client.funding_sources.refresh(
|
|
267
|
+
"YOUR_USER_ID",
|
|
268
|
+
"YOUR_ACCOUNT_ID",
|
|
269
|
+
funding_source_id="YOUR_FUNDING_SOURCE_ID",
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
funding_source = client.funding_sources.disable(
|
|
273
|
+
"YOUR_USER_ID",
|
|
274
|
+
"YOUR_ACCOUNT_ID",
|
|
275
|
+
funding_source_id="YOUR_FUNDING_SOURCE_ID",
|
|
276
|
+
)
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### 5. Portfolios and Holdings
|
|
280
|
+
|
|
281
|
+
Retrieve portfolio information and account holdings.
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
portfolio = client.portfolios.get(
|
|
285
|
+
"YOUR_USER_ID",
|
|
286
|
+
"YOUR_ACCOUNT_ID",
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
holdings = client.holdings.list(
|
|
290
|
+
"YOUR_USER_ID",
|
|
291
|
+
"YOUR_ACCOUNT_ID",
|
|
292
|
+
)
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### 6. Orders
|
|
296
|
+
|
|
297
|
+
Create, list, and retrieve investment orders.
|
|
298
|
+
|
|
299
|
+
**Market order:**
|
|
300
|
+
|
|
301
|
+
```python
|
|
302
|
+
order = client.orders.create(
|
|
303
|
+
user_id="YOUR_USER_ID",
|
|
304
|
+
account_id="YOUR_ACCOUNT_ID",
|
|
305
|
+
params={
|
|
306
|
+
"symbol": "AAPL",
|
|
307
|
+
"side": "BUY",
|
|
308
|
+
"quantity": 1,
|
|
309
|
+
"type": "MARKET",
|
|
310
|
+
},
|
|
311
|
+
)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**Limit order:**
|
|
315
|
+
|
|
316
|
+
```python
|
|
317
|
+
order = client.orders.create(
|
|
318
|
+
user_id="YOUR_USER_ID",
|
|
319
|
+
account_id="YOUR_ACCOUNT_ID",
|
|
320
|
+
params={
|
|
321
|
+
"symbol": "AAPL",
|
|
322
|
+
"side": "BUY",
|
|
323
|
+
"quantity": 1,
|
|
324
|
+
"type": "LIMIT",
|
|
325
|
+
"limitPrice": 200.00,
|
|
326
|
+
},
|
|
327
|
+
)
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**List orders:**
|
|
331
|
+
|
|
332
|
+
```python
|
|
333
|
+
orders = client.orders.list(
|
|
334
|
+
"YOUR_USER_ID",
|
|
335
|
+
"YOUR_ACCOUNT_ID",
|
|
336
|
+
)
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Retrieve an order:**
|
|
340
|
+
|
|
341
|
+
```python
|
|
342
|
+
order = client.orders.get(
|
|
343
|
+
"YOUR_USER_ID",
|
|
344
|
+
"YOUR_ACCOUNT_ID",
|
|
345
|
+
"YOUR_ORDER_ID",
|
|
346
|
+
)
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### 7. Deposits
|
|
350
|
+
|
|
351
|
+
Create a deposit into an investment account.
|
|
352
|
+
|
|
353
|
+
```python
|
|
354
|
+
deposit = client.deposits.create(
|
|
355
|
+
user_id="YOUR_USER_ID",
|
|
356
|
+
account_id="YOUR_ACCOUNT_ID",
|
|
357
|
+
params={
|
|
358
|
+
"amount": 100.00,
|
|
359
|
+
"currency": "USD",
|
|
360
|
+
"fundingSourceId": "YOUR_FUNDING_SOURCE_ID",
|
|
361
|
+
},
|
|
362
|
+
)
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
`fundingSourceId` is optional when the backend supports its configured funding-source selection behavior.
|
|
366
|
+
|
|
367
|
+
### 8. Withdrawals
|
|
368
|
+
|
|
369
|
+
Create a withdrawal from an investment account.
|
|
370
|
+
|
|
371
|
+
```python
|
|
372
|
+
withdrawal = client.withdrawals.create(
|
|
373
|
+
user_id="YOUR_USER_ID",
|
|
374
|
+
account_id="YOUR_ACCOUNT_ID",
|
|
375
|
+
params={
|
|
376
|
+
"amount": 50.00,
|
|
377
|
+
"currency": "USD",
|
|
378
|
+
"fundingSourceId": "YOUR_FUNDING_SOURCE_ID",
|
|
379
|
+
},
|
|
380
|
+
)
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### 9. Transactions
|
|
384
|
+
|
|
385
|
+
List transactions associated with an investment account.
|
|
386
|
+
|
|
387
|
+
```python
|
|
388
|
+
transactions = client.transactions.list(
|
|
389
|
+
"YOUR_USER_ID",
|
|
390
|
+
"YOUR_ACCOUNT_ID",
|
|
391
|
+
)
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### 10. Assets
|
|
395
|
+
|
|
396
|
+
Search assets using the required connection ID and query.
|
|
397
|
+
|
|
398
|
+
```python
|
|
399
|
+
assets = client.assets.list(
|
|
400
|
+
params={
|
|
401
|
+
"connectionId": "YOUR_BROKER_CONNECTION_ID",
|
|
402
|
+
"query": "AAPL",
|
|
403
|
+
},
|
|
404
|
+
)
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### 11. Market Data
|
|
408
|
+
|
|
409
|
+
Retrieve a quote for a symbol.
|
|
410
|
+
|
|
411
|
+
```python
|
|
412
|
+
quote = client.market_data.get_quote("AAPL")
|
|
413
|
+
|
|
414
|
+
print(quote["symbol"])
|
|
415
|
+
print(quote["price"])
|
|
416
|
+
print(quote["currency"])
|
|
417
|
+
print(quote["timestamp"])
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
The SDK URL-encodes symbols when constructing the request path.
|
|
421
|
+
|
|
422
|
+
### 12. Broker Agreements
|
|
423
|
+
|
|
424
|
+
Retrieve agreement requirements, list accepted agreements, and accept an agreement.
|
|
425
|
+
|
|
426
|
+
```python
|
|
427
|
+
requirements = client.broker_agreements.get_requirements(
|
|
428
|
+
"YOUR_USER_ID",
|
|
429
|
+
"YOUR_BROKER_CONNECTION_ID",
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
accepted = client.broker_agreements.list_accepted(
|
|
433
|
+
"YOUR_USER_ID",
|
|
434
|
+
"YOUR_BROKER_CONNECTION_ID",
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
agreement = client.broker_agreements.accept(
|
|
438
|
+
"YOUR_USER_ID",
|
|
439
|
+
"YOUR_BROKER_CONNECTION_ID",
|
|
440
|
+
params={
|
|
441
|
+
"agreement": "YOUR_AGREEMENT_TYPE",
|
|
442
|
+
},
|
|
443
|
+
)
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### 13. Broker Disclosures
|
|
447
|
+
|
|
448
|
+
Retrieve or create a user's broker disclosure.
|
|
449
|
+
|
|
450
|
+
```python
|
|
451
|
+
disclosure = client.broker_disclosures.create(
|
|
452
|
+
"YOUR_USER_ID",
|
|
453
|
+
"YOUR_BROKER_CONNECTION_ID",
|
|
454
|
+
params={
|
|
455
|
+
"employmentStatus": "EMPLOYED",
|
|
456
|
+
"employmentSector": "TECHNOLOGY",
|
|
457
|
+
"isControlPerson": False,
|
|
458
|
+
"isAffiliatedExchangeOrFinra": False,
|
|
459
|
+
"isPoliticallyExposed": False,
|
|
460
|
+
"immediateFamilyExposed": False,
|
|
461
|
+
},
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
disclosure = client.broker_disclosures.get(
|
|
465
|
+
"YOUR_USER_ID",
|
|
466
|
+
"YOUR_BROKER_CONNECTION_ID",
|
|
467
|
+
)
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
## Asynchronous Usage
|
|
471
|
+
|
|
472
|
+
Every resource listed above is also available on `AsyncAlvaindes`.
|
|
473
|
+
|
|
474
|
+
Example:
|
|
475
|
+
|
|
476
|
+
```python
|
|
477
|
+
import asyncio
|
|
478
|
+
|
|
479
|
+
from alvaindes import AsyncAlvaindes
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
async def main():
|
|
483
|
+
async with AsyncAlvaindes(api_key="YOUR_API_KEY") as client:
|
|
484
|
+
accounts = await client.accounts.list("YOUR_USER_ID")
|
|
485
|
+
|
|
486
|
+
quote = await client.market_data.get_quote("AAPL")
|
|
487
|
+
|
|
488
|
+
print(accounts)
|
|
489
|
+
print(quote)
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
asyncio.run(main())
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
## Idempotency
|
|
496
|
+
|
|
497
|
+
The SDK supports optional idempotency keys on order, deposit, and withdrawal creation.
|
|
498
|
+
|
|
499
|
+
Example:
|
|
500
|
+
|
|
501
|
+
```python
|
|
502
|
+
order = client.orders.create(
|
|
503
|
+
user_id="YOUR_USER_ID",
|
|
504
|
+
account_id="YOUR_ACCOUNT_ID",
|
|
505
|
+
params={
|
|
506
|
+
"symbol": "AAPL",
|
|
507
|
+
"side": "BUY",
|
|
508
|
+
"quantity": 1,
|
|
509
|
+
"type": "MARKET",
|
|
510
|
+
},
|
|
511
|
+
options={
|
|
512
|
+
"idempotencyKey": "YOUR_UNIQUE_REQUEST_KEY",
|
|
513
|
+
},
|
|
514
|
+
)
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
The same `options` pattern is supported by:
|
|
518
|
+
|
|
519
|
+
- `client.orders.create()`
|
|
520
|
+
- `client.deposits.create()`
|
|
521
|
+
- `client.withdrawals.create()`
|
|
522
|
+
|
|
523
|
+
The SDK sends the value using the `Idempotency-Key` HTTP header.
|
|
524
|
+
|
|
525
|
+
The SDK does not automatically retry requests. Applications should handle retries deliberately, particularly for financial operations, and use idempotency keys where supported.
|
|
526
|
+
|
|
527
|
+
## Error Handling
|
|
528
|
+
|
|
529
|
+
API and transport errors are exposed through `AlvaindesError`.
|
|
530
|
+
|
|
531
|
+
```python
|
|
532
|
+
from alvaindes import Alvaindes, AlvaindesError
|
|
533
|
+
|
|
534
|
+
try:
|
|
535
|
+
with Alvaindes(api_key="YOUR_API_KEY") as client:
|
|
536
|
+
user = client.users.get(
|
|
537
|
+
"YOUR_APPLICATION_ID",
|
|
538
|
+
"YOUR_USER_ID",
|
|
539
|
+
)
|
|
540
|
+
|
|
541
|
+
except AlvaindesError as error:
|
|
542
|
+
print("Message:", error.message)
|
|
543
|
+
print("HTTP status:", error.status)
|
|
544
|
+
print("Error code:", error.code)
|
|
545
|
+
print("Response:", error.response)
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
The exception exposes the following attributes:
|
|
549
|
+
|
|
550
|
+
| Attribute | Description |
|
|
551
|
+
| ---------- | ------------------------------------------------------- |
|
|
552
|
+
| `message` | Human-readable error message. |
|
|
553
|
+
| `status` | HTTP status code, or `0` for a transport-level failure. |
|
|
554
|
+
| `code` | API or transport error code when available. |
|
|
555
|
+
| `response` | Parsed API response when available. |
|
|
556
|
+
|
|
557
|
+
Transport error codes include `TIMEOUT` and `NETWORK_ERROR`.
|
|
558
|
+
|
|
559
|
+
## Client Lifecycle
|
|
560
|
+
|
|
561
|
+
The synchronous client supports:
|
|
562
|
+
|
|
563
|
+
- `close()`
|
|
564
|
+
- `with` context management
|
|
565
|
+
|
|
566
|
+
The asynchronous client supports:
|
|
567
|
+
|
|
568
|
+
- `aclose()`
|
|
569
|
+
- `async with` context management
|
|
570
|
+
|
|
571
|
+
Using context managers is recommended because they close the underlying HTTP client automatically.
|
|
572
|
+
|
|
573
|
+
## Type Definitions
|
|
574
|
+
|
|
575
|
+
The SDK includes typed request parameters and response definitions.
|
|
576
|
+
|
|
577
|
+
Import types from `alvaindes.types`:
|
|
578
|
+
|
|
579
|
+
```python
|
|
580
|
+
from alvaindes.types import (
|
|
581
|
+
CreateUserParams,
|
|
582
|
+
InvestmentAccountResponse,
|
|
583
|
+
MarketQuoteResponse,
|
|
584
|
+
OrderResponse,
|
|
585
|
+
)
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
The types preserve the camelCase field names used by the Alvaindes API.
|
|
589
|
+
|
|
590
|
+
## Documentation and Links
|
|
591
|
+
|
|
592
|
+
- Website: https://alvaindes.com
|
|
593
|
+
- API documentation: https://alvaindes.com/docs
|
|
594
|
+
- GitHub repository: https://github.com/davidokani/alvaindes-python-sdk
|
|
595
|
+
|
|
596
|
+
## License
|
|
597
|
+
|
|
598
|
+
This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.
|