tastytrade 11.0.3__tar.gz → 11.0.4__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.
Files changed (82) hide show
  1. {tastytrade-11.0.3 → tastytrade-11.0.4}/PKG-INFO +1 -1
  2. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/sessions.rst +0 -9
  3. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/__init__.py +1 -1
  4. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/order.py +4 -0
  5. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/session.py +9 -11
  6. {tastytrade-11.0.3 → tastytrade-11.0.4}/uv.lock +5 -3
  7. tastytrade-11.0.3/tastytrade/oauth.py +0 -129
  8. tastytrade-11.0.3/tmp.py +0 -32
  9. {tastytrade-11.0.3 → tastytrade-11.0.4}/.github/CONTRIBUTING.md +0 -0
  10. {tastytrade-11.0.3 → tastytrade-11.0.4}/.github/FUNDING.yml +0 -0
  11. {tastytrade-11.0.3 → tastytrade-11.0.4}/.github/pull_request_template.md +0 -0
  12. {tastytrade-11.0.3 → tastytrade-11.0.4}/.github/workflows/python-app.yml +0 -0
  13. {tastytrade-11.0.3 → tastytrade-11.0.4}/.github/workflows/python-publish-test.yml +0 -0
  14. {tastytrade-11.0.3 → tastytrade-11.0.4}/.github/workflows/python-publish.yml +0 -0
  15. {tastytrade-11.0.3 → tastytrade-11.0.4}/.gitignore +0 -0
  16. {tastytrade-11.0.3 → tastytrade-11.0.4}/.python-version +0 -0
  17. {tastytrade-11.0.3 → tastytrade-11.0.4}/.readthedocs.yaml +0 -0
  18. {tastytrade-11.0.3 → tastytrade-11.0.4}/LICENSE +0 -0
  19. {tastytrade-11.0.3 → tastytrade-11.0.4}/Makefile +0 -0
  20. {tastytrade-11.0.3 → tastytrade-11.0.4}/README.md +0 -0
  21. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/Makefile +0 -0
  22. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/account-streamer.rst +0 -0
  23. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/accounts.rst +0 -0
  24. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/api/account.rst +0 -0
  25. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/api/dxfeed.rst +0 -0
  26. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/api/instruments.rst +0 -0
  27. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/api/market-data.rst +0 -0
  28. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/api/market-sessions.rst +0 -0
  29. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/api/metrics.rst +0 -0
  30. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/api/order.rst +0 -0
  31. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/api/search.rst +0 -0
  32. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/api/session.rst +0 -0
  33. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/api/streamer.rst +0 -0
  34. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/api/utils.rst +0 -0
  35. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/api/watchlists.rst +0 -0
  36. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/conf.py +0 -0
  37. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/data-streamer.rst +0 -0
  38. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/img/netliq.png +0 -0
  39. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/index.rst +0 -0
  40. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/installation.rst +0 -0
  41. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/instruments.rst +0 -0
  42. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/make.bat +0 -0
  43. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/market-data.rst +0 -0
  44. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/market-sessions.rst +0 -0
  45. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/orders.rst +0 -0
  46. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/sync-async.rst +0 -0
  47. {tastytrade-11.0.3 → tastytrade-11.0.4}/docs/watchlists.rst +0 -0
  48. {tastytrade-11.0.3 → tastytrade-11.0.4}/pyproject.toml +0 -0
  49. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/account.py +0 -0
  50. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/dxfeed/__init__.py +0 -0
  51. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/dxfeed/candle.py +0 -0
  52. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/dxfeed/event.py +0 -0
  53. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/dxfeed/greeks.py +0 -0
  54. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/dxfeed/profile.py +0 -0
  55. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/dxfeed/quote.py +0 -0
  56. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/dxfeed/summary.py +0 -0
  57. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/dxfeed/theoprice.py +0 -0
  58. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/dxfeed/timeandsale.py +0 -0
  59. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/dxfeed/trade.py +0 -0
  60. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/dxfeed/underlying.py +0 -0
  61. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/instruments.py +0 -0
  62. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/market_data.py +0 -0
  63. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/market_sessions.py +0 -0
  64. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/metrics.py +0 -0
  65. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/py.typed +0 -0
  66. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/search.py +0 -0
  67. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/streamer.py +0 -0
  68. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/utils.py +0 -0
  69. {tastytrade-11.0.3 → tastytrade-11.0.4}/tastytrade/watchlists.py +0 -0
  70. {tastytrade-11.0.3 → tastytrade-11.0.4}/tests/__init__.py +0 -0
  71. {tastytrade-11.0.3 → tastytrade-11.0.4}/tests/conftest.py +0 -0
  72. {tastytrade-11.0.3 → tastytrade-11.0.4}/tests/test_account.py +0 -0
  73. {tastytrade-11.0.3 → tastytrade-11.0.4}/tests/test_dxfeed.py +0 -0
  74. {tastytrade-11.0.3 → tastytrade-11.0.4}/tests/test_instruments.py +0 -0
  75. {tastytrade-11.0.3 → tastytrade-11.0.4}/tests/test_market_data.py +0 -0
  76. {tastytrade-11.0.3 → tastytrade-11.0.4}/tests/test_market_sessions.py +0 -0
  77. {tastytrade-11.0.3 → tastytrade-11.0.4}/tests/test_metrics.py +0 -0
  78. {tastytrade-11.0.3 → tastytrade-11.0.4}/tests/test_search.py +0 -0
  79. {tastytrade-11.0.3 → tastytrade-11.0.4}/tests/test_session.py +0 -0
  80. {tastytrade-11.0.3 → tastytrade-11.0.4}/tests/test_streamer.py +0 -0
  81. {tastytrade-11.0.3 → tastytrade-11.0.4}/tests/test_utils.py +0 -0
  82. {tastytrade-11.0.3 → tastytrade-11.0.4}/tests/test_watchlists.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tastytrade
