Infinite loop (or Python app) plus Dash

Let’s say I made a Python application which runs forever - for example, checks 3000 stocks in real time and run technical analysis for all of them, and again, and again. So, in other words - it newer stops. Now, I want to make a Plotly/Dash app where I can monitor the progress and interfere with it like with a button and “tell” my infinite loop: “Ok, I want you now to buy AAPL and then continue where you were”.
How do I do this? If I start that infinite loop - Dash will become unresponsive, I think.

Hi,

I think that you could accomplish this using the dcc.Interval component.

https://dash.plotly.com/dash-core-components/interval

The component fires a callback at predefined time intervals. In your case you could just update your technical analysis callback every second (or less) for continuous monitoring. The button to trigger execution would be a separate callback. Here’s a quick example of the dcc.Interval component in action:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(
    html.Div([
        dcc.Interval(
            id='interval',
            interval=1*1000, # in milliseconds
            n_intervals=0
        ),
        html.P(id='seconds'),
        html.Button('Stop', id='stop'),
        html.Button('Resume', id='resume'),
        html.Button('Reset', id='restart')
    ])
)

@app.callback(
    Output('seconds', 'children'),
    [Input('interval', 'n_intervals')]
)
def display_seconds(n_intervals):
    return '{s} seconds'.format(s=n_intervals)

@app.callback(
    [
        Output('interval', 'n_intervals'),
        Output('interval', 'disabled')
    ],
    [
        Input('stop', 'n_clicks'),
        Input('resume', 'n_clicks'),
        Input('restart', 'n_clicks')
    ],
    [
        State('interval', 'n_intervals')
    ]
)
def update_interval(stop, resume, restart, current):
    changed_id = [p['prop_id'] for p in dash.callback_context.triggered][0]
    if 'restart' in changed_id:
        return [0,False]
    elif 'stop' in changed_id:
        return [current, True]
    elif 'resume' in changed_id:
        return [current, False]
    return [current, False]

if __name__ == '__main__':
    app.run_server(debug=True)

interval

Thanks, but where would you place my endless loop?
Let’s say this is the endless loop:

a = 0
while(a < 1):
    a = a - 1

The endless loop would be replaced by the callback that is triggered by the dcc.Interval component. The code would then be triggered endlessly at fixed intervals. You can change how frequently you want the interval to fire depending on how long the body of your loop takes to execute. In this case I’m just generating a random figure every 3 seconds, but you can replace that with whatever calculations are required:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import plotly.express as px
import numpy as np

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(
    html.Div([
        dcc.Interval(
            id='interval',
            interval=3*1000, # in milliseconds
            n_intervals=0
        ),
        dcc.Graph('output')
    ])
)

@app.callback(
    Output('output', 'figure'),
    [Input('interval', 'n_intervals')]
)
def update(n_intervals):
    # This is where your technical analysis code would go
    random = np.random.rand(5)
    figure = px.bar(
        x=range(1,6),
        y=random
    )
    return figure

if __name__ == '__main__':
    app.run_server(debug=True)

Hi @trader007

I think you can share data between your loop and any other Dash component.

For example, if your loop analyze a specific share and do the technical analysis, the result of this analysis could be save in a csv file, then with a callback you can read the csv file and execute the transaction you want according with the data provided by the loop.

Dash is a frontend framework. The task you describe seems like a backend task to me. Hence I would recommend running this task in a separate thread/process/container. You would then trigger updates from Dash using the interval component.

Thanks, Jwolf,
I tried exactly that before but it came out a little bit complicated:
In order to use almost all the time, let’s say 2900 miliseconds in a 3000 miliseconds interval function I would have to save to CSV file variable a, and when interval function calls the endless loop 100 miliseconds after it temporarily finished - the loop would have to read variable a from CSV and continue where it stopped 100 miliseconds before. However, I would have to make another loop within the endless loop to make sure it lasts for 2900 miliseconds.
That is not a lot of a problem if my stock appliaction has only one endless loop, but if has to do many things - it becomes hard to make sure it lasts about 2900 miliseconds.
I tried time function but looks like Dash caches the time and doesn’t change it.
Any other thoughts?
Thanks for your reply

Thanks, Emil,
I am new to all this stuff. How to run Python in multi thread or multi process mode? Any good link or book to learn about that?

Thanks Eduardo,
I tried to save to CSV and it works fine.

1 Like

There are many ways to achieve it. A very simple approach would be to write the loop code in a different .py file, launch it in one terminal, and then run your Dash app in another terminal.

Will try,
thanks, Emil