Skip to content

Commit

Permalink
fix #126, use pydantic w/ dxfeed, don't raise for orders, add more fu…
Browse files Browse the repository at this point in the history
…tures exp utils
  • Loading branch information
Graeme22 committed Feb 9, 2024
1 parent 98881ab commit 3d9e4db
Show file tree
Hide file tree
Showing 19 changed files with 198 additions and 120 deletions.
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
project = 'tastytrade'
copyright = '2023, Graeme Holliday'
author = 'Graeme Holliday'
release = '6.6'
release = '6.7'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
11 changes: 1 addition & 10 deletions docs/tastytrade.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,9 @@ Streamer

Utils
-----
.. module:: tastytrade.utils

.. autoclass:: TastytradeError

.. autofunction:: _dasherize

.. autopydantic_model:: TastytradeJsonDataclass
.. automodule:: tastytrade.utils
:members:
:inherited-members:
:model-show-config-summary:

.. autofunction:: validate_response

Watchlists
----------
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

setup(
name='tastytrade',
version='6.6',
version='6.7',
description='An unofficial SDK for Tastytrade!',
long_description=LONG_DESCRIPTION,
long_description_content_type='text/x-rst',
Expand Down
2 changes: 1 addition & 1 deletion tastytrade/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

API_URL = 'https://api.tastyworks.com'
CERT_URL = 'https://api.cert.tastyworks.com'
VERSION = '6.6'
VERSION = '6.7'

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
Expand Down
7 changes: 6 additions & 1 deletion tastytrade/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import requests
from pydantic import BaseModel

from tastytrade import logger
from tastytrade.order import (InstrumentType, NewComplexOrder, NewOrder,
OrderStatus, PlacedComplexOrder, PlacedOrder,
PlacedOrderResponse, PriceEffect)
Expand Down Expand Up @@ -1022,7 +1023,11 @@ def place_order(
json = order.json(exclude_none=True, by_alias=True)

response = requests.post(url, headers=session.headers, data=json)
validate_response(response)
# sometimes we just want to see BP usage for an invalid trade
try:
validate_response(response)
except TastytradeError as error:
logger.error(error)

data = response.json()['data']

Expand Down
24 changes: 12 additions & 12 deletions tastytrade/dxfeed/candle.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from dataclasses import dataclass
from decimal import Decimal
from typing import Optional

from .event import Event


@dataclass
class Candle(Event):
"""
A Candle event with open, high, low, close prices and other information
Expand All @@ -25,22 +25,22 @@ class Candle(Event):
#: total number of events in the candle
count: int
#: the first (open) price of the candle
open: float
open: Optional[Decimal] = None
#: the maximal (high) price of the candle
high: float
high: Optional[Decimal] = None
#: the minimal (low) price of the candle
low: float
low: Optional[Decimal] = None
#: the last (close) price of the candle
close: float
close: Optional[Decimal] = None
#: the total volume of the candle
volume: int
volume: Optional[int] = None
#: volume-weighted average price
vwap: float
vwap: Optional[Decimal] = None
#: bid volume in the candle
bidVolume: int
bidVolume: Optional[int] = None
#: ask volume in the candle
askVolume: int
askVolume: Optional[int] = None
#: implied volatility in the candle
impVolatility: float
impVolatility: Optional[Decimal] = None
#: open interest in the candle
openInterest: int
openInterest: Optional[int] = None
17 changes: 13 additions & 4 deletions tastytrade/dxfeed/event.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from abc import ABC
from enum import Enum
from typing import List

from pydantic import BaseModel, validator

from tastytrade.utils import TastytradeError


class EventType(str, Enum):
"""
Expand All @@ -24,7 +27,13 @@ class EventType(str, Enum):
UNDERLYING = 'Underlying'


class Event(ABC):
class Event(BaseModel):
@validator('*', pre=True)
def change_nan_to_none(cls, v):
if v == 'NaN':
return None
return v

@classmethod
def from_stream(cls, data: list) -> List['Event']: # pragma: no cover
"""
Expand All @@ -36,11 +45,11 @@ def from_stream(cls, data: list) -> List['Event']: # pragma: no cover
:return: list of event objects from data
"""
objs = []
size = len(cls.__dataclass_fields__) # type: ignore
size = len(cls.__fields__)
multiples = len(data) / size
if not multiples.is_integer():
msg = 'Mapper data input values are not a multiple of the key size'
raise Exception(msg)
raise TastytradeError(msg)
for i in range(int(multiples)):
offset = i * size
local_values = data[offset:(i + 1) * size]
Expand Down
17 changes: 8 additions & 9 deletions tastytrade/dxfeed/greeks.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from dataclasses import dataclass
from decimal import Decimal

from .event import Event


@dataclass
class Greeks(Event):
"""
Greek ratios, or simply Greeks, are differential values that show how the
Expand All @@ -26,16 +25,16 @@ class Greeks(Event):
#: sequence number to distinguish events that have the same time
sequence: int
#: option market price
price: float
price: Decimal
#: Black-Scholes implied volatility of the option
volatility: float
volatility: Decimal
#: option delta
delta: float
delta: Decimal
#: option gamma
gamma: float
gamma: Decimal
#: option theta
theta: float
theta: Decimal
#: option rho
rho: float
rho: Decimal
#: option vega
vega: float
vega: Decimal
40 changes: 20 additions & 20 deletions tastytrade/dxfeed/profile.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from dataclasses import dataclass
from decimal import Decimal
from typing import Optional

from .event import Event


@dataclass
class Profile(Event):
"""
A Profile event provides the security instrument description. It
Expand All @@ -22,31 +22,31 @@ class Profile(Event):
#: trading status of the security instrument
#: possible values are ACTIVE | HALTED | UNDEFINED
tradingStatus: str
#: description of the reason that trading was halted
statusReason: str
#: starting time of the trading halt interval
haltStartTime: int
#: ending time of the trading halt interval
haltEndTime: int
#: maximal (high) allowed price
highLimitPrice: float
#: minimal (low) allowed price
lowLimitPrice: float
#: identifier of the ex-dividend date
exDividendDayId: int
#: description of the reason that trading was halted
statusReason: Optional[str] = None
#: maximal (high) price in last 52 weeks
high52WeekPrice: float
high52WeekPrice: Optional[Decimal] = None
#: minimal (low) price in last 52 weeks
low52WeekPrice: float
low52WeekPrice: Optional[Decimal] = None
#: the correlation coefficient of the instrument to the S&P500 index
beta: float
beta: Optional[Decimal] = None
#: shares outstanding
shares: Optional[Decimal] = None
#: maximal (high) allowed price
highLimitPrice: Optional[Decimal] = None
#: minimal (low) allowed price
lowLimitPrice: Optional[Decimal] = None
#: earnings per share
earningsPerShare: float
#: frequency of cash dividends payments per year (calculated)
dividendFrequency: float
earningsPerShare: Optional[Decimal] = None
#: the amount of the last paid dividend
exDividendAmount: float
#: identifier of the ex-dividend date
exDividendDayId: int
#: shares outstanding
shares: float
exDividendAmount: Optional[Decimal] = None
#: frequency of cash dividends payments per year (calculated)
dividendFrequency: Optional[Decimal] = None
#: the number of shares that are available to the public for trade
freeFloat: float
freeFloat: Optional[Decimal] = None
16 changes: 8 additions & 8 deletions tastytrade/dxfeed/quote.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from dataclasses import dataclass
from decimal import Decimal
from typing import Optional

from .event import Event


@dataclass
class Quote(Event):
"""
A Quote event is a snapshot of the best bid and ask prices, and other
Expand All @@ -21,15 +21,15 @@ class Quote(Event):
bidTime: int
#: bid exchange code
bidExchangeCode: str
#: bid price
bidPrice: float
#: bid size as integer number (rounded toward zero)
bidSize: int
#: time of the last ask change
askTime: int
#: ask exchange code
askExchangeCode: str
#: bid price
bidPrice: Optional[Decimal] = None
#: ask price
askPrice: float
askPrice: Optional[Decimal] = None
#: bid size as integer number (rounded toward zero)
bidSize: Optional[int] = None
#: ask size as integer number (rounded toward zero)
askSize: int
askSize: Optional[int] = None
28 changes: 14 additions & 14 deletions tastytrade/dxfeed/summary.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from dataclasses import dataclass
from decimal import Decimal
from typing import Optional

from .event import Event


@dataclass
class Summary(Event):
"""
Summary is an information snapshot about the trading session including
Expand All @@ -22,25 +22,25 @@ class Summary(Event):
eventTime: int
#: identifier of the day that this summary represents
dayId: int
#: the first (open) price for the day
dayOpenPrice: float
#: the maximal (high) price for the day
dayHighPrice: float
#: the minimal (low) price for the day
dayLowPrice: float
#: the last (close) price for the day
dayClosePrice: float
#: the price type of the last (close) price for the day
#: possible values are FINAL | INDICATIVE | PRELIMINARY | REGULAR
dayClosePriceType: str
#: identifier of the previous day that this summary represents
prevDayId: int
#: the last (close) price for the previous day
prevDayClosePrice: float
#: the price type of the last (close) price for the previous day
#: possible values are FINAL | INDICATIVE | PRELIMINARY | REGULAR
prevDayClosePriceType: str
#: total volume traded for the previous day
prevDayVolume: float
#: open interest of the symbol as the number of open contracts
openInterest: int
#: the first (open) price for the day
dayOpenPrice: Optional[Decimal] = None
#: the maximal (high) price for the day
dayHighPrice: Optional[Decimal] = None
#: the minimal (low) price for the day
dayLowPrice: Optional[Decimal] = None
#: the last (close) price for the day
dayClosePrice: Optional[Decimal] = None
#: the last (close) price for the previous day
prevDayClosePrice: Optional[Decimal] = None
#: total volume traded for the previous day
prevDayVolume: Optional[Decimal] = None
15 changes: 7 additions & 8 deletions tastytrade/dxfeed/theoprice.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from dataclasses import dataclass
from decimal import Decimal

from .event import Event


@dataclass
class TheoPrice(Event):
"""
Theo price is a snapshot of the theoretical option price computation that
Expand All @@ -25,14 +24,14 @@ class TheoPrice(Event):
#: sequence number to distinguish events that have the same time
sequence: int
#: theoretical price
price: float
price: Decimal
#: underlying price at the time of theo price computation
underlyingPrice: float
underlyingPrice: Decimal
#: delta of the theoretical price
delta: float
delta: Decimal
#: gamma of the theoretical price
gamma: float
gamma: Decimal
#: implied simple dividend return of the corresponding option series
dividend: float
dividend: Decimal
#: implied simple interest return of the corresponding option series
interest: float
interest: Decimal
9 changes: 4 additions & 5 deletions tastytrade/dxfeed/timeandsale.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from dataclasses import dataclass
from decimal import Decimal

from .event import Event


@dataclass
class TimeAndSale(Event):
"""
TimeAndSale event represents a trade or other market event with a price,
Expand All @@ -30,13 +29,13 @@ class TimeAndSale(Event):
#: exchange code of this time and sale event
exchangeCode: str
#: price of this time and sale event
price: float
price: Decimal
#: size of this time and sale event as integer number (rounded toward zero)
size: int
#: the bid price on the market when this time and sale event occured
bidPrice: float
bidPrice: Decimal
#: the ask price on the market when this time and sale event occured
askPrice: float
askPrice: Decimal
#: sale conditions provided for this event by data feed
exchangeSaleConditions: str
#: transaction is concluded by exempting from compliance with some rule
Expand Down
Loading

0 comments on commit 3d9e4db

Please sign in to comment.