Skip to content

tastyware/tastytrade:v9.4

Compare
Choose a tag to compare
@Graeme22 Graeme22 released this 10 Dec 20:22
· 4 commits to master since this release
ce5ef1d

What's Changed

The datetime-related utilities in tastytrade.utils suffered from a hard-to-detect bug related to variable Python default arguments. These utilities will work correctly now, whereas previously something like this:

from tastytrade.utils import is_market_open_on
print(is_market_open_on())
# 5 hours later...
print(is_market_open_on())

could potentially yield incorrect results in long-running programs. This now behaves as expected, and no code changes are required.

This partially reverts the changes in v9.3 which excluded all Candle events without OHLC fields. @JBlohm brought to attention that these "empty" candles can still contain important information in the event_flags field. This was solved by re-allowing the empty candles (while still ensuring None values provided will be set to 0, which allows for filtering them out without messing with the types), and as a bonus a new class, tastytrade.dxfeed.IndexedEvent, was added which allows for easily parsing the event_flags field, which otherwise required some bitwise math. So upgrading will look something like this:

candles = []
async for candle in streamer.listen(Candle):
    if not Decimal.is_zero(candle.open):  # filter out invalid candles
        candles.append(candle)
    else:
        print(candle.snapshot_end)  # handle event flags

This updates the websockets dependency to >=14.1 and uses the new async websockets features to implement auto-reconnect functionality upon certain connection errors. This takes effect automatically and doesn't require any code changes. However, the reconnection algorithm's behavior can be modified through environment variables, documented here.

Building on the auto-reconnection functionality, this PR introduces callback functions that can be ran upon reconnection to handle common tasks, for example, re-subscribing to alerts or events. Here's how this looks:

async def callback(streamer: DXLinkStreamer, arg1, arg2):
    await streamer.subscribe(Trade, ["SPX"])
    print(arg1 + arg2)

async with DXLinkStreamer(session, reconnect_args=(arg1, arg2), reconnect_fn=callback) as streamer:
    pass

The first argument for the callback will always be the streamer itself; after that, the number and type of arguments is determined by your use case.
Additionally, a small change was made to the existing AlertStreamer.create and DXLinkStreamer.create functions. They have been switched to a simpler syntax that allows you to await the constructor directly. So this code:

streamer = await AlertStreamer.create(session)

becomes:

streamer = await AlertStreamer(session)

Full Changelog: v9.3...v9.4