Skip to content

Commit

Permalink
requests to httpx
Browse files Browse the repository at this point in the history
  • Loading branch information
Graeme22 committed Sep 30, 2024
1 parent 703f8e4 commit 881388f
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 1,602 deletions.
3 changes: 2 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# https://www.sphinx-doc.org/en/master/usage/configuration.html
import os
import sys

sys.path.insert(0, os.path.abspath(".."))

# -- Project information -----------------------------------------------------
Expand All @@ -12,7 +13,7 @@
project = "tastytrade"
copyright = "2024, Graeme Holliday"
author = "Graeme Holliday"
release = "8.4"
release = "8.5"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
4 changes: 1 addition & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "tastytrade"
version = "8.4"
version = "8.5"
description = "An unofficial SDK for Tastytrade!"
readme = "README.md"
requires-python = ">=3.8"
Expand All @@ -14,7 +14,6 @@ dependencies = [
"httpx>=0.27.2",
"pandas-market-calendars>=4.4.1",
"pydantic>=2.9.2",
"requests>=2.32.3",
"websockets>=13.1",
]

Expand All @@ -31,7 +30,6 @@ dev-dependencies = [
"ruff>=0.6.7",
"types-pytz>=2024.2.0.20240913",
"types-requests>=2.32.0.20240914",
"jupyter>=1.1.1",
]