3
- Version: 11.0.3
3
+ Version: 11.0.4
4
4
  Summary: An unofficial, sync/async SDK for Tastytrade!
5
5
  Project-URL: Homepage, https://github.com/tastyware/tastytrade
6
6
  Project-URL: Documentation, https://tastyworks-api.rtfd.io
@@ -13,15 +13,6 @@ Generating an initial refresh token
13
13
 
14
14
  In order to generate an initial refresh token, you have two options. The easiest way is to simply generate one from Tastytrade's website: go to OAuth Applications > Manage > Create Grant to get a new refresh token, **which you should also save**.
15
15
 
16
- The other option (which is actually the only option for sandbox accounts) is to run this helper code:
17
-
18
- .. code-block:: python
19
-
20
- from tastytrade.oauth import login
21
- login(is_test=True)
22
-
23
- This will open up a web interface in your browser where you'll be prompted to paste your client ID and client secret. These credentials will then be used to connect your application to Tastytrade. After following the steps in your browser, you should see your new refresh token in the browser and in the console.
24
-
25
16
  At this point, OAuth is now setup correctly! Doing these steps once is sufficient for **indefinite usage** of ``Session`` for authentication to the API, since refresh tokens never expire. From now on you can simply authenticate with your client secret and refresh token.
26
17
 
27
18
  Creating a session
@@ -4,7 +4,7 @@ API_URL = "https://api.tastyworks.com"
4
4
  API_VERSION = "20251101"
5
5
  CERT_URL = "https://api.cert.tastyworks.com"
6
6
  VAST_URL = "https://vast.tastyworks.com"
7
- VERSION = "11.0.3"
7
+ VERSION = "11.0.4"
8
8
 
9
9
  __version__ = VERSION
10
10
  version_str: str = f"tastyware/tastytrade:v{VERSION}"
@@ -254,6 +254,8 @@ class NewOrder(TastytradeData):
254
254
  preflight_id: str | None = None
255
255
  rules: OrderRule | None = None
256
256
  advanced_instructions: AdvancedInstructions | None = None
257
+ #: External identifier for the order, used to track orders across systems
258
+ external_identifier: str | None = None
257
259
 
258
260
  @computed_field # type: ignore[misc]
259
261
  @property
@@ -330,6 +332,8 @@ class PlacedOrder(TastytradeData):
330
332
  preflight_id: str | int | None = None
331
333
  order_rule: OrderRule | None = None
332
334
  source: str | None = None
335
+ #: External identifier for the order, used to track orders across systems
336
+ external_identifier: str | None = None
333
337
 
334
338
  @model_validator(mode="before")
335
339
  @classmethod
@@ -9,8 +9,8 @@ from typing_extensions import Self
9
9
 
10
10
  from tastytrade import API_URL, API_VERSION, CERT_URL, logger
11
11
  from tastytrade.utils import (
12
- TZ,
13
12
  TastytradeData,
13
+ now_in_new_york,
14
14
  validate_and_parse,
15
15
  validate_response,
16
16
  )
@@ -274,11 +274,9 @@ class Session:
274
274
  #: Refresh token for the user
275
275
  self.refresh_token = refresh_token
