etrade-python 1.0.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.
Files changed (49) hide show
  1. etrade_python/__init__.py +264 -0
  2. etrade_python/_dates.py +152 -0
  3. etrade_python/_version.py +3 -0
  4. etrade_python/accounts/__init__.py +31 -0
  5. etrade_python/accounts/models.py +204 -0
  6. etrade_python/accounts/service.py +136 -0
  7. etrade_python/alerts/__init__.py +23 -0
  8. etrade_python/alerts/models.py +180 -0
  9. etrade_python/alerts/service.py +128 -0
  10. etrade_python/auth/__init__.py +31 -0
  11. etrade_python/auth/credentials.py +85 -0
  12. etrade_python/auth/oauth.py +268 -0
  13. etrade_python/auth/session.py +154 -0
  14. etrade_python/auth/stores/__init__.py +7 -0
  15. etrade_python/auth/stores/base.py +18 -0
  16. etrade_python/auth/stores/keyring.py +49 -0
  17. etrade_python/auth/stores/memory.py +19 -0
  18. etrade_python/cli/__init__.py +1 -0
  19. etrade_python/cli/app.py +1623 -0
  20. etrade_python/client.py +84 -0
  21. etrade_python/config.py +43 -0
  22. etrade_python/enums.py +19 -0
  23. etrade_python/exceptions.py +68 -0
  24. etrade_python/market/__init__.py +59 -0
  25. etrade_python/market/models.py +811 -0
  26. etrade_python/market/service.py +168 -0
  27. etrade_python/orders/__init__.py +107 -0
  28. etrade_python/orders/builders.py +617 -0
  29. etrade_python/orders/models.py +1009 -0
  30. etrade_python/orders/service.py +259 -0
  31. etrade_python/orders/values.py +67 -0
  32. etrade_python/portfolio/__init__.py +35 -0
  33. etrade_python/portfolio/models.py +429 -0
  34. etrade_python/portfolio/service.py +99 -0
  35. etrade_python/py.typed +0 -0
  36. etrade_python/transactions/__init__.py +27 -0
  37. etrade_python/transactions/models.py +201 -0
  38. etrade_python/transactions/service.py +138 -0
  39. etrade_python/transport/__init__.py +7 -0
  40. etrade_python/transport/auth.py +17 -0
  41. etrade_python/transport/http.py +240 -0
  42. etrade_python/transport/logging.py +38 -0
  43. etrade_python/transport/response.py +243 -0
  44. etrade_python/transport/retry.py +75 -0
  45. etrade_python-1.0.0.dist-info/METADATA +513 -0
  46. etrade_python-1.0.0.dist-info/RECORD +49 -0
  47. etrade_python-1.0.0.dist-info/WHEEL +4 -0
  48. etrade_python-1.0.0.dist-info/entry_points.txt +2 -0
  49. etrade_python-1.0.0.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,513 @@