[tool.setuptools.package-data]
Expand Down
2 changes: 1 addition & 1 deletion tastytrade/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
API_URL = "https://api.tastyworks.com"
BACKTEST_URL = "https://backtester.vast.tastyworks.com"
CERT_URL = "https://api.cert.tastyworks.com"
VERSION = "8.4"
VERSION = "8.5"

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
Expand Down
39 changes: 19 additions & 20 deletions tastytrade/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ def get_balance_snapshots(
snapshots = []
while True:
response = session.client.get(
(f"{session.base_url}/accounts/{self.account_number}/balance-snapshots"),
f"/accounts/{self.account_number}/balance-snapshots",
params={
k: v # type: ignore
for k, v in params.items()
Expand All @@ -521,7 +521,9 @@ def get_balance_snapshots(
)
validate_response(response)
json = response.json()
snapshots.extend([AccountBalanceSnapshot(**i) for i in json["data"]["items"]])
snapshots.extend(
[AccountBalanceSnapshot(**i) for i in json["data"]["items"]]
)
# handle pagination
pagination = json["pagination"]
if (
Expand Down Expand Up @@ -564,7 +566,7 @@ def get_positions(
params = {
"underlying-symbol[]": underlying_symbols,
"symbol": symbol,
"instrument-type": instrument_type,
"instrument-type": instrument_type.value if instrument_type else None,
"include-closed-positions": include_closed,
"underlying-product-code": underlying_product_code,
"partition-keys[]": partition_keys,
Expand Down Expand Up @@ -638,7 +640,7 @@ def get_history(
"sub-type[]": sub_types,
"start-date": start_date,
"end-date": end_date,
"instrument-type": instrument_type,
"instrument-type": instrument_type.value if instrument_type else None,
"symbol": symbol,
"underlying-symbol": underlying_symbol,
"action": action,
Expand All @@ -651,7 +653,7 @@ def get_history(
txns = []
while True:
response = session.client.get(
(f"{session.base_url}/accounts/{self.account_number}" f"/transactions"),
f"/accounts/{self.account_number}/transactions",
params={
k: v # type: ignore
for k, v in params.items()
Expand Down Expand Up @@ -679,7 +681,7 @@ def get_transaction(self, session: Session, id: int) -> Transaction:
:param session: the session to use for the request.
:param id: the ID of the transaction to fetch.
"""
data = session.get(f"/accounts/{self.account_number}/transactions/" f"{id}")
data = session.get(f"/accounts/{self.account_number}/transactions/{id}")
return Transaction(**data)

def get_total_fees(
Expand Down Expand Up @@ -765,7 +767,7 @@ def get_margin_requirements(self, session: Session) -> MarginReport:
:param session: the session to use for the request.
"""
data = session.get(f"/margin/accounts/{self.account_number}" f"/requirements")
data = session.get(f"/margin/accounts/{self.account_number}/requirements")
return MarginReport(**data)

def get_live_orders(self, session: Session) -> List[PlacedOrder]:
Expand All @@ -783,7 +785,7 @@ def get_live_complex_orders(self, session: Session) -> List[PlacedComplexOrder]:
:param session: the session to use for the request.
"""
data = session.get(f"/accounts/{self.account_number}/complex-" f"orders/live")
data = session.get(f"/accounts/{self.account_number}/complex-orders/live")
return [PlacedComplexOrder(**i) for i in data["items"]]

def get_complex_order(self, session: Session, order_id: int) -> PlacedComplexOrder:
Expand All @@ -793,9 +795,7 @@ def get_complex_order(self, session: Session, order_id: int) -> PlacedComplexOrd
:param session: the session to use for the request.
:param order_id: the ID of the order to fetch.
"""
data = session.get(
f"/accounts/{self.account_number}/complex-" f"orders/{order_id}"
)
data = session.get(f"/accounts/{self.account_number}/complex-orders/{order_id}")
return PlacedComplexOrder(**data)

def get_order(self, session: Session, order_id: int) -> PlacedOrder:
Expand All @@ -805,7 +805,7 @@ def get_order(self, session: Session, order_id: int) -> PlacedOrder:
:param session: the session to use for the request.
:param order_id: the ID of the order to fetch.
"""
data = session.get(f"/accounts/{self.account_number}/orders" f"/{order_id}")
data = session.get(f"/accounts/{self.account_number}/orders/{order_id}")
return PlacedOrder(**data)

def delete_complex_order(self, session: Session, order_id: int) -> None:
Expand All @@ -815,7 +815,7 @@ def delete_complex_order(self, session: Session, order_id: int) -> None:
:param session: the session to use for the request.
:param order_id: the ID of the order to delete.
"""
session.delete(f"/accounts/{self.account_number}/complex-" f"orders/{order_id}")
session.delete(f"/accounts/{self.account_number}/complex-orders/{order_id}")

def delete_order(self, session: Session, order_id: int) -> None:
"""
Expand Down Expand Up @@ -873,9 +873,11 @@ def get_order_history(
"start-date": start_date,
"end-date": end_date,
"underlying-symbol": underlying_symbol,
"status[]": statuses,
"status[]": [s.value for s in statuses] if statuses else None,
"futures-symbol": futures_symbol,
"underlying-instrument-type": underlying_instrument_type,
"underlying-instrument-type": underlying_instrument_type.value
if underlying_instrument_type
else None,
"sort": sort,
"start-at": start_at,
"end-at": end_at,
Expand All @@ -884,7 +886,7 @@ def get_order_history(
orders = []
while True:
response = session.client.get(
f"{session.base_url}/accounts/{self.account_number}/orders",
f"/accounts/{self.account_number}/orders",
params={
k: v # type: ignore
for k, v in params.items()
Expand Down Expand Up @@ -927,10 +929,7 @@ def get_complex_order_history(
orders = []
while True:
response = session.client.get(
(
f"{session.base_url}/accounts/{self.account_number}"
f"/complex-orders"
),
f"/accounts/{self.account_number}/complex-orders",
params={k: v for k, v in params.items() if v is not None},
)
validate_response(response)
Expand Down
4 changes: 2 additions & 2 deletions tastytrade/instruments.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ def get_active_equities(
equities = []
while True:
response = session.client.get(
f"{session.base_url}/instruments/equities/active",
"/instruments/equities/active",
params={k: v for k, v in params.items() if v is not None},
)
validate_response(response)
Expand Down Expand Up @@ -773,7 +773,7 @@ def get_future_options(
"symbol[]": symbols,
"option-root-symbol": root_symbol,
"expiration-date": expiration_date,
"option-type": option_type,
"option-type": option_type.value if option_type else None,
"strike-price": strike_price,
}
data = session.get(
Expand Down
2 changes: 1 addition & 1 deletion tastytrade/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def symbol_search(session: Session, symbol: str) -> List[SymbolData]:
:param symbol: search phrase
"""
symbol = symbol.replace("/", "%2F")
response = session.client.get(f"{session.base_url}/symbols/search/" f"{symbol}")
response = session.client.get(f"/symbols/search/{symbol}")
if response.status_code // 100 != 2:
# here it doesn't really make sense to throw an exception
return []
Expand Down
27 changes: 13 additions & 14 deletions tastytrade/session.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Any, Dict, Optional

import requests
import httpx
from fake_useragent import UserAgent # type: ignore

from tastytrade import API_URL, CERT_URL
Expand Down Expand Up @@ -50,10 +50,8 @@ def __init__(
body["remember-token"] = remember_token
else:
raise TastytradeError(
"You must provide a password or remember " "token to log in."
"You must provide a password or remember token to log in."
)
# The base url to use for API requests
self.base_url = CERT_URL if is_test else API_URL
#: Whether this is a cert or real session
self.is_test = is_test
# The headers to use for API requests
Expand All @@ -63,16 +61,17 @@ def __init__(
"User-Agent": UserAgent().random,
}
# Set client for requests
self.client = requests.Session()
self.client.headers.update(headers)
self.client = httpx.Client(
base_url=(CERT_URL if is_test else API_URL), headers=headers
)
if two_factor_authentication is not None:
response = self.client.post(
f"{self.base_url}/sessions",
"/sessions",
json=body,
headers={"X-Tastyworks-OTP": two_factor_authentication},
)
else:
response = self.client.post(f"{self.base_url}/sessions", json=body)
response = self.client.post("/sessions", json=body)
validate_response(response) # throws exception if not 200

json = response.json()
Expand All @@ -98,22 +97,22 @@ def __init__(
self.dxlink_url = data["dxlink-url"]

def get(self, url, **kwargs) -> Dict[str, Any]:
response = self.client.get(self.base_url + url, timeout=30, **kwargs)
response = self.client.get(url, timeout=30, **kwargs)
return self._validate_and_parse(response)

def delete(self, url, **kwargs) -> None:
response = self.client.delete(self.base_url + url, **kwargs)
response = self.client.delete(url, **kwargs)
validate_response(response)

def post(self, url, **kwargs) -> Dict[str, Any]:
response = self.client.post(self.base_url + url, **kwargs)
response = self.client.post(url, **kwargs)
return self._validate_and_parse(response)

def put(self, url, **kwargs) -> Dict[str, Any]:
response = self.client.put(self.base_url + url, **kwargs)
response = self.client.put(url, **kwargs)
return self._validate_and_parse(response)

def _validate_and_parse(self, response: requests.Response) -> Dict[str, Any]:
def _validate_and_parse(self, response: httpx._models.Response) -> Dict[str, Any]:
validate_response(response)
return response.json()["data"]

Expand All @@ -123,7 +122,7 @@ def validate(self) -> bool:
:return: True if the session is valid and False otherwise.
"""
response = self.client.post(f"{self.base_url}/sessions/validate")
response = self.client.post("/sessions/validate")
return response.status_code // 100 == 2

def destroy(self) -> None:
Expand Down
6 changes: 2 additions & 4 deletions tastytrade/utils.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from datetime import date, datetime, timedelta
from typing import Union

import pandas_market_calendars as mcal # type: ignore
import pytz
from httpx._models import Response as HTTPXReponse
from httpx._models import Response
from pydantic import BaseModel
from requests import Response

NYSE = mcal.get_calendar("NYSE")
TZ = pytz.timezone("US/Eastern")
Expand Down Expand Up @@ -210,7 +208,7 @@ class Config:
populate_by_name = True


def validate_response(response: Union[Response, HTTPXReponse]) -> None:
def validate_response(response: Response) -> None:
"""
Checks if the given code is an error; if so, raises an exception.
Expand Down
Loading

0 comments on commit 881388f

Please sign in to comment.