276
276
  # The headers to use for API requests
277
- headers = {
278
- "Accept": "application/json",
279
- "Accept-Version": API_VERSION,
280
- "Content-Type": "application/json",
281
- }
277
+ headers = {"Accept": "application/json", "Content-Type": "application/json"}
278
+ if not is_test: # not accepted in sandbox
279
+ headers["Accept-Version"] = API_VERSION
282
280
  #: httpx client for sync requests
283
281
  self.sync_client = Client(
284
282
  base_url=(CERT_URL if is_test else API_URL), headers=headers, proxy=proxy
@@ -288,7 +286,7 @@ class Session:
288
286
  base_url=self.sync_client.base_url, headers=headers, proxy=proxy
289
287
  )
290
288
  #: expiration for streamer token
291
- self.streamer_expiration = datetime.now(TZ)
289
+ self.streamer_expiration = now_in_new_york()
292
290
  self.refresh()
293
291
 
294
292
  def _streamer_refresh(self) -> None:
@@ -325,14 +323,14 @@ class Session:
325
323
  self.session_token = data["access_token"]
326
324
  token_lifetime: int = data.get("expires_in", 900)
327
325
  #: expiration for session token
328
- self.session_expiration = datetime.now(TZ) + timedelta(seconds=token_lifetime)
326
+ self.session_expiration = now_in_new_york() + timedelta(seconds=token_lifetime)
329
327
  logger.debug(f"Refreshed token, expires in {token_lifetime}ms")
330
328
  auth_headers = {"Authorization": f"Bearer {self.session_token}"}
331
329
  # update the httpx clients with the new token
332
330
  self.sync_client.headers.update(auth_headers)
333
331
  self.async_client.headers.update(auth_headers)
334
332
  # update the streamer token if necessary
335
- if self.streamer_expiration < self.session_expiration:
333
+ if not self.is_test and self.streamer_expiration < self.session_expiration:
336
334
  self._streamer_refresh()
337
335
 
338
336
  async def a_refresh(self) -> None:
@@ -357,14 +355,14 @@ class Session:
357
355
  # update the relevant tokens
358
356
  self.session_token = data["access_token"]
359
357
  token_lifetime: int = data.get("expires_in", 900)
360
- self.session_expiration = datetime.now(TZ) + timedelta(token_lifetime)
358
+ self.session_expiration = now_in_new_york() + timedelta(token_lifetime)
361
359
  logger.debug(f"Refreshed token, expires in {token_lifetime}ms")
362
360
  auth_headers = {"Authorization": f"Bearer {self.session_token}"}
363
361
  # update the httpx clients with the new token
364
362
  self.sync_client.headers.update(auth_headers)
365
363
  self.async_client.headers.update(auth_headers)
366
364
  # update the streamer token if necessary
367
- if self.streamer_expiration < self.session_expiration:
365
+ if not self.is_test and self.streamer_expiration < self.session_expiration:
368
366
  # Pull streamer tokens and urls
369
367
  data = await self._a_get("/api-quote-tokens")
370
368
  # Auth token for dxfeed websocket
