tastyware / tastytrade

An unofficial, sync/async Python SDK for Tastytrade!
https://tastyworks-api.rtfd.io
MIT License
126 stars 43 forks source link

Websocket never closes for certain quotes #155

Closed r0fls closed 5 months ago

r0fls commented 5 months ago

Describe the bug There is no way to simply retrieve a quote without opening a websocket. Is this a flaw with the Tastytrade API?

How to reproduce This code never releases the websocket it opens when I try to get certain options quotes:

https://github.com/r0fls/soad/blob/main/brokers/tastytrade_broker.py#L252-L260

    async def get_current_price(self, symbol):                                                                            
        streamer = await DXLinkStreamer.create(self.session)                                                              
        try:                                                                                                              
            subs_list = [symbol]                                                                                          
            await streamer.subscribe(EventType.QUOTE, subs_list)                                                          
            quote = await streamer.get_event(EventType.QUOTE)                                                             
            return round(float((quote.bidPrice + quote.askPrice) / 2), 2)                                                 
        finally:                                                                                                          
            await streamer.close()    

I have tried various other implementations as well. It feels I may have to resort to using an alternate data provider, since I can't find any REST methods to get quotes on the TastyTrade API docs. Anyway the above code produces this output, whereas I don't want to establish a keep alive or stream anything, I just want a singular quote. Note this doesn't occur with all quotes, regular stock quotes seem to close gracefully. I was getting this with the symbol QQQ 240703C00482000 as seen in this log line: DEBUG:tastytrade:sending subscription: {'type': 'FEED_SUBSCRIPTION', 'channel': 7, 'add': [{'symbol': 'QQQ 240703C00482000', 'type': <EventType.QUOTE: 'Quote'>}]}:

Websocket not closing

DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:received: {'type': 'KEEPALIVE', 'channel': 0}
DEBUG:tastytrade:sending keepalive message: {'type': 'KEEPALIVE', 'channel': 0}
Graeme22 commented 5 months ago

Hello! Yes, unfortunately the dxfeed REST API, which used to be available, is no longer accessible to Tastytrade users. So the streamer is required.

The problem you're having is due to using Tastytrade symbology instead of dxfeed symbology.

In the example in the README, you'll see the use of the streamer_symbol field here: https://tastyworks-api.readthedocs.io/en/latest/index.html#options-chain-streaming-greeks.

r0fls commented 5 months ago

Got it, thanks so much for the quick answer! 🙏

Would you be able to provide an example by chance of retrieving a quote given a string symbol for an option? I'm having a bit of trouble figuring it out, I would be happy to update the docs or readme with it in case others have the same question.

Basically I am given something like: SPY240705P00540000 and want to retrieve a quote for it. I'm converting that to this format quite easily but as you can see that's not enough to interface with this DXStreamer thing:

>>> tastytrade_broker.TastytradeBroker.format_option_symbol('SPY240705P00540000')
'SPY   240705P00540000'

My goal is to create an algorithmic trading system with an interface that is somewhat "broker agnostic", which is why I want regular quotes here. Thanks again!

Graeme22 commented 5 months ago

The SDK actually includes a utility function for that here: https://tastyworks-api.readthedocs.io/en/latest/tastytrade.html#tastytrade.instruments.Option.occ_to_streamer_symbol

from tastytrade.instruments import Option
print(Option.occ_to_streamer_symbol('SPY   240705P00540000'))

This outputs: .SPY240705P540 which can then be used with the streamer.

r0fls commented 5 months ago

Sweet, thanks so much! Closing this out then.