Skip to content

Commit

Permalink
dxfeed events have less optional fields
Browse files Browse the repository at this point in the history
  • Loading branch information
Graeme22 committed Dec 3, 2024
1 parent 202655e commit b510862
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 22 deletions.
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
project = "tastytrade"
copyright = "2024, Graeme Holliday"
author = "Graeme Holliday"
release = "9.2"
release = "9.3"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "tastytrade"
version = "9.2"
version = "9.3"
description = "An unofficial, sync/async SDK for Tastytrade!"
readme = "README.md"
requires-python = ">=3.8"
Expand Down
2 changes: 1 addition & 1 deletion tastytrade/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
BACKTEST_URL = "https://backtester.vast.tastyworks.com"
CERT_URL = "https://api.cert.tastyworks.com"
VAST_URL = "https://vast.tastyworks.com"
VERSION = "9.2"
VERSION = "9.3"

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
Expand Down
8 changes: 4 additions & 4 deletions tastytrade/dxfeed/candle.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ class Candle(Event):
#: total number of events in the candle
count: int
#: the first (open) price of the candle
open: Optional[Decimal] = None
open: Decimal
#: the maximal (high) price of the candle
high: Optional[Decimal] = None
high: Decimal
#: the minimal (low) price of the candle
low: Optional[Decimal] = None
low: Decimal
#: the last (close) price of the candle
close: Optional[Decimal] = None
close: Decimal
#: the total volume of the candle
volume: Optional[Decimal] = None
#: volume-weighted average price
Expand Down
14 changes: 10 additions & 4 deletions tastytrade/dxfeed/event.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from typing import Any, List

from pydantic import BaseModel, field_validator
from pydantic import BaseModel, ValidationError, field_validator

from tastytrade import logger
from tastytrade.utils import TastytradeError


Expand All @@ -27,12 +28,17 @@ def from_stream(cls, data: list) -> List["Event"]:
size = len(cls.model_fields)
multiples = len(data) / size
if not multiples.is_integer():
msg = "Mapper data input values are not a multiple of the key size"
raise TastytradeError(msg)
raise TastytradeError(
"Mapper data input values are not a multiple of the key size!"
)
keys = cls.model_fields.keys()
for i in range(int(multiples)):
offset = i * size
local_values = data[offset : (i + 1) * size]
event_dict = dict(zip(keys, local_values))
objs.append(cls(**event_dict))
try:
objs.append(cls(**event_dict))
except ValidationError as e:
# we just skip these events as they're generally useless
logger.debug(e)
return objs
4 changes: 2 additions & 2 deletions tastytrade/dxfeed/quote.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ class Quote(Event):
#: ask exchange code
askExchangeCode: str
#: bid price
bidPrice: Optional[Decimal] = None
bidPrice: Decimal
#: ask price
askPrice: Optional[Decimal] = None
askPrice: Decimal
#: bid size as integer number (rounded toward zero)
#: or decimal for cryptocurrencies
bidSize: Optional[Decimal] = None
Expand Down
2 changes: 1 addition & 1 deletion tastytrade/dxfeed/trade.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Trade(Event):
#: whether the last trade was in extended trading hours
extendedTradingHours: bool
#: price of the last trade
price: Optional[Decimal] = None
price: Decimal
#: change of the last trade
change: Optional[Decimal] = None
#: size of the last trade as integer number (rounded toward zero)
Expand Down
28 changes: 21 additions & 7 deletions tests/test_dxfeed.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,31 @@

import pytest

from tastytrade.dxfeed import Quote
from tastytrade.dxfeed import Quote, Summary
from tastytrade.utils import TastytradeError


def test_parse_infinities_and_nan():
quote_data = ["SPY", 0, 0, 0, 0, "Q", 0, "Q", "-Infinity", "Infinity", "NaN", "NaN"]
quote = Quote.from_stream(quote_data)[0]
quote = cast(Quote, quote)
assert quote.bidPrice is None
assert quote.askPrice is None
assert quote.bidSize is None
summary_data = [
"SPY",
0,
0,
"foo",
0,
"bar",
0,
"-Infinity",
"Infinity",
"NaN",
"NaN",
"NaN",
"Infinity",
]
summary = Summary.from_stream(summary_data)[0]
summary = cast(Summary, summary)
assert summary.dayOpenPrice is None
assert summary.dayClosePrice is None
assert summary.dayHighPrice is None


def test_malformatted_data():
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b510862

Please sign in to comment.