tastytrade 10.2.2__py3-none-any.whl → 10.2.3__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.
- tastytrade/__init__.py +1 -1
- tastytrade/session.py +10 -2
- tastytrade/streamer.py +39 -37
- {tastytrade-10.2.2.dist-info → tastytrade-10.2.3.dist-info}/METADATA +1 -1
- {tastytrade-10.2.2.dist-info → tastytrade-10.2.3.dist-info}/RECORD +7 -7
- {tastytrade-10.2.2.dist-info → tastytrade-10.2.3.dist-info}/WHEEL +0 -0
- {tastytrade-10.2.2.dist-info → tastytrade-10.2.3.dist-info}/licenses/LICENSE +0 -0
tastytrade/__init__.py
CHANGED
|
@@ -4,7 +4,7 @@ API_URL = "https://api.tastyworks.com"
|
|
|
4
4
|
BACKTEST_URL = "https://backtester.vast.tastyworks.com"
|
|
5
5
|
CERT_URL = "https://api.cert.tastyworks.com"
|
|
6
6
|
VAST_URL = "https://vast.tastyworks.com"
|
|
7
|
-
VERSION = "10.2.
|
|
7
|
+
VERSION = "10.2.3"
|
|
8
8
|
|
|
9
9
|
__version__ = VERSION
|
|
10
10
|
version_str: str = f"tastyware/tastytrade:v{VERSION}"
|
tastytrade/session.py
CHANGED
|
@@ -578,7 +578,8 @@ class OAuthSession(Session): # pragma: no cover
|
|
|
578
578
|
"""
|
|
579
579
|
Refreshes the acccess token using the stored refresh token.
|
|
580
580
|
"""
|
|
581
|
-
|
|
581
|
+
request = self.sync_client.build_request(
|
|
582
|
+
"POST",
|
|
582
583
|
"/oauth/token",
|
|
583
584
|
json={
|
|
584
585
|
"grant_type": "refresh_token",
|
|
@@ -586,6 +587,9 @@ class OAuthSession(Session): # pragma: no cover
|
|
|
586
587
|
"refresh_token": self.refresh_token,
|
|
587
588
|
},
|
|
588
589
|
)
|
|
590
|
+
# Don't send the Authorization header for this request
|
|
591
|
+
request.headers.pop("Authorization", None)
|
|
592
|
+
response = self.sync_client.send(request)
|
|
589
593
|
validate_response(response)
|
|
590
594
|
data = response.json()
|
|
591
595
|
# update the relevant tokens
|
|
@@ -602,7 +606,8 @@ class OAuthSession(Session): # pragma: no cover
|
|
|
602
606
|
"""
|
|
603
607
|
Refreshes the acccess token using the stored refresh token.
|
|
604
608
|
"""
|
|
605
|
-
|
|
609
|
+
request = self.async_client.build_request(
|
|
610
|
+
"POST",
|
|
606
611
|
"/oauth/token",
|
|
607
612
|
json={
|
|
608
613
|
"grant_type": "refresh_token",
|
|
@@ -610,6 +615,9 @@ class OAuthSession(Session): # pragma: no cover
|
|
|
610
615
|
"refresh_token": self.refresh_token,
|
|
611
616
|
},
|
|
612
617
|
)
|
|
618
|
+
# Don't send the Authorization header for this request
|
|
619
|
+
request.headers.pop("Authorization", None)
|
|
620
|
+
response = await self.async_client.send(request)
|
|
613
621
|
validate_response(response)
|
|
614
622
|
data = response.json()
|
|
615
623
|
# update the relevant tokens
|
tastytrade/streamer.py
CHANGED
|
@@ -278,17 +278,18 @@ class AlertStreamer:
|
|
|
278
278
|
"""
|
|
279
279
|
Closes the websocket connection and cancels the pending tasks.
|
|
280
280
|
"""
|
|
281
|
-
self._closing
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
self._heartbeat_task.
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
self._reconnect_task.
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
281
|
+
if not self._closing: # can only be called once
|
|
282
|
+
self._closing = True
|
|
283
|
+
self._connect_task.cancel()
|
|
284
|
+
tasks = [self._connect_task]
|
|
285
|
+
if self._heartbeat_task and not self._heartbeat_task.done():
|
|
286
|
+
self._heartbeat_task.cancel()
|
|
287
|
+
tasks.append(self._heartbeat_task)
|
|
288
|
+
if self._reconnect_task and not self._reconnect_task.done():
|
|
289
|
+
self._reconnect_task.cancel()
|
|
290
|
+
tasks.append(self._reconnect_task)
|
|
291
|
+
await asyncio.gather(*tasks)
|
|
292
|
+
await self._websocket.wait_closed() # type: ignore
|
|
292
293
|
|
|
293
294
|
async def _connect(self) -> None:
|
|
294
295
|
"""
|
|
@@ -316,9 +317,7 @@ class AlertStreamer:
|
|
|
316
317
|
logger.error(f"Websocket connection closed with {e}")
|
|
317
318
|
except asyncio.CancelledError:
|
|
318
319
|
logger.debug("Websocket interrupted, cancelling main loop.")
|
|
319
|
-
|
|
320
|
-
await self.close()
|
|
321
|
-
return
|
|
320
|
+
return await self.close()
|
|
322
321
|
finally:
|
|
323
322
|
asyncio.create_task(self.disconnect_fn(self, *self.disconnect_args))
|
|
324
323
|
logger.debug("Websocket connection closed, retrying...")
|
|
@@ -336,9 +335,12 @@ class AlertStreamer:
|
|
|
336
335
|
the type of alert to listen for, should be of :any:`AlertType`
|
|
337
336
|
"""
|
|
338
337
|
cls_str = next(k for k, v in MAP_ALERTS.items() if v == alert_class)
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
338
|
+
try:
|
|
339
|
+
while True:
|
|
340
|
+
item = await self._queues[cls_str].get()
|
|
341
|
+
yield cast(T, item)
|
|
342
|
+
except GeneratorExit: # no cleanup needed
|
|
343
|
+
pass
|
|
342
344
|
|
|
343
345
|
async def _map_message(self, type_str: str, data: dict[str, Any]) -> None:
|
|
344
346
|
"""
|
|
@@ -515,17 +517,18 @@ class DXLinkStreamer:
|
|
|
515
517
|
"""
|
|
516
518
|
Closes the websocket connection and cancels the heartbeat task.
|
|
517
519
|
"""
|
|
518
|
-
self._closing
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
self._heartbeat_task
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
self._reconnect_task.
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
520
|
+
if not self._closing: # can only be called once
|
|
521
|
+
self._closing = True
|
|
522
|
+
self._connect_task.cancel()
|
|
523
|
+
tasks = [self._connect_task]
|
|
524
|
+
if self._heartbeat_task:
|
|
525
|
+
self._heartbeat_task.cancel()
|
|
526
|
+
tasks.append(self._heartbeat_task)
|
|
527
|
+
if self._reconnect_task is not None and not self._reconnect_task.done():
|
|
528
|
+
self._reconnect_task.cancel()
|
|
529
|
+
tasks.append(self._reconnect_task)
|
|
530
|
+
await asyncio.gather(*tasks)
|
|
531
|
+
await self._websocket.wait_closed()
|
|
529
532
|
|
|
530
533
|
async def _connect(self) -> None:
|
|
531
534
|
"""
|
|
@@ -592,8 +595,7 @@ class DXLinkStreamer:
|
|
|
592
595
|
pass
|
|
593
596
|
elif message["type"] == "ERROR":
|
|
594
597
|
logger.error(f"Fatal streamer error: {message['message']}")
|
|
595
|
-
await self.close()
|
|
596
|
-
return
|
|
598
|
+
return await self.close()
|
|
597
599
|
else:
|
|
598
600
|
logger.error(f"Unknown message: {message}")
|
|
599
601
|
except ConnectionClosed as e:
|
|
@@ -603,13 +605,10 @@ class DXLinkStreamer:
|
|
|
603
605
|
"Subscription message too long! Try reducing the number of "
|
|
604
606
|
"symbols."
|
|
605
607
|
)
|
|
606
|
-
await self.close()
|
|
607
|
-
return
|
|
608
|
+
return await self.close()
|
|
608
609
|
except asyncio.CancelledError:
|
|
609
610
|
logger.debug("Websocket interrupted, cancelling main loop.")
|
|
610
|
-
|
|
611
|
-
await self.close()
|
|
612
|
-
return
|
|
611
|
+
return await self.close()
|
|
613
612
|
finally:
|
|
614
613
|
asyncio.create_task(self.disconnect_fn(self, *self.disconnect_args))
|
|
615
614
|
logger.debug("Websocket connection closed, retrying...")
|
|
@@ -645,8 +644,11 @@ class DXLinkStreamer:
|
|
|
645
644
|
:param event_class:
|
|
646
645
|
the type of alert to listen for, should be of :any:`EventType`
|
|
647
646
|
"""
|
|
648
|
-
|
|
649
|
-
|
|
647
|
+
try:
|
|
648
|
+
while True:
|
|
649
|
+
yield await self._queues[MAP_EVENTS_REVERSE[event_class]].get() # type: ignore
|
|
650
|
+
except GeneratorExit: # no cleanup needed
|
|
651
|
+
pass
|
|
650
652
|
|
|
651
653
|
def get_event_nowait(self, event_class: type[U]) -> Optional[U]:
|
|
652
654
|
"""
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
tastytrade/__init__.py,sha256=
|
|
1
|
+
tastytrade/__init__.py,sha256=C1Ziu6t5GQoRBAP9TW_HtjES_m6HT3cJqZK0hBuOV3s,581
|
|
2
2
|
tastytrade/account.py,sha256=zjeS3_snMh7QT21NrjPjJQ5RBPChdgHF3w1lMggdAw8,63578
|
|
3
3
|
tastytrade/backtest.py,sha256=-IqzxT44d9rGpdCirEj2Kbcl0AaiBOqi9pELHHW6cY8,7898
|
|
4
4
|
tastytrade/instruments.py,sha256=DX8gc81xhkKRRgoL7-g2aWXo_WX30N_3SmRSuYMZBxM,47062
|
|
@@ -8,8 +8,8 @@ tastytrade/metrics.py,sha256=yKZ1EoiQgCLEfdTF-sC9U_pgpeG27Bq717I-FQg1RZc,7256
|
|
|
8
8
|
tastytrade/order.py,sha256=C7Eyn2uDCY5Ss3AG5xk5mnHu1W58P1Ji7pJEMAHHWiU,15107
|
|
9
9
|
tastytrade/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
tastytrade/search.py,sha256=LdoVEhiYNvtolXlf_jAVZUtA2ymUWOvHMhQxJxuVt_A,1529
|
|
11
|
-
tastytrade/session.py,sha256=
|
|
12
|
-
tastytrade/streamer.py,sha256
|
|
11
|
+
tastytrade/session.py,sha256=SOl4RLm1JAZTlLM0w8iR94bJPNWejh1MXchcbrIhG-4,21109
|
|
12
|
+
tastytrade/streamer.py,sha256=-xLVwjB5ozgATZXfibJQIXaZNbz8sD696MkjoHVR_4A,32983
|
|
13
13
|
tastytrade/utils.py,sha256=yUWSEux3XrDTOB184_YdDEuwIufITcnH5eUYXT38ukM,9702
|
|
14
14
|
tastytrade/watchlists.py,sha256=rpZmtl-jGJVNXT_L9oD3khwiKKUy-0ilAixkMNC11uI,8731
|
|
15
15
|
tastytrade/dxfeed/__init__.py,sha256=GmC0aKtiUjs7aqbX7PeqMaROxqalwzHOnJOMJn8TaZk,458
|
|
@@ -23,7 +23,7 @@ tastytrade/dxfeed/theoprice.py,sha256=L5aH--F_6xLZCSYZ4APpzlihbW0-cYEwRdeGVI-aNa
|
|
|
23
23
|
tastytrade/dxfeed/timeandsale.py,sha256=QuMFoccq8x3c2y6s3DnwBNIVTrLS6OPqV6GmCNoXQEQ,1903
|
|
24
24
|
tastytrade/dxfeed/trade.py,sha256=qNo4oKb7iq0Opoq3FCBEUUcGGF6udda1bD0eKQVty_0,1402
|
|
25
25
|
tastytrade/dxfeed/underlying.py,sha256=YYqJNlmrlt6Kpg0F6voQ18g60obXiYTVlroXirBWPR8,1226
|
|
26
|
-
tastytrade-10.2.
|
|
27
|
-
tastytrade-10.2.
|
|
28
|
-
tastytrade-10.2.
|
|
29
|
-
tastytrade-10.2.
|
|
26
|
+
tastytrade-10.2.3.dist-info/METADATA,sha256=0ehiijPEx7V1hDLPuvpJJ8f8vD42eNvOgTqSuiCvS7c,10903
|
|
27
|
+
tastytrade-10.2.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
28
|
+
tastytrade-10.2.3.dist-info/licenses/LICENSE,sha256=enBkMN4OsfLt6Z_AsrGC7u5dAJkCEODnoN7BwMCzSfc,1072
|
|
29
|
+
tastytrade-10.2.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|