Search code examples
pythontwistedpysimpleguialpha-vantage

How to update a GUI window in Python?


My goal is to have a window with the latest quote of a stock updating during the day. I chose alpha_vantage as a quote source, pysimplegui to create the window and twisted to run a loop to update the window every minute. The code works as written, prints the correct quote and change, creates the window as desired, but the window does not update.

Why doesn't the window update?

from alpha_vantage.timeseries import TimeSeries
from twisted.internet import task, reactor
import PySimpleGUI as sg

def paintQuote():
    quote, quote_meta = av.get_intraday(symbol='spy', interval = '1min')
    last = quote.iloc[-1][3]
    print('{0:6.2f}'.format(last))
    change = (last / yesterday - 1) * 100
    print('{0:4.2f}%'.format(change))
    event, values = window.read()
    window['quote'].update(last)

# window color
sg.theme('BluePurple')
# window layout
layout = [[sg.Text('last price', size=(20, 2), justification='center')],
            [sg.Text(''), sg.Text(size=(24,1), key='quote')]]
# create window
window = sg.Window('MikeQuote', layout)
wait = 60.0
av = TimeSeries(key ='your_key', output_format = 'pandas')
yest, yest_meta = av.get_daily(symbol='spy')
yesterday = yest.iloc[-2][3]
loop = task.LoopingCall(paintQuote)
loop.start(wait)
reactor.run()
window.close()

Solution

  • Answer: Your script is not calling paintQuote more than once. Add print lines in there and you'll see it never calls it more than once.

    Suggested solutions: I don't know much about that reactor or loopingCall thing or how it works. A simpler solution is just to use a while loop with a sleep in it. Here is my solution that seemed to work well:

    import PySimpleGUI as sg
    from alpha_vantage.timeseries import TimeSeries
    import time
    
    sg.theme('BluePurple')
    
    layout = [[sg.Text('Last Price', size=(20, 2), justification='center')],
              [sg.Text('', size=(10, 2), font=('Helvetica', 20),
                       justification='center', key='quote')]]
    
    window = sg.Window('MikeQuote', layout)
    av = TimeSeries(key = 'key')
    spy, _ = av.get_quote_endpoint(symbol='SPY')
    last = spy['05. price']
    yest = spy['08. previous close']
    wait = 1  # Wait is in seconds
    
    while True:
        event, values = window.read(timeout=10)
        if event in (None, 'Quit'):
            break
        spy, _ = av.get_quote_endpoint(symbol='SPY')
        last = spy['05. price']
        window['quote'].update(last)
        time.sleep(wait)
    

    I added a few tweaks including:

    1. Calling just the "GLOBAL_QUOTE" endpoint (so you're not returning the entire massive intraday dataset)

    2. Remove twisted package for a simple while loop with a time.sleep function.

    3. Added a 'Quit' event so it actually stop when you close the window.

    4. Removed the paintQuote() function. I think clean code ideally would have this function not removed, but you can add it back in however you like.

    5. Removed the pandas integration. You're not dealing with massive data manipulation so it's easier and faster to just use the JSON format.