tastytrade Python SDK

repository·master·Indexed 42 days ago

https://github.com/tastyware/tastytrade

An unofficial, typed, asynchronous Python SDK for the Tastytrade public API. It provides tools for creating trading algorithms, managing accounts, placing orders, and streaming real-time market data via DXLinkStreamer and AlertStreamer.

Tokens
28.7K
Snippets
120
Records
137
Agent score
54%

What's inside tastytrade

  1. Overview of the Tastytrade Python SDK

    master

    The tastytrade SDK is a typed, asynchronous Python library built on top of the Tastytrade public API. It is designed to help developers quickly and efficiently build trading algorithms and automated strategies in Python.

    For a practical demonstration of the SDK's capabilities, you can refer to the tastytrade-cli project, which is a command-line interface that showcases many of the SDK's features.

  2. Explore tastytrade.dxfeed data models

    master

    The tastytrade.dxfeed module provides access to various real-time data types via the dxfeed stream. The following data models are available:

    • Event: Base event information.
    • Candle: OHLC (Open, High, Low, Close) bar data.
    • Greeks: Option Greeks data.
    • Profile: Instrument profile information.
    • Quote: Real-time bid/ask quote data.
    • Summary: Aggregated market summary data.
    • TimeAndSale: Individual time and sales transactions.
    • TheoPrice: Theoretical price data.
    • Trade: Individual trade execution data.
    • Underlying: Data related to the underlying asset.
  3. How session token refreshing works

    master

    Tastytrade OAuth sessions use session tokens that expire every 15 minutes. However, the refresh tokens used to obtain new session tokens last indefinitely.

    As of tastytrade>=12.0.0, the SDK handles token refreshing automatically. Every API request made using a Session object will check if the current token is expiring soon and will refresh it behind the scenes if necessary.

  4. How to combine normal and paper sessions

    master

    When writing paper trading applications, use a standard Session for non-account endpoints (like fetching option chains) and a PaperSession for account-related actions (like placing orders). This allows you to simulate production code by using real market data to drive paper trades.

    Example Workflow:

    1. Use Session to fetch an option chain.
    2. Select an option from the chain.
    3. Use PaperSession to place a LimitOrder on a paper account.
    from tastytrade import Session
    from tastytrade.paper import PaperSession
    
    # Use a normal session for market data
    session = Session("MY-SECRET", "MY-REFRESH")
    # Use a paper session for simulated trading
    paper = PaperSession("MY-API-KEY")
    
    # 1. Fetch real option chain data
    chain = (await get_option_chain(session, "SPX"))[date(2026, 4, 17)]
    option = next(
        c
        for c in chain
        if c.option_type == OptionType.CALL and round(c.strike_price) == 7000
    )
    
    # 2. Place order using the paper session
    acc = await Account.get(paper, "TW000014")
    order = LimitOrder(
        legs=[option.build_leg(1, OrderAction.BUY_TO_OPEN)],
        price=-Decimal("3"),
    )
    print(await acc.place_order(paper, order, dry_run=True))
  5. Create a PaperSession for paper trading

    master

    To use the proprietary paper trading API, initialize a PaperSession using your tastyware API key. This session can be used with account-related endpoints (like Account.get) to emulate production behavior.

    Note: The paper API currently only supports equities and index options trades.

    from tastytrade.paper import PaperSession
    
    paper = PaperSession("MY-API-KEY")
  6. Place trades using instrument legs

    master

    To place a trade, convert an instrument into a 'leg' using the build_leg(quantity, order_action) method. A trade (such as a spread or strangle) is constructed by passing a list of these legs to a LimitOrder.

    Key Details:

    • build_leg parameters: Requires quantity (int) and order_action (from tastytrade.order.OrderAction).
    • Pricing: The price in a LimitOrder is per quantity, not the total order price. For example, if you have two legs with a quantity of 2 each and a price of Decimal('1.25'), the total credit/debit is calculated based on that per-unit price.
    • Execution: Use account.place_order(session, order, dry_run=False) to execute the trade.
    from tastytrade.instruments import get_future_option_chain
    from tastytrade.order import LimitOrder, OrderAction
    from datetime import date
    from decimal import Decimal
    
    # 1. Get the chain
    chain = await get_future_option_chain(session, '/MCL')
    
    # 2. Select specific instruments (e.g., a strangle)
    put = chain[date(2024, 3, 15)][286]
    call = chain[date(2024, 3, 15)][187]
    
    # 3. Build the order
    order = LimitOrder(
        legs=[
            put.build_leg(1, OrderAction.SELL_TO_OPEN),
            call.build_leg(1, OrderAction.SELL_TO_OPEN)
        ],
        price=Decimal('1.25')  # This is the price per unit
    )
    
    # 4. Place the order
    await account.place_order(session, order, dry_run=False)
  7. Add symbols to a private watchlist

    master

    You can add symbols to a PrivateWatchlist using the add_symbol method, which requires the symbol string and an InstrumentType.

    Note: Adding a symbol updates the local object state but does not automatically sync with the Tastytrade servers. To persist the changes to the remote server, you must call await watchlist.update(session).

    from tastytrade.instruments import InstrumentType
    
    # Add symbol locally
    watchlist.add_symbol('SPY', InstrumentType.EQUITY)
    
    # Sync changes to the remote server
    await watchlist.update(session)
  8. Implement auto-retries and persistence for AlertStreamer

    master

    Since the SDK does not provide built-in long-lived connection persistence, you should implement a retry loop with exponential backoff. You can catch HTTPXWSException from httpx_ws to handle disconnections and use anyio.sleep to manage the backoff timing.

    from anyio import sleep
    from httpx_ws import HTTPXWSException
    
    tries, max_tries = 0, 3
    while (tries := tries + 1) <= max_tries:
        try:
            async with AlertStreamer(session) as streamer:
                print("Yay! Connected!")
                ...
        except* HTTPXWSException:
            print("Oh no! Disconnected!")
            await sleep(tries ** 2)
  9. Install the tastytrade SDK

    master

    You can install the tastytrade SDK using pip or uv.

    To bootstrap a new project template with agent integration, utilities, and documentation, use the tastytrade-cli via uvx:

    $ pip install tastytrade
    
    $ uvx --from tastytrade-cli bootstrap my_project
  10. How to use streamers in a synchronous context

    master

    You can use async streamers (like DXLinkStreamer) within a synchronous context by using anyio's start_blocking_portal. To manage the streamer's lifecycle, you must wrap its async context manager using portal.wrap_async_context_manager().

    from tastytrade import DXLinkStreamer
    from tastytrade.dxfeed import Quote
    from anyio.from_thread import start_blocking_portal
    
    # Assuming sesh is a valid Session object
    with start_blocking_portal() as portal:
        streamer = DXLinkStreamer(sesh)
        with portal.wrap_async_context_manager(streamer.__asynccontextmanager__()):
            portal.call(streamer.subscribe, Quote, ["SPY"])
            print(portal.call(streamer.get_event, Quote))