diff --git a/README.md b/README.md index 2882602..cc72710 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,17 @@ # Tastytrade Python SDK -A simple, reverse-engineered, sync/async SDK for Tastytrade built on their (now mostly public) API. This will allow you to create trading algorithms for whatever strategies you may have quickly and painlessly in Python. +A simple, reverse-engineered SDK for Tastytrade built on their (now mostly public) API. This will allow you to create trading algorithms for whatever strategies you may have quickly and painlessly in Python. + +## Features + +- Up to 10x less code than using the API directly +- Sync/async functions for all endpoints +- Powerful websocket implementation for account alerts and data streaming, with support for auto-reconnection and reconnection callbacks +- 100% typed, with Pydantic models for all JSON responses from the API +- 95%+ unit test coverage +- Comprehensive documentation +- Utility functions for timezone calculations, futures monthly expiration dates, and more > [!NOTE] > Want to see the SDK in action? Check out [tastytrade-cli](https://github.com/tastyware/tastytrade-cli), a CLI for Tastytrade that showcases many of the SDK's features. @@ -43,7 +53,7 @@ async with DXLinkStreamer(session) as streamer: ``` ```python ->>> Quote(eventSymbol='SPY', eventTime=0, sequence=0, timeNanoPart=0, bidTime=0, bidExchangeCode='Q', bidPrice=411.58, bidSize=400.0, askTime=0, askExchangeCode='Q', askPrice=411.6, askSize=1313.0) +>>> Quote(event_symbol='SPY', event_time=0, sequence=0, time_nano_part=0, bid_time=0, bid_exchange_code='Q', bid_price=411.58, bid_size=400.0, ask_time=0, ask_exchange_code='Q', ask_price=411.6, ask_size=1313.0) ``` Note that this is asynchronous code, so you can't run it as is unless you're using a Jupyter notebook or something similar. @@ -59,7 +69,7 @@ print(positions[0]) ``` ```python ->>> CurrentPosition(account_number='5WX01234', symbol='IAU', instrument_type=, underlying_symbol='IAU', quantity=Decimal('20'), quantity_direction='Long', close_price=Decimal('37.09'), average_open_price=Decimal('37.51'), average_yearly_market_close_price=Decimal('37.51'), average_daily_market_close_price=Decimal('37.51'), multiplier=1, cost_effect='Credit', is_suppressed=False, is_frozen=False, realized_day_gain=Decimal('7.888'), realized_day_gain_effect='Credit', realized_day_gain_date=datetime.date(2023, 5, 19), realized_today=Decimal('0.512'), realized_today_effect='Debit', realized_today_date=datetime.date(2023, 5, 19), created_at=datetime.datetime(2023, 3, 31, 14, 38, 32, 58000, tzinfo=datetime.timezone.utc), updated_at=datetime.datetime(2023, 5, 19, 16, 56, 51, 920000, tzinfo=datetime.timezone.utc), mark=None, mark_price=None, restricted_quantity=Decimal('0'), expires_at=None, fixing_price=None, deliverable_type=None) +>>> CurrentPosition(account_number='5WX01234', symbol='IAU', instrument_type=, underlying_symbol='IAU', quantity=Decimal('20'), quantity_direction='Long', close_price=Decimal('37.09'), average_open_price=Decimal('37.51'), average_yearly_market_close_price=Decimal('37.51'), average_daily_market_close_price=Decimal('37.51'), multiplier=1, cost_effect=, is_suppressed=False, is_frozen=False, realized_day_gain=Decimal('7.888'), realized_day_gain_date=datetime.date(2023, 5, 19), realized_today=Decimal('-0.512'), realized_today_date=datetime.date(2023, 5, 19), created_at=datetime.datetime(2023, 3, 31, 14, 38, 32, 58000, tzinfo=datetime.timezone.utc), updated_at=datetime.datetime(2023, 5, 19, 16, 56, 51, 920000, tzinfo=datetime.timezone.utc), mark=None, mark_price=None, restricted_quantity=Decimal('0'), expires_at=None, fixing_price=None, deliverable_type=None) ``` ## Placing an order @@ -85,7 +95,7 @@ print(response) ``` ```python ->>> PlacedOrderResponse(buying_power_effect=BuyingPowerEffect(change_in_margin_requirement=Decimal('125.0'), change_in_margin_requirement_effect=, change_in_buying_power=Decimal('125.004'), change_in_buying_power_effect=, current_buying_power=Decimal('1000.0'), current_buying_power_effect=, new_buying_power=Decimal('874.996'), new_buying_power_effect=, isolated_order_margin_requirement=Decimal('125.0'), isolated_order_margin_requirement_effect=, is_spread=False, impact=Decimal('125.004'), effect=), fee_calculation=FeeCalculation(regulatory_fees=Decimal('0.0'), regulatory_fees_effect=, clearing_fees=Decimal('0.004'), clearing_fees_effect=, commission=Decimal('0.0'), commission_effect=, proprietary_index_option_fees=Decimal('0.0'), proprietary_index_option_fees_effect=, total_fees=Decimal('0.004'), total_fees_effect=), order=PlacedOrder(account_number='5WV69754', time_in_force=, order_type=, size='5', underlying_symbol='USO', underlying_instrument_type=, status=, cancellable=True, editable=True, edited=False, updated_at=datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc), legs=[Leg(instrument_type=, symbol='USO', action=, quantity=Decimal('5'), remaining_quantity=Decimal('5'), fills=[])], id=None, price=Decimal('50.0'), price_effect=, gtc_date=None, value=None, value_effect=None, stop_trigger=None, contingent_status=None, confirmation_status=None, cancelled_at=None, cancel_user_id=None, cancel_username=None, replacing_order_id=None, replaces_order_id=None, in_flight_at=None, live_at=None, received_at=None, reject_reason=None, user_id=None, username=None, terminal_at=None, complex_order_id=None, complex_order_tag=None, preflight_id=None, order_rule=None), complex_order=None, warnings=[Message(code='tif_next_valid_sesssion', message='Your order will begin working during next valid session.', preflight_id=None)], errors=None) +>>> PlacedOrderResponse(buying_power_effect=BuyingPowerEffect(change_in_margin_requirement=Decimal('-125.0'), change_in_buying_power=Decimal('-125.004'), current_buying_power=Decimal('1000.0'), new_buying_power=Decimal('874.996'), isolated_order_margin_requirement=Decimal('-125.0'), is_spread=False, impact=Decimal('125.004'), effect=), fee_calculation=FeeCalculation(regulatory_fees=Decimal('0.0'), clearing_fees=Decimal('-0.004'), commission=Decimal('0.0'), proprietary_index_option_fees=Decimal('0.0'), total_fees=Decimal('-0.004'), order=PlacedOrder(account_number='5WV69754', time_in_force=, order_type=, size='5', underlying_symbol='USO', underlying_instrument_type=, status=, cancellable=True, editable=True, edited=False, updated_at=datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc), legs=[Leg(instrument_type=, symbol='USO', action=, quantity=Decimal('5'), remaining_quantity=Decimal('5'), fills=[])], id=None, price=Decimal('-10.0'), gtc_date=None, value=None, stop_trigger=None, contingent_status=None, confirmation_status=None, cancelled_at=None, cancel_user_id=None, cancel_username=None, replacing_order_id=None, replaces_order_id=None, in_flight_at=None, live_at=None, received_at=None, reject_reason=None, user_id=None, username=None, terminal_at=None, complex_order_id=None, complex_order_tag=None, preflight_id=None, order_rule=None), complex_order=None, warnings=[Message(code='tif_next_valid_sesssion', message='Your order will begin working during next valid session.', preflight_id=None)], errors=None) ``` ## Options chain/streaming greeks @@ -107,7 +117,7 @@ async with DXLinkStreamer(session) as streamer: ``` ```python ->>> [Greeks(eventSymbol='.SPLG230616C23', eventTime=0, eventFlags=0, index=7235129486797176832, time=1684559855338, sequence=0, price=26.3380972233688, volatility=0.396983376650804, delta=0.999999999996191, gamma=4.81989763184255e-12, theta=-2.5212017514875e-12, rho=0.01834504287973133, vega=3.7003015672215e-12)] +>>> [Greeks(event_symbol='.SPLG230616C23', event_time=0, event_flags=0, index=7235129486797176832, time=1684559855338, sequence=0, price=26.3380972233688, volatility=0.396983376650804, delta=0.999999999996191, gamma=4.81989763184255e-12, theta=-2.5212017514875e-12, rho=0.01834504287973133, vega=3.7003015672215e-12)] ``` For more examples, check out the [documentation](https://tastyworks-api.readthedocs.io/en/latest/).