@@ -1368,15 +1368,15 @@ wheels = [
1368
1368
 
1369
1369
  [[package]]
1370
1370
  name = "pyright"
1371
- version = "1.1.406"
1371
+ version = "1.1.407"
1372
1372
  source = { registry = "https://pypi.org/simple" }
1373
1373
  dependencies = [
1374
1374
  { name = "nodeenv" },
1375
1375
  { name = "typing-extensions" },
1376
1376
  ]
1377
- sdist = { url = "https://files.pythonhosted.org/packages/f7/16/6b4fbdd1fef59a0292cbb99f790b44983e390321eccbc5921b4d161da5d1/pyright-1.1.406.tar.gz", hash = "sha256:c4872bc58c9643dac09e8a2e74d472c62036910b3bd37a32813989ef7576ea2c", size = 4113151, upload-time = "2025-10-02T01:04:45.488Z" }
1377
+ sdist = { url = "https://files.pythonhosted.org/packages/a6/1b/0aa08ee42948b61745ac5b5b5ccaec4669e8884b53d31c8ec20b2fcd6b6f/pyright-1.1.407.tar.gz", hash = "sha256:099674dba5c10489832d4a4b2d302636152a9a42d317986c38474c76fe562262", size = 4122872, upload-time = "2025-10-24T23:17:15.145Z" }
1378
1378
  wheels = [
1379
- { url = "https://files.pythonhosted.org/packages/f6/a2/e309afbb459f50507103793aaef85ca4348b66814c86bc73908bdeb66d12/pyright-1.1.406-py3-none-any.whl", hash = "sha256:1d81fb43c2407bf566e97e57abb01c811973fdb21b2df8df59f870f688bdca71", size = 5980982, upload-time = "2025-10-02T01:04:43.137Z" },
1379
+ { url = "https://files.pythonhosted.org/packages/dc/93/b69052907d032b00c40cb656d21438ec00b3a471733de137a3f65a49a0a0/pyright-1.1.407-py3-none-any.whl", hash = "sha256:6dd419f54fcc13f03b52285796d65e639786373f433e243f8b94cf93a7444d21", size = 5997008, upload-time = "2025-10-24T23:17:13.159Z" },
1380
1380
  ]
1381
1381
 
1382
1382
  [[package]]
@@ -1549,6 +1549,8 @@ wheels = [
1549
1549
  { url = "https://files.pythonhosted.org/packages/42/cd/85b422d24ee2096eaf6faa360c95ef9bdb59097d19b9624cebce4dd9bc2a/ruamel.yaml.clib-0.2.14-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:808c7190a0fe7ae7014c42f73897cf8e9ef14ff3aa533450e51b1e72ec5239ad", size = 725028, upload-time = "2025-09-22T19:51:19.782Z" },
1550
1550
  { url = "https://files.pythonhosted.org/packages/4d/ac/99e6e0ea2584f84f447069d0187fe411e9b5deb7e3ddecda25001cfc7a95/ruamel.yaml.clib-0.2.14-cp39-cp39-win32.whl", hash = "sha256:6d5472f63a31b042aadf5ed28dd3ef0523da49ac17f0463e10fda9c4a2773352", size = 100915, upload-time = "2025-09-22T19:51:21.764Z" },
1551
1551
  { url = "https://files.pythonhosted.org/packages/5d/8d/846e43369658958c99d959bb7774136fff9210f9017d91a4277818ceafbf/ruamel.yaml.clib-0.2.14-cp39-cp39-win_amd64.whl", hash = "sha256:8dd3c2cc49caa7a8d64b67146462aed6723a0495e44bf0aa0a2e94beaa8432f6", size = 118706, upload-time = "2025-09-22T19:51:20.878Z" },
1552
+ { url = "https://files.pythonhosted.org/packages/e7/cd/150fdb96b8fab27fe08d8a59fe67554568727981806e6bc2677a16081ec7/ruamel_yaml_clib-0.2.14-cp314-cp314-win32.whl", hash = "sha256:9b4104bf43ca0cd4e6f738cb86326a3b2f6eef00f417bd1e7efb7bdffe74c539", size = 102394, upload-time = "2025-11-14T21:57:36.703Z" },
1553
+ { url = "https://files.pythonhosted.org/packages/bd/e6/a3fa40084558c7e1dc9546385f22a93949c890a8b2e445b2ba43935f51da/ruamel_yaml_clib-0.2.14-cp314-cp314-win_amd64.whl", hash = "sha256:13997d7d354a9890ea1ec5937a219817464e5cc344805b37671562a401ca3008", size = 122673, upload-time = "2025-11-14T21:57:38.177Z" },
1552
1554
  ]
1553
1555
 
1554
1556
  [[package]]
@@ -1,129 +0,0 @@
1
- import re
2
- import webbrowser
3
- from http.server import BaseHTTPRequestHandler, HTTPServer
4
- from urllib.parse import parse_qs
5
-
6
- import httpx
7
-
8
- PORT = 8000
9
- REDIRECT_URI = f"http://localhost:{PORT}"
10
- SCOPES = ["read", "trade", "openid"]
11
-
12
- authorize_url = "https://my.tastytrade.com/auth.html"
13
- token_url = "https://api.tastyworks.com/oauth/token"
14
- client_id = ""
15
- client_secret = ""
16
-
17
-
18
- root_page = """
19
- <!DOCTYPE html>
20
- <html lang="en-us">
21
- <head>
22
- <meta charset="utf-8">
23
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
24
- <title>OAuth Setup</title>
25
- <!-- Favicon -->
26
- <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
27
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
28
- rel="stylesheet"
29
- integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
30
- crossorigin="anonymous">
31
- </head>
32
- <body>
33
- <div class="container position-absolute top-50 start-50 translate-middle"
34
- style="width: 400px">
35
- <form method="POST">
36
- <div class="row mb-3">
37
- <input type="text"
38
- required
39
- placeholder="Client ID"
40
- name="client_id"
41
- class="form-control">
42
- </div>
43
- <div class="row mb-3">
44
- <input type="password"
45
- required
46
- placeholder="Client Secret"
47
- name="client_secret"
48
- class="form-control">
49
- </div>
50
- <div class="row mb-3">
51
- <button type="submit" class="btn btn-success">Connect</button>
52
- </div>
53
- </form>
54
- </div>
55
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
56
- integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
57
- crossorigin="anonymous"></script>
58
- </body>
59
- </html>
60
- """.encode()
61
-
62
-
63
- class RequestHandler(BaseHTTPRequestHandler):
64
- def do_POST(self) -> None:
65
- global client_id, client_secret
66
- content_length = int(self.headers["Content-Length"])
67
- raw = self.rfile.read(content_length)
68
- data = parse_qs(raw.decode("utf-8"))
69
- client_id = data["client_id"][0]
70
- client_secret = data["client_secret"][0]
71
-
72
- # Redirect to login page using API key submitted by user
73
- self.send_response(302)
74
- query_string = "&".join(
75
- [
76
- "response_type=code",
77
- f"redirect_uri={REDIRECT_URI}",
78
- f"client_id={data['client_id'][0]}",
79
- f"scope={' '.join(SCOPES)}",
80
- ]
81
- )
82
- url = f"{authorize_url}?{query_string}"
83
- self.send_header("Location", url)
84
- self.end_headers()
85
-
86
- def do_GET(self) -> None:
87
- global client_id, client_secret
88
- # Serve root page with sign in link
89
- if self.path == "/":
90
- self.send_response(200)
91
- self.send_header("Content-type", "text/html; charset=utf-8")
92
- self.end_headers()
93
- self.wfile.write(root_page)
94
- else:
95
- # Check if query path contains case insensitive "code="
96
- code_match = re.search(r"code=(.+)", self.path, re.I)
97
- if code_match and client_id and client_secret:
98
- user_auth_code = code_match[1]
99
- post_data = {
100
- "grant_type": "authorization_code",
101
- "client_id": client_id,
102
- "client_secret": client_secret,
103
- "redirect_uri": REDIRECT_URI,
104
- "code": user_auth_code,
105
- }
106
- response = httpx.post(token_url, data=post_data)
107
- token_access = response.json()
108
- refresh_token: str = token_access["refresh_token"]
109
- print(refresh_token)
110
-
111
- self.send_response(200)
112
- self.send_header("Content-type", "text/html; charset=utf-8")
113
- self.end_headers()
114
- self.wfile.write(refresh_token.encode())
115
-
116
-
117
- def login(is_test: bool = False) -> None:
118
- """
119
- Starts a local HTTP server and opens the browser to OAuth login.
120
- Designed for one-time use to get a refresh token.
121
- """
122
- global authorize_url, token_url
123
- if is_test:
124
- authorize_url = "https://cert-my.staging-tasty.works/auth.html"
125
- token_url = "https://api.cert.tastyworks.com/oauth/token"
126
- httpd = HTTPServer(("", PORT), RequestHandler)
127
- print(f"Opening url: {REDIRECT_URI}")
128
- webbrowser.open(REDIRECT_URI)
129
- httpd.serve_forever()
tastytrade-11.0.3/tmp.py DELETED
@@ -1,32 +0,0 @@
1
- import asyncio
2
- import os
3
- from datetime import date, datetime, time
4
-
5
- import pandas as pd
6
-
7
- from tastytrade import Session
8
- from tastytrade.dxfeed.candle import Candle
9
- from tastytrade.streamer import DXLinkStreamer
10
- from tastytrade.utils import TZ
11
-
12
- session = Session(os.environ["TT_SECRET"], os.environ["TT_REFRESH"])
13
-
14
-
15
- async def main():
16
- async with DXLinkStreamer(session) as streamer:
17
- start_time = datetime.combine(date(2025, 11, 7), time(9, 30), tzinfo=TZ)
18
- ts = round(start_time.timestamp() * 1000)
19
- await streamer.subscribe_candle(["DIA"], "5s", start_time=start_time)
20
- candles: list[Candle] = []
21
- async for candle in streamer.listen(Candle):
22
- candles.append(candle)
23
- if candle.time <= ts:
24
- break
25
- candles.sort(key=lambda c: c.time)
26
- df = pd.DataFrame([c.model_dump() for c in candles])
27
- df = df[["time", "open", "high", "low", "close"]]
28
- print(df)
29
-
30
-
31
- if __name__ == "__main__":
32
- asyncio.run(main())
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes