Skip to content

Commit 4195df8

Browse files
committed
use wrap validator for candle
1 parent c0a3786 commit 4195df8

File tree

3 files changed

+32
-46
lines changed

3 files changed

+32
-46
lines changed

tastytrade/dxfeed/candle.py

Lines changed: 27 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
11
from decimal import Decimal
2-
from typing import Optional
2+
from typing import Annotated, Any, Optional
33

4-
from pydantic import Field, computed_field
4+
from pydantic import (
5+
ValidationError,
6+
ValidationInfo,
7+
ValidatorFunctionWrapHandler,
8+
WrapValidator,
9+
)
510

611
from .event import IndexedEvent
712

813
ZERO = Decimal(0)
914

1015

16+
def zero_from_none(
17+
v: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
18+
) -> Decimal:
19+
try:
20+
return handler(v)
21+
except ValidationError:
22+
return ZERO
23+
24+
25+
ZeroFromNone = Annotated[Decimal, WrapValidator(zero_from_none)]
26+
27+
1128
class Candle(IndexedEvent):
1229
"""
1330
A Candle event with open, high, low, close prices and other information
@@ -35,40 +52,11 @@ class Candle(IndexedEvent):
3552
imp_volatility: Optional[Decimal] = None
3653
#: open interest in the candle
3754
open_interest: Optional[int] = None
38-
# these fields will not show up in serialization
39-
raw_open: Optional[Decimal] = Field(validation_alias="open", exclude=True)
40-
raw_high: Optional[Decimal] = Field(validation_alias="high", exclude=True)
41-
raw_low: Optional[Decimal] = Field(validation_alias="low", exclude=True)
42-
raw_close: Optional[Decimal] = Field(validation_alias="close", exclude=True)
43-
44-
@computed_field
45-
@property
46-
def open(self) -> Decimal:
47-
"""
48-
the first (open) price of the candle
49-
"""
50-
return self.raw_open or ZERO
51-
52-
@computed_field
53-
@property
54-
def high(self) -> Decimal:
55-
"""
56-
the maximal (high) price of the candle
57-
"""
58-
return self.raw_high or ZERO
59-
60-
@computed_field
61-
@property
62-
def low(self) -> Decimal:
63-
"""
64-
the minimal (low) price of the candle
65-
"""
66-
return self.raw_low or ZERO
67-
68-
@computed_field
69-
@property
70-
def close(self) -> Decimal:
71-
"""
72-
the last (close) price of the candle
73-
"""
74-
return self.raw_close or ZERO
55+
#: the first (open) price of the candle
56+
open: ZeroFromNone
57+
#: the maximal (high) price of the candle
58+
high: ZeroFromNone
59+
#: the minimal (low) price of the candle
60+
low: ZeroFromNone
61+
#: the last (close) price of the candle
62+
close: ZeroFromNone

tastytrade/dxfeed/event.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
from typing import Any, List
1+
from typing import Any
22

33
from pydantic import BaseModel, ConfigDict, ValidationError, field_validator
44
from pydantic.alias_generators import to_camel
55

6-
from tastytrade import logger
76
from tastytrade.utils import TastytradeError
87

98
REMOVE_EVENT = 0x2
@@ -34,7 +33,7 @@ def change_nan_to_none(cls, v: Any) -> Any:
3433
return v
3534

3635
@classmethod
37-
def from_stream(cls, data: list) -> List["Event"]:
36+
def from_stream(cls, data: list) -> list["Event"]:
3837
"""
3938
Makes a list of event objects from a list of raw trade data fetched by
4039
a :class:`~tastyworks.streamer.DXFeedStreamer`.
@@ -56,10 +55,10 @@ def from_stream(cls, data: list) -> List["Event"]:
5655
local_values = data[offset : (i + 1) * size]
5756
event_dict = dict(zip(keys, local_values))
5857
try:
59-
objs.append(cls(**event_dict))
60-
except ValidationError as e:
58+
objs.append(cls.model_validate(event_dict))
59+
except ValidationError:
6160
# we just skip these events as they're generally not helpful
62-
logger.debug(f"Skipping event due to error: {e}")
61+
pass
6362
return objs
6463

6564

tastytrade/order.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from enum import Enum
44
from typing import Any, Optional, Union
55

6-
from pandas_market_calendars.calendar_registry import prop
76
from pydantic import computed_field, field_serializer, model_validator
87

98
from tastytrade import VERSION

0 commit comments

Comments
 (0)