From 4195df82f8f1673f4cff25fe447b3e7424d726b1 Mon Sep 17 00:00:00 2001 From: Graeme Holliday Date: Mon, 16 Dec 2024 17:22:57 -0500 Subject: [PATCH] use wrap validator for candle --- tastytrade/dxfeed/candle.py | 66 +++++++++++++++---------------------- tastytrade/dxfeed/event.py | 11 +++---- tastytrade/order.py | 1 - 3 files changed, 32 insertions(+), 46 deletions(-) diff --git a/tastytrade/dxfeed/candle.py b/tastytrade/dxfeed/candle.py index 73cb4a7..9669d06 100644 --- a/tastytrade/dxfeed/candle.py +++ b/tastytrade/dxfeed/candle.py @@ -1,13 +1,30 @@ from decimal import Decimal -from typing import Optional +from typing import Annotated, Any, Optional -from pydantic import Field, computed_field +from pydantic import ( + ValidationError, + ValidationInfo, + ValidatorFunctionWrapHandler, + WrapValidator, +) from .event import IndexedEvent ZERO = Decimal(0) +def zero_from_none( + v: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo +) -> Decimal: + try: + return handler(v) + except ValidationError: + return ZERO + + +ZeroFromNone = Annotated[Decimal, WrapValidator(zero_from_none)] + + class Candle(IndexedEvent): """ A Candle event with open, high, low, close prices and other information @@ -35,40 +52,11 @@ class Candle(IndexedEvent): imp_volatility: Optional[Decimal] = None #: open interest in the candle open_interest: Optional[int] = None - # these fields will not show up in serialization - raw_open: Optional[Decimal] = Field(validation_alias="open", exclude=True) - raw_high: Optional[Decimal] = Field(validation_alias="high", exclude=True) - raw_low: Optional[Decimal] = Field(validation_alias="low", exclude=True) - raw_close: Optional[Decimal] = Field(validation_alias="close", exclude=True) - - @computed_field - @property - def open(self) -> Decimal: - """ - the first (open) price of the candle - """ - return self.raw_open or ZERO - - @computed_field - @property - def high(self) -> Decimal: - """ - the maximal (high) price of the candle - """ - return self.raw_high or ZERO - - @computed_field - @property - def low(self) -> Decimal: - """ - the minimal (low) price of the candle - """ - return self.raw_low or ZERO - - @computed_field - @property - def close(self) -> Decimal: - """ - the last (close) price of the candle - """ - return self.raw_close or ZERO + #: the first (open) price of the candle + open: ZeroFromNone + #: the maximal (high) price of the candle + high: ZeroFromNone + #: the minimal (low) price of the candle + low: ZeroFromNone + #: the last (close) price of the candle + close: ZeroFromNone diff --git a/tastytrade/dxfeed/event.py b/tastytrade/dxfeed/event.py index f82d55a..986410e 100644 --- a/tastytrade/dxfeed/event.py +++ b/tastytrade/dxfeed/event.py @@ -1,9 +1,8 @@ -from typing import Any, List +from typing import Any from pydantic import BaseModel, ConfigDict, ValidationError, field_validator from pydantic.alias_generators import to_camel -from tastytrade import logger from tastytrade.utils import TastytradeError REMOVE_EVENT = 0x2 @@ -34,7 +33,7 @@ def change_nan_to_none(cls, v: Any) -> Any: return v @classmethod - def from_stream(cls, data: list) -> List["Event"]: + def from_stream(cls, data: list) -> list["Event"]: """ Makes a list of event objects from a list of raw trade data fetched by a :class:`~tastyworks.streamer.DXFeedStreamer`. @@ -56,10 +55,10 @@ def from_stream(cls, data: list) -> List["Event"]: local_values = data[offset : (i + 1) * size] event_dict = dict(zip(keys, local_values)) try: - objs.append(cls(**event_dict)) - except ValidationError as e: + objs.append(cls.model_validate(event_dict)) + except ValidationError: # we just skip these events as they're generally not helpful - logger.debug(f"Skipping event due to error: {e}") + pass return objs diff --git a/tastytrade/order.py b/tastytrade/order.py index ffead10..45e4219 100644 --- a/tastytrade/order.py +++ b/tastytrade/order.py @@ -3,7 +3,6 @@ from enum import Enum from typing import Any, Optional, Union -from pandas_market_calendars.calendar_registry import prop from pydantic import computed_field, field_serializer, model_validator from tastytrade import VERSION