1
+ Metadata-Version: 2.4
2
+ Name: etrade-python
3
+ Version: 1.0.0
4
+ Summary: An unofficial, typed, async-first E*TRADE API client
5
+ Project-URL: Repository, https://github.com/kevinrider/etrade-python
6
+ Project-URL: Issues, https://github.com/kevinrider/etrade-python/issues
7
+ Project-URL: Changelog, https://github.com/kevinrider/etrade-python/blob/main/CHANGELOG.md
8
+ Author: etrade-python contributors
9
+ License-Expression: Apache-2.0
10
+ License-File: LICENSE
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: httpx<1,>=0.28
21
+ Requires-Dist: keyring<26,>=25
22
+ Requires-Dist: pydantic-settings<3,>=2.7
23
+ Requires-Dist: pydantic<3,>=2.10
24
+ Requires-Dist: typer<1,>=0.20
25
+ Provides-Extra: dev
26
+ Requires-Dist: build<2,>=1.2; extra == 'dev'
27
+ Requires-Dist: pyright<2,>=1.1.400; extra == 'dev'
28
+ Requires-Dist: pytest-asyncio<2,>=1; extra == 'dev'
29
+ Requires-Dist: pytest-cov<8,>=6; extra == 'dev'
30
+ Requires-Dist: pytest<10,>=8.3; extra == 'dev'
31
+ Requires-Dist: ruff<1,>=0.11; extra == 'dev'
32
+ Requires-Dist: twine<7,>=6; extra == 'dev'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # etrade-python
36
+
37
+ An unofficial, typed, async-first Python client for the E*TRADE REST API.
38
+
39
+ `etrade-python` provides typed request and response models, OAuth 1.0a session
40
+ management, and shared async networking for Python applications, CLIs, background
41
+ workers, web services, workflow engines, and notebooks. Requires Python 3.11+.
42
+
43
+ The package is prepared for its first stable release, **1.0.0**. The PyPI
44
+ installation instructions below apply once the release is published.
45
+
46
+ ## Features
47
+
48
+ - Namespaced Accounts, Portfolio, Transactions, Market, Orders, and Alerts services.
49
+ - Async HTTPX transport shared across services, with injectable clients and transports.
50
+ - Pydantic request/response models, Decimal monetary values, and date/datetime fields.
51
+ - Explicit sandbox and production settings; sandbox is the default.
52
+ - OAuth authorization, inactivity renewal, daily expiration, and pluggable credential stores.
53
+ - Separate order preview and placement, validated requests, and an order builder.
54
+ - Pagination helpers, structured exceptions, sanitized diagnostics, and conservative retries.
55
+ - Diagnostic CLI and interactive orders demo.
56
+
57
+ Responses are JSON only. Unknown response fields are discarded rather than exposed
58
+ as an untyped metadata dictionary. Typed models support JSON serialization and schema
59
+ inspection through Pydantic.
60
+
61
+ ## Installation
62
+
63
+ From a source checkout, install into an activated Python 3.11+ virtual environment:
64
+
65
+ ```sh
66
+ python -m pip install .
67
+ ```
68
+
69
+ Once published on PyPI:
70
+
71
+ ```sh
72
+ python -m pip install etrade-python
73
+ ```
74
+
75
+ The distribution name is `etrade-python`; the import package is `etrade_python`.
76
+ The installation also provides the `etrade` command.
77
+
78
+ ## API Credentials and Configuration
79
+
80
+ Obtain a consumer key and consumer secret through the
81
+ [official E*TRADE getting-started guide](https://developer.etrade.com/getting-started).
82
+ Sandbox and production require separate keys. Use credentials issued for the
83
+ configured environment.
84
+
85
+ Export these variables before using the SDK or CLI:
86
+
87
+ ```sh
88
+ export ETRADE_CONSUMER_KEY='your-sandbox-consumer-key'
89
+ export ETRADE_CONSUMER_SECRET='your-sandbox-consumer-secret'
90
+ export ETRADE_ENVIRONMENT=sandbox
91
+ ```
92
+
93
+ `ETRADE_ENVIRONMENT` accepts `sandbox` or `production`. Sandbox is the default;
94
+ production must be selected explicitly. Optional settings are
95
+ `ETRADE_REQUEST_TIMEOUT_SECONDS` (default `30`) and
96
+ `ETRADE_INACTIVITY_BUFFER_SECONDS` (default `300`).
97
+
98
+ `ETradeClient.from_environment()` and the CLI read environment variables. They do
99
+ not automatically load `.env`. For explicit `.env` loading in an application:
100
+
101
+ ```python
102
+ from etrade_python import ETradeClient, ETradeSettings
103
+
104
+ settings = ETradeSettings(_env_file=".env")
105
+ client = ETradeClient(settings)
106
+ ```
107
+
108
+ Copy `.env.example` as a starting point and replace its fake values.
109
+
110
+ ## Authentication
111
+
112
+ Bootstrap authentication using the CLI:
113
+
114
+ ```sh
115
+ etrade auth login
116
+ etrade auth status
117
+ ```
118
+
119
+ Login prints a browser authorization URL. Open it, authorize the application, and
120
+ enter the verifier at the hidden prompt. The CLI exchanges it for access credentials
121
+ and saves them in the system keyring. Use the same environment, consumer key, and
122
+ profile when accessing those credentials from an application.
123
+
124
+ Custom profiles are optional:
125
+
126
+ ```sh
127
+ etrade auth login --profile personal
128
+ etrade auth status --profile personal
129
+ etrade auth renew --profile personal
130
+ etrade auth revoke --profile personal
131
+ ```
132
+
133
+ Pass `profile="personal"` to `ETradeClient(settings, profile="personal")` in SDK
134
+ code. `from_environment()` uses the default profile.
135
+
136
+ E*TRADE tokens become inactive after two hours without requests and expire at
137
+ midnight US Eastern time. The session manager renews locally inactive tokens
138
+ before an API request; expired tokens require a new login. Explicit `auth renew`
139
+ contacts the broker even when the token appears active locally.
140
+ [Official token lifecycle](https://apisb.etrade.com/docs/api/authorization/renew_access_token.html).
141
+
142
+ `auth status` reports a local lifecycle estimate, not broker verification.
143
+
144
+ ## Accounts and Portfolio
145
+
146
+ After logging in with the CLI, save this as a Python script and run it with the
147
+ same environment variables:
148
+
149
+ ```python
150
+ import asyncio
151
+
152
+ from etrade_python import ETradeClient
153
+
154
+
155
+ async def main() -> None:
156
+ async with ETradeClient.from_environment() as client:
157
+ response = await client.accounts.list()
158
+ if not response.accounts:
159
+ print("No accounts returned.")
160
+ return
161
+
162
+ account = response.accounts[0]
163
+ account_id_key = account.account_id_key
164
+ balance = await client.accounts.get_balance(account_id_key)
165
+ portfolio = await client.portfolio.get_positions(account_id_key)
166
+ print(balance.model_dump_json(indent=2))
167
+ print(portfolio.model_dump_json(indent=2))
168
+
169
+
170
+ asyncio.run(main())
171
+ ```
172
+
173
+ Account operations take `account_id_key`, the broker's routing identifier returned
174
+ by account listing, rather than the numeric `account_id`. Output can contain
175
+ sensitive account information; treat it accordingly.
176
+
177
+ ## Market Data and Concurrent Requests
178
+
179
+ Independent requests can run concurrently through the shared async client:
180
+
181
+ ```python
182
+ import asyncio
183
+
184
+ from etrade_python import ETradeClient
185
+
186
+
187
+ async def main() -> None:
188
+ async with ETradeClient.from_environment() as client:
189
+ quote, chain = await asyncio.gather(
190
+ client.market.get_quote("AAPL"),
191
+ client.market.get_option_chain("AAPL"),
192
+ )
193
+ print(quote.model_dump_json(indent=2))
194
+ print(chain.model_dump_json(indent=2))
195
+
196
+ products = await client.market.lookup_product("Bank of America")
197
+ print(products.model_dump_json(indent=2))
198
+
199
+
200
+ asyncio.run(main())
201
+ ```
202
+
203
+ For a specific expiration, use a date returned by the broker rather than guessing:
204
+
205
+ ```python
206
+ import asyncio
207
+
208
+ from etrade_python import ETradeClient, OptionChainRequest
209
+
210
+
211
+ async def main() -> None:
212
+ async with ETradeClient.from_environment() as client:
213
+ response = await client.market.get_option_expirations("AAPL")
214
+ if not response.expiration_dates:
215
+ print("No expirations returned.")
216
+ return
217
+
218
+ expiration = response.expiration_dates[0]
219
+ chain = await client.market.get_option_chain(
220
+ "AAPL",
221
+ OptionChainRequest(
222
+ expiry_year=expiration.year,
223
+ expiry_month=expiration.month,
224
+ expiry_day=expiration.day,
225
+ chain_type="CALLPUT",
226
+ no_of_strikes=5,
227
+ ),
228
+ )
229
+ print(chain.model_dump_json(indent=2))
230
+
231
+
232
+ asyncio.run(main())
233
+ ```
234
+
235
+ ## Pagination
236
+
237
+ Single-page methods return typed response models. For automatic pagination, use
238
+ `portfolio.iter_positions()`, `transactions.list_all()`, and `orders.list_all()`.
239
+ These are async iterators; despite the `list_all` name, they do not eagerly return
240
+ one combined list.
241
+
242
+ ```python
243
+ import asyncio
244
+
245
+ from etrade_python import ETradeClient, TransactionsRequest
246
+
247
+
248
+ async def main() -> None:
249
+ async with ETradeClient.from_environment() as client:
250
+ response = await client.accounts.list()
251
+ if not response.accounts:
252
+ return
253
+ account_id_key = response.accounts[0].account_id_key
254
+
255
+ async for transaction in client.transactions.list_all(
256
+ account_id_key, TransactionsRequest(count=50)
257
+ ):
258
+ print(transaction.model_dump_json())
259
+
260
+
261
+ asyncio.run(main())
262
+ ```
263
+
264
+ Transaction requests default to descending order. Automatic transaction pagination
265
+ removes repeated boundary transactions and requires `count >= 2`; the single-page
266
+ `transactions.list()` method permits `count=1`. Pagination helpers reject repeated
267
+ continuation values instead of looping indefinitely.
268
+
269
+ ## Order Builder and Preview
270
+
271
+ The builder produces the typed requests accepted by the Orders service. This
272
+ example previews an equity limit order; it does not place it:
273
+
274
+ ```python
275
+ import asyncio
276
+ from decimal import Decimal
277
+ from uuid import uuid4
278
+
279
+ from etrade_python import ETradeClient, OrderBuilder
280
+
281
+
282
+ async def main() -> None:
283
+ async with ETradeClient.from_environment() as client:
284
+ response = await client.accounts.list()
285
+ if not response.accounts:
286
+ return
287
+ account_id_key = response.accounts[0].account_id_key
288
+
289
+ builder = (
290
+ OrderBuilder.for_account(account_id_key)
291
+ .client_order_id(uuid4().hex[:20])
292
+ .equity_limit("AAPL", action="BUY", quantity=1, limit_price=Decimal("1.00"))
293
+ )
294
+ preview = await client.orders.preview(account_id_key, builder.build_preview_request())
295
+ print(preview.model_dump_json(indent=2))
296
+
297
+
298
+ asyncio.run(main())
299
+ ```
300
+
301
+ The limit price is illustrative, not a trading recommendation. Preview acceptance
302
+ depends on the account and broker validations.
303
+
304
+ The builder supports equity, single-option, vertical spread, three-leg, iron-condor,
305
+ and buy-write requests. Low-level request models remain available for direct use.
306
+ Preview and placement stay separate: after reviewing an actual preview response,
307
+ pass its IDs to `builder.build_place_request(preview_ids=...)` and submit that request
308
+ with `client.orders.place(account_id_key, request)`. SDK placement methods do not
309
+ provide a CLI-style confirmation prompt; the application must control submission.
310
+
311
+ Changes use `orders.preview_change()` and `orders.place_change()`; cancellation uses
312
+ `orders.cancel()`. Production placement, changes, and cancellations affect real
313
+ brokerage accounts. Order mutations are not automatically retried. If a request
314
+ fails after submission, reconcile its broker outcome before resubmitting.
315
+
316
+ ## Error Handling
317
+
318
+ The library raises structured E*TRADE exceptions rather than exposing raw HTTPX
319
+ status exceptions as its primary API:
320
+
321
+ ```python
322
+ import asyncio
323
+
324
+ from etrade_python import (
325
+ AuthenticationRequired,
326
+ AuthorizationExpired,
327
+ ETradeApiError,
328
+ ETradeClient,
329
+ ETradeError,
330
+ )
331
+
332
+
333
+ async def main() -> None:
334
+ try:
335
+ async with ETradeClient.from_environment() as client:
336
+ quote = await client.market.get_quote("AAPL")
337
+ print(quote.model_dump_json(indent=2))
338
+ except (AuthenticationRequired, AuthorizationExpired):
339
+ print("Run etrade auth login with the configured environment and profile.")
340
+ except ETradeApiError as error:
341
+ print(f"Broker request failed: HTTP {error.status_code}, code {error.broker_code}")
342
+ except ETradeError:
343
+ print("The client could not complete the request.")
344
+
345
+
346
+ asyncio.run(main())
347
+ ```
348
+
349
+ API exceptions expose `status_code`, `broker_code`, `broker_message`, and `request_id`
350
+ when available. Diagnostics redact known request secrets, but broker messages can
351
+ still contain personal information; avoid logging them wholesale. Invalid direct
352
+ Pydantic model construction raises Pydantic validation errors.
353
+
354
+ ## Credential Storage
355
+
356
+ `ETradeClient` defaults to `KeyringCredentialStore`. The operating-system keyring
357
+ backend determines storage protection; there is no automatic plaintext fallback.
358
+ Credentials are isolated by environment, consumer-key SHA-256 fingerprint, and
359
+ profile.
360
+
361
+ To use process-local memory storage:
362
+
363
+ ```python
364
+ from etrade_python import ETradeClient, ETradeSettings
365
+ from etrade_python.auth import MemoryCredentialStore
366
+
367
+ store = MemoryCredentialStore()
368
+ client = ETradeClient(ETradeSettings(), credential_store=store)
369
+ ```
370
+
371
+ Memory storage does not load credentials saved by the CLI and is lost when the
372
+ process exits. Use `client.oauth.get_request_token()`,
373
+ `client.oauth.get_authorization_url()`, and `client.oauth.exchange_verifier()` for
374
+ application-managed authorization, then `await client.session.save(credentials)`.
375
+ Always close the client after use. Applications can implement the async
376
+ `CredentialStore` protocol for other persistence systems.
377
+
378
+ ## Diagnostic CLI and Orders Demo
379
+
380
+ Use `etrade --help` or `etrade COMMAND --help` to inspect available commands.
381
+ Add `--json` to read/preview commands for typed JSON output; it is optional.
382
+
383
+ ```sh
384
+ etrade accounts list
385
+ etrade accounts balance ACCOUNT_ID_KEY
386
+ etrade portfolio positions ACCOUNT_ID_KEY
387
+ etrade transactions list ACCOUNT_ID_KEY --count 50 --json
388
+ etrade transactions get ACCOUNT_ID_KEY TRANSACTION_ID
389
+ etrade market quote AAPL
390
+ etrade market quotes AAPL MSFT
391
+ etrade market lookup "Bank of America"
392
+ etrade market option-expirations AAPL
393
+ etrade market option-chain AAPL
394
+ etrade orders list ACCOUNT_ID_KEY
395
+ etrade alerts list
396
+ etrade alerts get ALERT_ID
397
+ etrade alerts delete ALERT_ID --confirm-delete
398
+ etrade orders demo
399
+ ```
400
+
401
+ The orders demo begins with account selection and supports equity, single-option,
402
+ vertical spread, three-leg, iron-condor, and buy-write scenarios. It retrieves
403
+ expirations and strikes from market data and suggests prices from quotes. Expirations
404
+ appear ten per page, with `n`/`p` navigation; the initial page shows the monthly
405
+ default when one is available. Prices and broker responses still require review.
406
+
407
+ The demo walks through preview, optional placement, change, and cancellation with
408
+ explicit confirmations. File-based order commands are also available:
409
+
410
+ ```sh
411
+ etrade orders preview ACCOUNT_ID_KEY preview-order.json
412
+ etrade orders place ACCOUNT_ID_KEY place-order.json --confirm-live-order
413
+ etrade orders preview-change ACCOUNT_ID_KEY ORDER_ID preview-order.json
414
+ etrade orders place-change ACCOUNT_ID_KEY ORDER_ID place-order.json --confirm-live-order
415
+ etrade orders cancel ACCOUNT_ID_KEY ORDER_ID --confirm-live-order
416
+ ```
417
+
418
+ Order JSON files use the broker request envelope emitted by the request models.
419
+ Account commands print routing identifiers for manual testing; protect their output.
420
+ Login intentionally prints the authorization URL needed for the browser flow.
421
+ Order mutation commands require `--confirm-live-order`, and alert deletion requires
422
+ `--confirm-delete`.
423
+
424
+ ## Development
425
+
426
+ Use uv and the Makefile from the repository root:
427
+
428
+ ```sh
429
+ make install
430
+ make check
431
+ make package-check
432
+ ```
433
+
434
+ `make install` synchronizes the environment and development dependencies.
435
+ `make check` runs lint, formatting checks, type checking, and offline tests.
436
+ `make package-check` builds the wheel/source distribution and validates metadata.
437
+
438
+ Individual targets include `make lint`, `make format`, `make format-check`,
439
+ `make type`, and `make test`. `make venv-reset` deletes `.venv` and recreates it
440
+ with Python 3.12; the library itself supports Python 3.11+. `make build` recreates
441
+ `dist`, and `make clean` removes generated build and cache artifacts.
442
+
443
+ If make is unavailable:
444
+
445
+ ```sh
446
+ uv sync --extra dev
447
+ uv run ruff check .
448
+ uv run ruff format --check .
449
+ uv run pyright --pythonpath .venv/bin/python
450
+ uv run pytest
451
+ uv build
452
+ uv run python -m twine check dist/*
453
+ ```
454
+
455
+ CI checks Python 3.11–3.14, enforces at least 90% combined statement/branch coverage,
456
+ and verifies wheel installation outside the checkout. Push and pull-request CI
457
+ does not publish. A separate release workflow publishes stable GitHub releases
458
+ using PyPI Trusted Publishing once the publisher is configured. See
459
+ [CONTRIBUTING.md](CONTRIBUTING.md) for contribution and package verification instructions.
460
+
461
+ ## API Coverage
462
+
463
+ The documented endpoint families below are implemented and covered by offline
464
+ contract tests.
465
+
466
+ Endpoint paths are relative to `/v1` on the sandbox or production API host.
467
+ OAuth paths are relative to `https://api.etrade.com` for both environments. JSON
468
+ suffixes select response format and do not create separate endpoints.
469
+
470
+ | Family | Official endpoint | Service method | Request | Response |
471
+ | --- | --- | --- | --- | --- |
472
+ | OAuth | [GET /oauth/request_token](https://apisb.etrade.com/docs/api/authorization/request_token.html) | `OAuthClient.get_request_token` | - | RequestToken |
473
+ | OAuth | [GET https://us.etrade.com/e/t/etws/authorize](https://apisb.etrade.com/docs/api/authorization/authorize.html) | `OAuthClient.get_authorization_url` | RequestToken | AuthorizationUrl |
474
+ | OAuth | [GET /oauth/access_token](https://apisb.etrade.com/docs/api/authorization/get_access_token.html) | `OAuthClient.exchange_verifier` | RequestToken + verifier | ETradeCredentials |
475
+ | OAuth | [GET /oauth/renew_access_token](https://apisb.etrade.com/docs/api/authorization/renew_access_token.html) | `OAuthClient.renew_access_token` | ETradeCredentials | RenewalResult |
476
+ | OAuth | [GET /oauth/revoke_access_token](https://apisb.etrade.com/docs/api/authorization/revoke_access_token.html) | `OAuthClient.revoke_access_token` | ETradeCredentials | RevocationResult |
477
+ | Accounts | [GET /accounts/list](https://apisb.etrade.com/docs/api/account/api-account-v1.html) | `accounts.list` | - | AccountListResponse |
478
+ | Accounts | [GET /accounts/{accountIdKey}/balance](https://apisb.etrade.com/docs/api/account/api-balance-v1.html) | `accounts.get_balance` | AccountBalanceRequest | AccountBalanceResponse |
479
+ | Portfolio | [GET /accounts/{accountIdKey}/portfolio](https://apisb.etrade.com/docs/api/account/api-portfolio-v1.html) | `portfolio.get_positions / iter_positions` | PortfolioRequest | PortfolioResponse including PositionLot |
480
+ | Transactions | [GET /accounts/{accountIdKey}/transactions](https://apisb.etrade.com/docs/api/account/api-transaction-v1.html) | `transactions.list` | TransactionsRequest | TransactionsResponse |
481
+ | Transactions | [GET /accounts/{accountIdKey}/transactions/{tranid}](https://apisb.etrade.com/docs/api/account/api-transaction-v1.html) | `transactions.get` | TransactionDetailsRequest | TransactionDetailsResponse |
482
+ | Market | [GET /market/quote/{symbols}](https://apisb.etrade.com/docs/api/market/api-quote-v1.html) | `market.get_quote / get_quotes` | QuotesRequest | Quote / QuotesResponse |
483
+ | Market | [GET /market/lookup/{search}](https://apisb.etrade.com/docs/api/market/api-market-v1.html) | `market.lookup_product` | ProductLookupRequest | ProductLookupResponse |
484
+ | Market | [GET /market/optionexpiredate](https://apisb.etrade.com/docs/api/market/api-market-v1.html) | `market.get_option_expirations` | OptionExpirationsRequest | OptionExpirationsResponse |
485
+ | Market | [GET /market/optionchains](https://apisb.etrade.com/docs/api/market/api-market-v1.html) | `market.get_option_chain` | OptionChainRequest | OptionChainResponse |
486
+ | Orders | [GET /accounts/{accountIdKey}/orders](https://apisb.etrade.com/docs/api/order/api-order-v1.html) | `orders.list / list_all` | OrdersRequest | OrdersResponse |
487
+ | Orders | [POST /accounts/{accountIdKey}/orders/preview](https://apisb.etrade.com/docs/api/order/api-order-v1.html) | `orders.preview` | PreviewOrderRequest | PreviewOrderResponse |
488
+ | Orders | [POST /accounts/{accountIdKey}/orders/place](https://apisb.etrade.com/docs/api/order/api-order-v1.html) | `orders.place` | PlaceOrderRequest | PlaceOrderResponse |
489
+ | Orders | [PUT /accounts/{accountIdKey}/orders/{orderId}/change/preview](https://apisb.etrade.com/docs/api/order/api-order-v1.html) | `orders.preview_change` | PreviewOrderRequest | PreviewOrderResponse |
490
+ | Orders | [PUT /accounts/{accountIdKey}/orders/{orderId}/change/place](https://apisb.etrade.com/docs/api/order/api-order-v1.html) | `orders.place_change` | PlaceOrderRequest | PlaceOrderResponse |
491
+ | Orders | [PUT /accounts/{accountIdKey}/orders/cancel](https://apisb.etrade.com/docs/api/order/api-order-v1.html) | `orders.cancel` | CancelOrderRequest | CancelOrderResponse |
492
+ | Alerts | [GET /user/alerts](https://apisb.etrade.com/docs/api/user/api-alert-v1.html) | `alerts.list` | AlertsRequest | AlertsResponse |
493
+ | Alerts | [GET /user/alerts/{id}](https://apisb.etrade.com/docs/api/user/api-alert-v1.html) | `alerts.get` | AlertDetailsRequest | AlertDetailsResponse |
494
+ | Alerts | [DELETE /user/alerts/{alert_id_list}](https://apisb.etrade.com/docs/api/user/api-alert-v1.html) | `alerts.delete` | alert ID list | DeleteAlertsResponse |
495
+
496
+ ## Safety and License
497
+
498
+ This project is not affiliated with, endorsed by, or supported by Morgan Stanley
499
+ or E*TRADE. It is a software API client, not financial advice.
500
+
501
+ Production trading methods affect real brokerage accounts. Start in sandbox,
502
+ review request details and broker confirmations, and keep secrets and sensitive
503
+ account output out of source control and public logs. Read the
504
+ [security policy](SECURITY.md) for storage, logging, and mutation considerations.
505
+
506
+ Licensed under [Apache-2.0](LICENSE).
507
+
508
+ ## Further Reading
509
+
510
+ - [Official E*TRADE developer documentation](https://developer.etrade.com/)
511
+ - [Changelog](CHANGELOG.md)
512
+ - [Contributing guide](CONTRIBUTING.md)
513
+ - [Security policy](SECURITY.md)
@@ -0,0 +1,49 @@
1
+ etrade_python/__init__.py,sha256=YeTxdrXY3kz_W_njtE5_z4td7wCpUVFavZA2kZyxdsY,5963
2
+ etrade_python/_dates.py,sha256=6I7QmElS3e5jipJSVkY0lrBNed1i9eCIjsMhFPicTlU,4614
3
+ etrade_python/_version.py,sha256=wVzvdZEqZCvsp3GrIZI-Oh8FDnb35FkUIcgt3r4K1U4,94
4
+ etrade_python/client.py,sha256=5I5frcyDDnPfIfmYRYMBnHxsQbqJh1mPufegbDHEe70,3439
5
+ etrade_python/config.py,sha256=JbuPHoGijKHO9eN37WIrWNZaGpxspNBcNj9wIab8oHY,1699
6
+ etrade_python/enums.py,sha256=ashvh8PXge21mUeGj7cJfYuQlxZp5V_vGuiIF4hCjiw,519
7
+ etrade_python/exceptions.py,sha256=2qIZExdQj1VlGCEzUrLCGD6kTwM5Yb02khMiFJiwyg4,1896
8
+ etrade_python/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ etrade_python/accounts/__init__.py,sha256=0KtBaDl7UVin-Gl-qnwKhjBaWpiKU2XsIoLakCv60JM,657
10
+ etrade_python/accounts/models.py,sha256=9gILGHLW6V_8TOoVtgBk-TMRblpog8aC09ma2vNNM8c,9753
11
+ etrade_python/accounts/service.py,sha256=dbs8C_qavZCtGhkPuwSkAa-bK1thwd3viYoA0r1WuBM,4943
12
+ etrade_python/alerts/__init__.py,sha256=aZ3fwW4iKyWFFki6pq5BmSEHkD7he70KnyzI7W0bEuY,473
13
+ etrade_python/alerts/models.py,sha256=-hLI_0WO7wymOIWF3dWjq3royq6minN_Bx_32DM-Te8,5646
14
+ etrade_python/alerts/service.py,sha256=96y9KwMsyMJVipenicS0NlIQ6mgziQv9bnUuDbzcQ_I,5084
15
+ etrade_python/auth/__init__.py,sha256=vtXjjZw8rAP2MBLhBj0csw422DLMUVo-k8YqK3TPiNU,750
16
+ etrade_python/auth/credentials.py,sha256=1yF2lr6Qj2xuBBBnWiZdn2QUIs3qOjSO4NNgC-N27Gc,2873
17
+ etrade_python/auth/oauth.py,sha256=kFrLH83uf-cDe8MJycKNHCaUw8dXpuAn8GJzLNTK4F0,10494
18
+ etrade_python/auth/session.py,sha256=2WdfWkHt6UGgKO6Jn4teDkXwTQJ4fp2dK_kC5258oA8,6226
19
+ etrade_python/auth/stores/__init__.py,sha256=d2cCDnDxeXsBOqmLa0A1lDaQWr_GEzXrTlLqDuVYvmM,318
20
+ etrade_python/auth/stores/base.py,sha256=XXbWAoYUf-MumiPybpAd-jv_8pMZMYxPRlu-FwdQctA,591
21
+ etrade_python/auth/stores/keyring.py,sha256=QWEgEKg-41fbTYMu9RtrdsEFmgO9jAxkMRMCb12LfXI,1909
22
+ etrade_python/auth/stores/memory.py,sha256=lnzjQe-rJgJIL4t-6_QHSizVhFJQv1DFilC8EVKNO3g,645
23
+ etrade_python/cli/__init__.py,sha256=0ouz55BJFQtDyuOsMAIaI-RI0vCWqZfos6OF1lDc_js,38
24
+ etrade_python/cli/app.py,sha256=Hxs1iDI4hMgC6hWyEplgYdKulB1tLpHG_NUfbvpdag0,64833
25
+ etrade_python/market/__init__.py,sha256=uEfAqe1ff4tkpbSk-YNMEhwLn-oVQUK6-_gSFkqM5iU,1296
26
+ etrade_python/market/models.py,sha256=Qumrafwxi5qDymdsU5_idJZHkL50YUVQPI-mlHmGc1g,32501
27
+ etrade_python/market/service.py,sha256=q3vQNzaVo4LG6TiIw_seexvPqJrhMI9HeNGTXZ3cph8,6683
28
+ etrade_python/orders/__init__.py,sha256=xeweUYxQACo98neg1o_XVkv08HS7sHeXui8J3WKYk_w,2264
29
+ etrade_python/orders/builders.py,sha256=FSjfO1gYHrZOyUNmPR5FJAOv7HVnkkUHKobXVQF6zSs,22001
30
+ etrade_python/orders/models.py,sha256=Zxo7evowCVWatIe2X-Di1PN3-cj_CwTWeewwjYE8HM4,40742
31
+ etrade_python/orders/service.py,sha256=3lf-_-_eMDynk7v4N3EgNLsJL6r7-fUiUeo-6_QWnYY,10881
32
+ etrade_python/orders/values.py,sha256=z6BK_Zho0_sKsG5rcDMRP4xyByWrGQREcY1b9pb_zMo,1659
33
+ etrade_python/portfolio/__init__.py,sha256=bYXq3mJac-46ORmd6s7LoM-DpUWNu19cTPlFnRCB6Cw,720
34
+ etrade_python/portfolio/models.py,sha256=GVfjj2wuSoFB1Dygy-diH3uPn8J8uPpYkdJKFlhp1Mw,20118
35
+ etrade_python/portfolio/service.py,sha256=0CbRYSToY9wnB4rf1rfK6zNS4PrNiWGh-jnzqTGzIR4,3968
36
+ etrade_python/transactions/__init__.py,sha256=geOcmt3KHQYQgbPx68-ajD25hnVD_tVicqQNWaJ9jsQ,663
37
+ etrade_python/transactions/models.py,sha256=u1mBMVBzPy4cvKOCsjRQaLWY2xnylWBZb1X_dlDIbg0,7549
38
+ etrade_python/transactions/service.py,sha256=A5k_LLAzioqgmrGR-OH228RBk21BKHUSKJBo3W7clLA,5495
39
+ etrade_python/transport/__init__.py,sha256=VaGqhPNrNnskVEwAgllywxW4pHE_9Kk0K8j5rf7o_T4,342
40
+ etrade_python/transport/auth.py,sha256=eLXwnwdD7K5URBuyf9cdV-I4o2s-EYM7PUXic5sFGXs,669
41
+ etrade_python/transport/http.py,sha256=O56r0q589CE-AoHlOJcykrzq9cvfxtVhg5Ri7R4nwV8,10204
42
+ etrade_python/transport/logging.py,sha256=743RBiSJPxLVM1aacs-nGWP_bV8SvPsBfOoHXTwir28,1129
43
+ etrade_python/transport/response.py,sha256=BxOlKtphuwsdTEpjO-OkEL-Y-0GEaIShHtkMNNQKEPI,8905
44
+ etrade_python/transport/retry.py,sha256=L7KzV-AoLPrnnttfIRGzhSh3U5rpuU8a8mnB_p4v_Z0,2627
45
+ etrade_python-1.0.0.dist-info/METADATA,sha256=U3dh0vFjg9wN05QACd1P8nQyMIo4_2OipsYEJzgkyL4,21795
46
+ etrade_python-1.0.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
47
+ etrade_python-1.0.0.dist-info/entry_points.txt,sha256=f4i6DI09N1yZdkyEiE48FA9ErB_FcvHCZd4Pm6TKukQ,53
48
+ etrade_python-1.0.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
49
+ etrade_python-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ etrade = etrade_python.cli.app:app