tastytrade 11.0.5__py3-none-any.whl → 11.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.
- tastytrade/__init__.py +1 -2
- tastytrade/account.py +0 -171
- tastytrade/market_sessions.py +19 -0
- tastytrade/order.py +3 -120
- tastytrade/session.py +5 -12
- tastytrade/streamer.py +2 -9
- tastytrade/utils.py +17 -0
- {tastytrade-11.0.5.dist-info → tastytrade-11.1.0.dist-info}/METADATA +1 -1
- {tastytrade-11.0.5.dist-info → tastytrade-11.1.0.dist-info}/RECORD +11 -11
- {tastytrade-11.0.5.dist-info → tastytrade-11.1.0.dist-info}/WHEEL +0 -0
- {tastytrade-11.0.5.dist-info → tastytrade-11.1.0.dist-info}/licenses/LICENSE +0 -0
tastytrade/__init__.py
CHANGED
|
@@ -3,8 +3,7 @@ import logging
|
|
|
3
3
|
API_URL = "https://api.tastyworks.com"
|
|
4
4
|
API_VERSION = "20251101"
|
|
5
5
|
CERT_URL = "https://api.cert.tastyworks.com"
|
|
6
|
-
|
|
7
|
-
VERSION = "11.0.5"
|
|
6
|
+
VERSION = "11.1.0"
|
|
8
7
|
|
|
9
8
|
__version__ = VERSION
|
|
10
9
|
version_str: str = f"tastyware/tastytrade:v{VERSION}"
|
tastytrade/account.py
CHANGED
|
@@ -2,17 +2,14 @@ from datetime import date, datetime
|
|
|
2
2
|
from decimal import Decimal
|
|
3
3
|
from typing import Any, Literal, cast, overload
|
|
4
4
|
|
|
5
|
-
import httpx
|
|
6
5
|
from pydantic import BaseModel, ConfigDict, model_validator
|
|
7
6
|
from typing_extensions import Self
|
|
8
7
|
|
|
9
|
-
from tastytrade import VAST_URL
|
|
10
8
|
from tastytrade.order import (
|
|
11
9
|
InstrumentType,
|
|
12
10
|
NewComplexOrder,
|
|
13
11
|
NewOrder,
|
|
14
12
|
OrderAction,
|
|
15
|
-
OrderChain,
|
|
16
13
|
OrderStatus,
|
|
17
14
|
PlacedComplexOrder,
|
|
18
15
|
PlacedComplexOrderResponse,
|
|
@@ -28,7 +25,6 @@ from tastytrade.utils import (
|
|
|
28
25
|
paginate,
|
|
29
26
|
set_sign_for,
|
|
30
27
|
today_in_new_york,
|
|
31
|
-
validate_response,
|
|
32
28
|
)
|
|
33
29
|
|
|
34
30
|
TT_DATE_FMT = "%Y-%m-%dT%H:%M:%SZ"
|
|
@@ -296,23 +292,6 @@ class MarginReport(TastytradeData):
|
|
|
296
292
|
)
|
|
297
293
|
|
|
298
294
|
|
|
299
|
-
class MarginRequirement(TastytradeData):
|
|
300
|
-
"""
|
|
301
|
-
Dataclass containing general margin requirement information for a symbol.
|
|
302
|
-
"""
|
|
303
|
-
|
|
304
|
-
underlying_symbol: str
|
|
305
|
-
long_equity_initial: Decimal
|
|
306
|
-
short_equity_initial: Decimal
|
|
307
|
-
long_equity_maintenance: Decimal
|
|
308
|
-
short_equity_maintenance: Decimal
|
|
309
|
-
naked_option_standard: Decimal
|
|
310
|
-
naked_option_minimum: Decimal
|
|
311
|
-
naked_option_floor: Decimal
|
|
312
|
-
clearing_identifier: str | None = None
|
|
313
|
-
is_deleted: bool | None = None
|
|
314
|
-
|
|
315
|
-
|
|
316
295
|
class NetLiqOhlc(TastytradeData):
|
|
317
296
|
"""
|
|
318
297
|
Dataclass containing historical net liquidation data in OHLC format
|
|
@@ -334,23 +313,6 @@ class NetLiqOhlc(TastytradeData):
|
|
|
334
313
|
time: str
|
|
335
314
|
|
|
336
315
|
|
|
337
|
-
class PositionLimit(TastytradeData):
|
|
338
|
-
"""
|
|
339
|
-
Dataclass containing information about general account limits.
|
|
340
|
-
"""
|
|
341
|
-
|
|
342
|
-
account_number: str
|
|
343
|
-
equity_order_size: int
|
|
344
|
-
equity_option_order_size: int
|
|
345
|
-
future_order_size: int
|
|
346
|
-
future_option_order_size: int
|
|
347
|
-
underlying_opening_order_limit: int
|
|
348
|
-
equity_position_size: int
|
|
349
|
-
equity_option_position_size: int
|
|
350
|
-
future_position_size: int
|
|
351
|
-
future_option_position_size: int
|
|
352
|
-
|
|
353
|
-
|
|
354
316
|
class TradingStatus(TastytradeData):
|
|
355
317
|
"""
|
|
356
318
|
Dataclass containing information about an account's trading status, such
|
|
@@ -1043,58 +1005,6 @@ class Account(TastytradeData):
|
|
|
1043
1005
|
)
|
|
1044
1006
|
return [NetLiqOhlc(**i) for i in data["items"]]
|
|
1045
1007
|
|
|
1046
|
-
async def a_get_position_limit(self, session: Session) -> PositionLimit:
|
|
1047
|
-
"""
|
|
1048
|
-
Get the maximum order size information for the account.
|
|
1049
|
-
|
|
1050
|
-
:param session: the session to use for the request.
|
|
1051
|
-
"""
|
|
1052
|
-
data = await session._a_get(f"/accounts/{self.account_number}/position-limit")
|
|
1053
|
-
return PositionLimit(**data)
|
|
1054
|
-
|
|
1055
|
-
def get_position_limit(self, session: Session) -> PositionLimit:
|
|
1056
|
-
"""
|
|
1057
|
-
Get the maximum order size information for the account.
|
|
1058
|
-
|
|
1059
|
-
:param session: the session to use for the request.
|
|
1060
|
-
"""
|
|
1061
|
-
data = session._get(f"/accounts/{self.account_number}/position-limit")
|
|
1062
|
-
return PositionLimit(**data)
|
|
1063
|
-
|
|
1064
|
-
async def a_get_effective_margin_requirements(
|
|
1065
|
-
self, session: Session, symbol: str
|
|
1066
|
-
) -> MarginRequirement:
|
|
1067
|
-
"""
|
|
1068
|
-
Get the effective margin requirements for a given symbol.
|
|
1069
|
-
|
|
1070
|
-
:param session:
|
|
1071
|
-
the session to use for the request, can't be certification
|
|
1072
|
-
:param symbol: the symbol to get margin requirements for.
|
|
1073
|
-
"""
|
|
1074
|
-
if symbol:
|
|
1075
|
-
symbol = symbol.replace("/", "%2F")
|
|
1076
|
-
data = await session._a_get(
|
|
1077
|
-
f"/accounts/{self.account_number}/margin-requirements/{symbol}/effective"
|
|
1078
|
-
)
|
|
1079
|
-
return MarginRequirement(**data)
|
|
1080
|
-
|
|
1081
|
-
def get_effective_margin_requirements(
|
|
1082
|
-
self, session: Session, symbol: str
|
|
1083
|
-
) -> MarginRequirement:
|
|
1084
|
-
"""
|
|
1085
|
-
Get the effective margin requirements for a given symbol.
|
|
1086
|
-
|
|
1087
|
-
:param session:
|
|
1088
|
-
the session to use for the request, can't be certification
|
|
1089
|
-
:param symbol: the symbol to get margin requirements for.
|
|
1090
|
-
"""
|
|
1091
|
-
if symbol:
|
|
1092
|
-
symbol = symbol.replace("/", "%2F")
|
|
1093
|
-
data = session._get(
|
|
1094
|
-
f"/accounts/{self.account_number}/margin-requirements/{symbol}/effective"
|
|
1095
|
-
)
|
|
1096
|
-
return MarginRequirement(**data)
|
|
1097
|
-
|
|
1098
1008
|
async def a_get_margin_requirements(self, session: Session) -> MarginReport:
|
|
1099
1009
|
"""
|
|
1100
1010
|
Get the margin report for the account, with total margin requirements
|
|
@@ -1500,84 +1410,3 @@ class Account(TastytradeData):
|
|
|
1500
1410
|
),
|
|
1501
1411
|
)
|
|
1502
1412
|
return PlacedOrder(**data)
|
|
1503
|
-
|
|
1504
|
-
async def a_get_order_chains(
|
|
1505
|
-
self,
|
|
1506
|
-
session: Session,
|
|
1507
|
-
symbol: str,
|
|
1508
|
-
start_time: datetime,
|
|
1509
|
-
end_time: datetime,
|
|
1510
|
-
) -> list[OrderChain]:
|
|
1511
|
-
"""
|
|
1512
|
-
Get a list of order chains (open + rolls + close) for given symbol
|
|
1513
|
-
over the given time frame, with total P/L, commissions, etc.
|
|
1514
|
-
|
|
1515
|
-
Not supported for OAuth sessions--write Tasty to get this added!
|
|
1516
|
-
|
|
1517
|
-
:param session: the session to use for the request.
|
|
1518
|
-
:param symbol: the underlying symbol for the chains.
|
|
1519
|
-
:param start_time: the beginning time of the query.
|
|
1520
|
-
:param end_time: the ending time of the query.
|
|
1521
|
-
"""
|
|
1522
|
-
params = {
|
|
1523
|
-
"account-numbers[]": self.account_number,
|
|
1524
|
-
"underlying-symbols[]": symbol,
|
|
1525
|
-
"start-at": start_time.strftime(TT_DATE_FMT),
|
|
1526
|
-
"end-at": end_time.strftime(TT_DATE_FMT),
|
|
1527
|
-
"defer-open-winner-loser-filtering-to-frontend": False,
|
|
1528
|
-
"per-page": 250,
|
|
1529
|
-
}
|
|
1530
|
-
headers = {
|
|
1531
|
-
"Authorization": session.session_token,
|
|
1532
|
-
"Accept": "application/json",
|
|
1533
|
-
"Content-Type": "application/json",
|
|
1534
|
-
}
|
|
1535
|
-
async with httpx.AsyncClient() as client:
|
|
1536
|
-
response = await client.get(
|
|
1537
|
-
f"{VAST_URL}/order-chains",
|
|
1538
|
-
headers=headers,
|
|
1539
|
-
params=params, # type: ignore[arg-type]
|
|
1540
|
-
)
|
|
1541
|
-
validate_response(response)
|
|
1542
|
-
chains = response.json()["data"]["items"]
|
|
1543
|
-
return [OrderChain(**i) for i in chains]
|
|
1544
|
-
|
|
1545
|
-
def get_order_chains(
|
|
1546
|
-
self,
|
|
1547
|
-
session: Session,
|
|
1548
|
-
symbol: str,
|
|
1549
|
-
start_time: datetime,
|
|
1550
|
-
end_time: datetime,
|
|
1551
|
-
) -> list[OrderChain]:
|
|
1552
|
-
"""
|
|
1553
|
-
Get a list of order chains (open + rolls + close) for given symbol
|
|
1554
|
-
over the given time frame, with total P/L, commissions, etc.
|
|
1555
|
-
|
|
1556
|
-
Not supported for OAuth sessions--write Tasty to get this added!
|
|
1557
|
-
|
|
1558
|
-
:param session: the session to use for the request.
|
|
1559
|
-
:param symbol: the underlying symbol for the chains.
|
|
1560
|
-
:param start_time: the beginning time of the query.
|
|
1561
|
-
:param end_time: the ending time of the query.
|
|
1562
|
-
"""
|
|
1563
|
-
params = {
|
|
1564
|
-
"account-numbers[]": self.account_number,
|
|
1565
|
-
"underlying-symbols[]": symbol,
|
|
1566
|
-
"start-at": start_time.strftime(TT_DATE_FMT),
|
|
1567
|
-
"end-at": end_time.strftime(TT_DATE_FMT),
|
|
1568
|
-
"defer-open-winner-loser-filtering-to-frontend": False,
|
|
1569
|
-
"per-page": 250,
|
|
1570
|
-
}
|
|
1571
|
-
headers = {
|
|
1572
|
-
"Authorization": session.session_token,
|
|
1573
|
-
"Accept": "application/json",
|
|
1574
|
-
"Content-Type": "application/json",
|
|
1575
|
-
}
|
|
1576
|
-
response = httpx.get(
|
|
1577
|
-
f"{VAST_URL}/order-chains",
|
|
1578
|
-
headers=headers,
|
|
1579
|
-
params=params, # type: ignore[arg-type]
|
|
1580
|
-
)
|
|
1581
|
-
validate_response(response)
|
|
1582
|
-
chains = response.json()["data"]["items"]
|
|
1583
|
-
return [OrderChain(**i) for i in chains]
|
tastytrade/market_sessions.py
CHANGED
|
@@ -118,6 +118,25 @@ def get_market_holidays(session: Session) -> MarketCalendar:
|
|
|
118
118
|
return MarketCalendar(**data)
|
|
119
119
|
|
|
120
120
|
|
|
121
|
+
async def a_get_futures_holidays(
|
|
122
|
+
session: Session, exchange: ExchangeType
|
|
123
|
+
) -> MarketCalendar:
|
|
124
|
+
"""
|
|
125
|
+
Retrieves market calendar for half days and holidays for a futures exchange.
|
|
126
|
+
|
|
127
|
+
:param session: active user session to use
|
|
128
|
+
:param exchange: exchange to fetch calendar for
|
|
129
|
+
"""
|
|
130
|
+
data = await session._a_get(f"/market-time/futures/holidays/{exchange.value}")
|
|
131
|
+
return MarketCalendar(**data)
|
|
132
|
+
|
|
133
|
+
|
|
121
134
|
def get_futures_holidays(session: Session, exchange: ExchangeType) -> MarketCalendar:
|
|
135
|
+
"""
|
|
136
|
+
Retrieves market calendar for half days and holidays for a futures exchange.
|
|
137
|
+
|
|
138
|
+
:param session: active user session to use
|
|
139
|
+
:param exchange: exchange to fetch calendar for
|
|
140
|
+
"""
|
|
122
141
|
data = session._get(f"/market-time/futures/holidays/{exchange.value}")
|
|
123
142
|
return MarketCalendar(**data)
|
tastytrade/order.py
CHANGED
|
@@ -3,7 +3,7 @@ from decimal import Decimal
|
|
|
3
3
|
from enum import Enum
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
-
from pydantic import computed_field, field_serializer, model_validator
|
|
6
|
+
from pydantic import ConfigDict, computed_field, field_serializer, model_validator
|
|
7
7
|
|
|
8
8
|
from tastytrade import version_str
|
|
9
9
|
from tastytrade.utils import (
|
|
@@ -237,6 +237,8 @@ class NewOrder(TastytradeData):
|
|
|
237
237
|
modifying existing orders.
|
|
238
238
|
"""
|
|
239
239
|
|
|
240
|
+
model_config = ConfigDict(extra="allow")
|
|
241
|
+
|
|
240
242
|
time_in_force: OrderTimeInForce
|
|
241
243
|
order_type: OrderType
|
|
242
244
|
source: str = version_str
|
|
@@ -435,122 +437,3 @@ class PlacedOrderResponse(TastytradeData):
|
|
|
435
437
|
fee_calculation: FeeCalculation | None = None
|
|
436
438
|
warnings: list[Message] | None = None
|
|
437
439
|
errors: list[Message] | None = None
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
class OrderChainEntry(TastytradeData):
|
|
441
|
-
"""
|
|
442
|
-
Dataclass containing information about a single order in an order chain.
|
|
443
|
-
"""
|
|
444
|
-
|
|
445
|
-
symbol: str
|
|
446
|
-
instrument_type: InstrumentType
|
|
447
|
-
quantity: str
|
|
448
|
-
quantity_type: str
|
|
449
|
-
quantity_numeric: Decimal
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
class OrderChainLeg(TastytradeData):
|
|
453
|
-
"""
|
|
454
|
-
Dataclass containing information about a single leg in an order
|
|
455
|
-
from an order chain.
|
|
456
|
-
"""
|
|
457
|
-
|
|
458
|
-
symbol: str
|
|
459
|
-
instrument_type: InstrumentType
|
|
460
|
-
action: OrderAction
|
|
461
|
-
fill_quantity: Decimal
|
|
462
|
-
order_quantity: Decimal
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
class OrderChainNode(TastytradeData):
|
|
466
|
-
"""
|
|
467
|
-
Dataclass containing information about a single node in an order chain.
|
|
468
|
-
"""
|
|
469
|
-
|
|
470
|
-
node_type: str
|
|
471
|
-
id: str
|
|
472
|
-
description: str
|
|
473
|
-
occurred_at: datetime | None = None
|
|
474
|
-
total_fees: Decimal | None = None
|
|
475
|
-
total_fill_cost: Decimal | None = None
|
|
476
|
-
gcd_quantity: Decimal | None = None
|
|
477
|
-
fill_cost_per_quantity: Decimal | None = None
|
|
478
|
-
order_fill_count: int | None = None
|
|
479
|
-
roll: bool | None = None
|
|
480
|
-
legs: list[OrderChainLeg] | None = None
|
|
481
|
-
entries: list[OrderChainEntry] | None = None
|
|
482
|
-
|
|
483
|
-
@model_validator(mode="before")
|
|
484
|
-
@classmethod
|
|
485
|
-
def validate_price_effects(cls, data: Any) -> Any:
|
|
486
|
-
return set_sign_for(
|
|
487
|
-
data,
|
|
488
|
-
[
|
|
489
|
-
"total_fees",
|
|
490
|
-
"total_fill_cost",
|
|
491
|
-
"fill_cost_per_quantity",
|
|
492
|
-
],
|
|
493
|
-
)
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
class ComputedData(TastytradeData):
|
|
497
|
-
"""
|
|
498
|
-
Dataclass containing computed data about an order chain.
|
|
499
|
-
"""
|
|
500
|
-
|
|
501
|
-
open: bool
|
|
502
|
-
updated_at: datetime
|
|
503
|
-
total_fees: Decimal
|
|
504
|
-
total_commissions: Decimal
|
|
505
|
-
realized_gain: Decimal
|
|
506
|
-
realized_gain_with_fees: Decimal
|
|
507
|
-
winner_realized_and_closed: bool
|
|
508
|
-
winner_realized: bool
|
|
509
|
-
winner_realized_with_fees: bool
|
|
510
|
-
roll_count: int
|
|
511
|
-
opened_at: datetime
|
|
512
|
-
last_occurred_at: datetime
|
|
513
|
-
started_at_days_to_expiration: int
|
|
514
|
-
duration: int
|
|
515
|
-
total_opening_cost: Decimal
|
|
516
|
-
total_closing_cost: Decimal
|
|
517
|
-
total_cost: Decimal
|
|
518
|
-
gcd_open_quantity: Decimal
|
|
519
|
-
fees_missing: bool
|
|
520
|
-
open_entries: list[OrderChainEntry]
|
|
521
|
-
total_cost_per_unit: Decimal | None = None
|
|
522
|
-
|
|
523
|
-
@model_validator(mode="before")
|
|
524
|
-
@classmethod
|
|
525
|
-
def validate_price_effects(cls, data: Any) -> Any:
|
|
526
|
-
return set_sign_for(
|
|
527
|
-
data,
|
|
528
|
-
[
|
|
529
|
-
"total_fees",
|
|
530
|
-
"total_commissions",
|
|
531
|
-
"realized_gain",
|
|
532
|
-
"realized_gain_with_fees",
|
|
533
|
-
"total_opening_cost",
|
|
534
|
-
"total_closing_cost",
|
|
535
|
-
"total_cost",
|
|
536
|
-
"total_cost_per_unit",
|
|
537
|
-
],
|
|
538
|
-
)
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
class OrderChain(TastytradeData):
|
|
542
|
-
"""
|
|
543
|
-
Dataclass containing information about an order chain: a group of orders
|
|
544
|
-
for a specific underlying, such as total P/L, rolls, current P/L in a
|
|
545
|
-
symbol, etc.
|
|
546
|
-
"""
|
|
547
|
-
|
|
548
|
-
id: int
|
|
549
|
-
account_number: str
|
|
550
|
-
description: str
|
|
551
|
-
underlying_symbol: str
|
|
552
|
-
computed_data: ComputedData
|
|
553
|
-
lite_nodes: list[OrderChainNode]
|
|
554
|
-
lite_nodes_sizes: int | None = None
|
|
555
|
-
updated_at: datetime | None = None
|
|
556
|
-
created_at: datetime | None = None
|
tastytrade/session.py
CHANGED
|
@@ -233,7 +233,7 @@ class Customer(TastytradeData):
|
|
|
233
233
|
desk_customer_id: str | None = None
|
|
234
234
|
entity: CustomerEntity | None = None
|
|
235
235
|
family_member_names: str | None = None
|
|
236
|
-
has_institutional_assets: str | None = None
|
|
236
|
+
has_institutional_assets: str | bool | None = None
|
|
237
237
|
industry_affiliation_firm: str | None = None
|
|
238
238
|
is_investment_adviser: bool | None = None
|
|
239
239
|
listed_affiliation_symbol: str | None = None
|
|
@@ -289,9 +289,7 @@ class Session:
|
|
|
289
289
|
self.streamer_expiration = now_in_new_york()
|
|
290
290
|
self.refresh()
|
|
291
291
|
|
|
292
|
-
def _streamer_refresh(self) -> None:
|
|
293
|
-
# Pull streamer tokens and urls
|
|
294
|
-
data = self._get("/api-quote-tokens")
|
|
292
|
+
def _streamer_refresh(self, data: Any) -> None:
|
|
295
293
|
# Auth token for dxfeed websocket
|
|
296
294
|
self.streamer_token = data["token"]
|
|
297
295
|
# URL for dxfeed websocket
|
|
@@ -331,7 +329,8 @@ class Session:
|
|
|
331
329
|
self.async_client.headers.update(auth_headers)
|
|
332
330
|
# update the streamer token if necessary
|
|
333
331
|
if not self.is_test and self.streamer_expiration < self.session_expiration:
|
|
334
|
-
self.
|
|
332
|
+
data = self._get("/api-quote-tokens")
|
|
333
|
+
self._streamer_refresh(data)
|
|
335
334
|
|
|
336
335
|
async def a_refresh(self) -> None:
|
|
337
336
|
"""
|
|
@@ -365,13 +364,7 @@ class Session:
|
|
|
365
364
|
if not self.is_test and self.streamer_expiration < self.session_expiration:
|
|
366
365
|
# Pull streamer tokens and urls
|
|
367
366
|
data = await self._a_get("/api-quote-tokens")
|
|
368
|
-
|
|
369
|
-
self.streamer_token = data["token"]
|
|
370
|
-
# URL for dxfeed websocket
|
|
371
|
-
self.dxlink_url = data["dxlink-url"]
|
|
372
|
-
self.streamer_expiration = datetime.fromisoformat(
|
|
373
|
-
data["expires-at"].replace("Z", "+00:00")
|
|
374
|
-
)
|
|
367
|
+
self._streamer_refresh(data)
|
|
375
368
|
|
|
376
369
|
async def a_get_customer(self) -> Customer:
|
|
377
370
|
"""
|
tastytrade/streamer.py
CHANGED
|
@@ -29,12 +29,7 @@ from tastytrade.dxfeed import (
|
|
|
29
29
|
Trade,
|
|
30
30
|
Underlying,
|
|
31
31
|
)
|
|
32
|
-
from tastytrade.order import
|
|
33
|
-
InstrumentType,
|
|
34
|
-
OrderChain,
|
|
35
|
-
PlacedComplexOrder,
|
|
36
|
-
PlacedOrder,
|
|
37
|
-
)
|
|
32
|
+
from tastytrade.order import InstrumentType, PlacedComplexOrder, PlacedOrder
|
|
38
33
|
from tastytrade.session import Session
|
|
39
34
|
from tastytrade.utils import TastytradeData, TastytradeError, set_sign_for
|
|
40
35
|
from tastytrade.watchlists import Watchlist
|
|
@@ -133,7 +128,6 @@ AlertType: TypeAlias = (
|
|
|
133
128
|
| ExternalTransaction
|
|
134
129
|
| PlacedComplexOrder
|
|
135
130
|
| PlacedOrder
|
|
136
|
-
| OrderChain
|
|
137
131
|
| CurrentPosition
|
|
138
132
|
| QuoteAlert
|
|
139
133
|
| TradingStatus
|
|
@@ -146,7 +140,6 @@ MAP_ALERTS: dict[str, type[AlertType]] = {
|
|
|
146
140
|
"ComplexOrder": PlacedComplexOrder,
|
|
147
141
|
"ExternalTransaction": ExternalTransaction,
|
|
148
142
|
"Order": PlacedOrder,
|
|
149
|
-
"OrderChain": OrderChain,
|
|
150
143
|
"CurrentPosition": CurrentPosition,
|
|
151
144
|
"QuoteAlert": QuoteAlert,
|
|
152
145
|
"TradingStatus": TradingStatus,
|
|
@@ -761,7 +754,7 @@ class DXLinkStreamer:
|
|
|
761
754
|
}
|
|
762
755
|
|
|
763
756
|
def dict_from_schema(event_class: Any) -> dict[str, list[Any]]:
|
|
764
|
-
schema = event_class.
|
|
757
|
+
schema = event_class.model_json_schema()
|
|
765
758
|
return {schema["title"]: list(schema["properties"].keys())}
|
|
766
759
|
|
|
767
760
|
cls = MAP_EVENTS[event_type]
|
tastytrade/utils.py
CHANGED
|
@@ -6,6 +6,7 @@ from typing import Any, Type, TypeVar, cast
|
|
|
6
6
|
from zoneinfo import ZoneInfo
|
|
7
7
|
|
|
8
8
|
from httpx import AsyncClient, Client, Response
|
|
9
|
+
from pandas import Timestamp
|
|
9
10
|
from pandas_market_calendars import get_calendar # type: ignore[import-untyped]
|
|
10
11
|
from pydantic import BaseModel, ConfigDict
|
|
11
12
|
|
|
@@ -40,6 +41,22 @@ def today_in_new_york() -> date:
|
|
|
40
41
|
return now_in_new_york().date()
|
|
41
42
|
|
|
42
43
|
|
|
44
|
+
def is_market_open_now() -> bool:
|
|
45
|
+
"""
|
|
46
|
+
Check if the market is currently open.
|
|
47
|
+
"""
|
|
48
|
+
today = today_in_new_york()
|
|
49
|
+
sched = NYSE.schedule(start_date=today, end_date=today)
|
|
50
|
+
if sched.empty:
|
|
51
|
+
# Closed full day (weekend or holiday)
|
|
52
|
+
return False
|
|
53
|
+
|
|
54
|
+
# Use iloc[0] since schedule has only one row for a single day
|
|
55
|
+
market_open: Timestamp = sched.iloc[0]["market_open"]
|
|
56
|
+
market_close: Timestamp = sched.iloc[0]["market_close"]
|
|
57
|
+
return market_open <= now_in_new_york() < market_close
|
|
58
|
+
|
|
59
|
+
|
|
43
60
|
def is_market_open_on(day: date | None = None) -> bool:
|
|
44
61
|
"""
|
|
45
62
|
Returns whether the market was/is/will be open at ANY point
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
tastytrade/__init__.py,sha256=
|
|
2
|
-
tastytrade/account.py,sha256=
|
|
1
|
+
tastytrade/__init__.py,sha256=DvTWfw-6-YKHKsRPptZDHxdn4iqnRK8hTVzd8lSfJxE,490
|
|
2
|
+
tastytrade/account.py,sha256=Tekp-k1V6PIne9saasRyhkmFp3Zj4bypWtuk-KNVp58,50850
|
|
3
3
|
tastytrade/instruments.py,sha256=QZHakLgxsgscZx7ouz1LgIuahlHM2n0AfY9UQBdlEoM,46803
|
|
4
4
|
tastytrade/market_data.py,sha256=iyBpleKvDWfXReo6DuKbXP-gN1Yv8iyvNs9z2x5Gxig,5940
|
|
5
|
-
tastytrade/market_sessions.py,sha256=
|
|
5
|
+
tastytrade/market_sessions.py,sha256=qx1oSOqmFzrGVN_IwxAbG7oSEIob2H_RTEX8zTlFoOA,3995
|
|
6
6
|
tastytrade/metrics.py,sha256=LqpUZIR4L2bQwawf_L4gJ3Pjg_S72eURrJpu4ebKtpU,7495
|
|
7
|
-
tastytrade/order.py,sha256=
|
|
7
|
+
tastytrade/order.py,sha256=NUAL8Ac8mH0CULe1g1Xz_A7m5ZeKPkLjFPCF5_3D6m0,12032
|
|
8
8
|
tastytrade/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
tastytrade/search.py,sha256=LdoVEhiYNvtolXlf_jAVZUtA2ymUWOvHMhQxJxuVt_A,1529
|
|
10
|
-
tastytrade/session.py,sha256=
|
|
11
|
-
tastytrade/streamer.py,sha256=
|
|
12
|
-
tastytrade/utils.py,sha256=
|
|
10
|
+
tastytrade/session.py,sha256=iV4M_dBbpi9H5umiVBVDYm0I-7823xgqiOc6cVN5Xu8,14832
|
|
11
|
+
tastytrade/streamer.py,sha256=VTZBlPfiYIwsg_hoYBvofjTPExubYSGmxbfFo-ELrj4,32540
|
|
12
|
+
tastytrade/utils.py,sha256=65Zr8hz3oUNmh8WYL2YGYt2pRBafljyLghfHLU60mtA,12851
|
|
13
13
|
tastytrade/watchlists.py,sha256=K9jpgXi9a9dklGl-jCXzpbM0tOd836GSkXa4fySeH3Q,8657
|
|
14
14
|
tastytrade/dxfeed/__init__.py,sha256=GmC0aKtiUjs7aqbX7PeqMaROxqalwzHOnJOMJn8TaZk,458
|
|
15
15
|
tastytrade/dxfeed/candle.py,sha256=j9nuWftzOT_qGDTZNNfFIABZp_n_5Gi7OFm5KPK2dnc,1757
|
|
@@ -22,7 +22,7 @@ tastytrade/dxfeed/theoprice.py,sha256=L5aH--F_6xLZCSYZ4APpzlihbW0-cYEwRdeGVI-aNa
|
|
|
22
22
|
tastytrade/dxfeed/timeandsale.py,sha256=QuMFoccq8x3c2y6s3DnwBNIVTrLS6OPqV6GmCNoXQEQ,1903
|
|
23
23
|
tastytrade/dxfeed/trade.py,sha256=qNo4oKb7iq0Opoq3FCBEUUcGGF6udda1bD0eKQVty_0,1402
|
|
24
24
|
tastytrade/dxfeed/underlying.py,sha256=YYqJNlmrlt6Kpg0F6voQ18g60obXiYTVlroXirBWPR8,1226
|
|
25
|
-
tastytrade-11.0.
|
|
26
|
-
tastytrade-11.0.
|
|
27
|
-
tastytrade-11.0.
|
|
28
|
-
tastytrade-11.0.
|
|
25
|
+
tastytrade-11.1.0.dist-info/METADATA,sha256=MANTjAy63Lj770EI56KQ06oVm9pOp69g2svr_x8yvmc,10904
|
|
26
|
+
tastytrade-11.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
27
|
+
tastytrade-11.1.0.dist-info/licenses/LICENSE,sha256=enBkMN4OsfLt6Z_AsrGC7u5dAJkCEODnoN7BwMCzSfc,1072
|
|
28
|
+
tastytrade-11.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|