Skip to content

Commit

Permalink
begin remove price effects
Browse files Browse the repository at this point in the history
  • Loading branch information
Graeme22 committed Oct 10, 2024
1 parent 0e93f55 commit bfd90ce
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 18 deletions.
4 changes: 2 additions & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
Fixes ...

## Pre-merge checklist
- [ ] Code formatted correctly with `uv run ruff format .`
- [ ] Code formatted correctly (check with `make lint`)
- [ ] Code implemented for both sync and async
- [ ] Passing tests locally
- [ ] Passing tests locally (check with `make test`, make sure you have `TT_USERNAME`, `TT_PASSWORD`, and `TT_ACCOUNT` environment variables set)
- [ ] New tests added (if applicable)

Please note that, in order to pass the tests, you'll need to set up your Tastytrade credentials as repository secrets on your local fork. Read more at CONTRIBUTING.md.
23 changes: 19 additions & 4 deletions tastytrade/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from decimal import Decimal
from typing import Any, Dict, List, Literal, Optional, Union

from pydantic import BaseModel
from pydantic import BaseModel, computed_field, field_serializer, model_validator

from tastytrade.order import (
InstrumentType,
Expand All @@ -13,12 +13,14 @@
PlacedComplexOrder,
PlacedOrder,
PlacedOrderResponse,
PriceEffect,
)
from tastytrade.session import Session
from tastytrade.utils import (
PriceEffect,
TastytradeError,
TastytradeJsonDataclass,
_get_sign,
_set_sign_for,
today_in_new_york,
validate_response,
)
Expand Down Expand Up @@ -61,11 +63,10 @@ class AccountBalance(TastytradeJsonDataclass):
cash_available_to_withdraw: Decimal
day_trade_excess: Decimal
pending_cash: Decimal
pending_cash_effect: PriceEffect
long_cryptocurrency_value: Decimal
short_cryptocurrency_value: Decimal
cryptocurrency_margin_requirement: Decimal
unsettled_cryptocurrency_fiat_amount: Decimal
unsettled_cryptocurrency_fiat_amount: Decimal # TODO: work with _amount suffix
unsettled_cryptocurrency_fiat_effect: PriceEffect
closed_loop_available_balance: Decimal
equity_offering_margin_requirement: Decimal
Expand All @@ -84,6 +85,20 @@ class AccountBalance(TastytradeJsonDataclass):
buying_power_adjustment_effect: Optional[PriceEffect] = None
time_of_day: Optional[str] = None

@computed_field
@property
def pending_cash_effect(self) -> PriceEffect:
return _get_sign(self.pending_cash)

@model_validator(mode="before")
@classmethod
def validate_pending_cash(cls, data: Any) -> Any:
return _set_sign_for(data, "pending_cash")

@field_serializer("pending_cash")
def serialize_pending_cash(self, price: Decimal) -> Decimal:
return abs(price)


class AccountBalanceSnapshot(TastytradeJsonDataclass):
"""
Expand Down
13 changes: 1 addition & 12 deletions tastytrade/order.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Dict, List, Optional, Union

from tastytrade import VERSION
from tastytrade.utils import TastytradeJsonDataclass
from tastytrade.utils import PriceEffect, TastytradeJsonDataclass


class InstrumentType(str, Enum):
Expand Down Expand Up @@ -101,17 +101,6 @@ class ComplexOrderType(str, Enum):
OTOCO = "OTOCO"


class PriceEffect(str, Enum):
"""
This is an :class:`~enum.Enum` that shows the sign of a price effect, since
Tastytrade is apparently against negative numbers.
"""

CREDIT = "Credit"
DEBIT = "Debit"
NONE = "None"


class FillInfo(TastytradeJsonDataclass):
"""
Dataclass that contains information about an order fill.
Expand Down
33 changes: 33 additions & 0 deletions tastytrade/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from datetime import date, datetime, timedelta
from decimal import Decimal
from enum import Enum
from typing import Any

import pandas_market_calendars as mcal # type: ignore
import pytz
Expand All @@ -9,6 +12,17 @@
TZ = pytz.timezone("US/Eastern")


class PriceEffect(str, Enum):
"""
This is an :class:`~enum.Enum` that shows the sign of a price effect, since
Tastytrade is apparently against negative numbers.
"""

CREDIT = "Credit"
DEBIT = "Debit"
NONE = "None"


def now_in_new_york() -> datetime:
"""
Gets the current time in the New York timezone.
Expand Down Expand Up @@ -226,3 +240,22 @@ def validate_response(response: Response) -> None:
error_message += f"\n{error['domain']}: {error['reason']}"

raise TastytradeError(error_message)


def _get_sign(value: Decimal) -> PriceEffect:
return PriceEffect.DEBIT if value < 0 else PriceEffect.CREDIT


def _set_sign_for(data: Any, property: str) -> Any:
"""
Handles setting the sign of a number using the associated "-effect" field.
:param data: the raw, unprocessed model object
:param property: the name of the number field
"""
if isinstance(data, dict):
key = _dasherize(property)
effect = data.get(f"{key}-effect")
if effect == PriceEffect.DEBIT:
data[key] = -abs(Decimal(data[key]))
return data

0 comments on commit bfd90ce

Please sign in to comment.