Home > other >  Creating thread which runs endless loop
Creating thread which runs endless loop

Time:06-21


What I am trying to achieve here is following:
  • I want a class to collect data once every minute. This happens with an endless loop.
    • Since this uses the sleep method, I need to use multiple threads afaik.
  • At the same time, I want a GUI to be running (PyQt6)

I have a class which is collecting data from an API. This class is running in an endless loop.

class Get4hForexData:
    """
    Instantiating the different market_data objects
    """

    def __init__(self):
        # Gets list containing the markets
        self.markets = get_forex_market_to_process()  # Returns a list containing tuples
        self.list_with_market_data_objects = []

    def collect_market_data(self):

        # Loop does something once every minute in the first 3-8 seconds of each minute
        while True:
            seconds_in_current_minute = dt.datetime.now().second

            if 3 < seconds_in_current_minute < 8:
                print("now")  # Testing print statement

                # Creating all 4h timeframe marketdata objects
                for market in self.markets:
                    self.list_with_market_data_objects.append(
                        MarketData(from_currency=market[1], to_currency=market[2], timeframe="4h", outputsize=50)
                    )

                print(self.list_with_market_data_objects)  # Testing print statement
                print(self.list_with_market_data_objects[0].structure_x_coord)  # Testing print statement

            time.sleep(10)  # Stop maxing out CPU

in the main.py I am creating an Object from this class and calling the method via the threading.Thread class.

def main():
    data = datacontroller.Get4hForexData()

    t1 = threading.Thread(target=data.collect_market_data)  # calling the method here
    t2 = threading.Thread(target=gui.testing)

    t1.start()
    t2.start()

    t1.join()
    t2.join()

in the datacollection class I have different print statements for testing purposes. My GUI is a simple button, which when pressed also prints a statement. So in theory both, the data collection method, as well as the GUI (when the button is pressed) should print statements to the console.

BUT this does not happen. Only the GUI happens to work.

What I have done so far:

  1. Tested the GUI and the Get4hForexData class each on their own. Both are working as they should.
  2. I tested my main.py code with a different, more simple endless loop as seen below. --> (this is also working)
def loop():
    while True:

        print("Now")
        time.sleep(1)


def main():

    t1 = threading.Thread(target=loop)
    t2 = threading.Thread(target=gui.testing)

    t1.start()
    t2.start()

    t1.join()
    t2.join()

I don't know, what I am doing wrong here. The problem has to be within my Get4hForexData class. But I don't know what it could be.

Thanks for any advice!


EDIT:

Here is the code cut down to the essentials. This code is reproducing the behavior stated above:

main.py

import gui
import threading
import datacontroller


def main():
    data = datacontroller.Get4hForexData()

    t1 = threading.Thread(target=data.collect_market_data)
    t2 = threading.Thread(target=gui.testing)

    t1.start()
    t2.start()


if __name__ == '__main__':
    main()

datacontroller.py

import datetime as dt
from data import MarketData
import time


class Get4hForexData:
    """
    Instantiating the different market_data objects
    """
    def __init__(self):
        # Gets list containing the markets
        self.list_with_market_data_objects = []

    def collect_market_data(self):

        # Loop does something once every minute in the first 3-8 seconds of each minute
        while True:
            seconds_in_current_minute = dt.datetime.now().second

            if 3 < seconds_in_current_minute < 8:
                print("now")  # Testing print statement

                # Creating all 4h timeframe marketdata objects
                for _ in range(10):
                    self.list_with_market_data_objects.append(MarketData())

                print(self.list_with_market_data_objects)  # Testing print statement
                print(self.list_with_market_data_objects[0].name)  # Testing print statement

            time.sleep(10)  # Stop maxing out CPU

data.py

class MarketData:

    def __init__(self):
        super().__init__()
        self.name = "test"

gui.py

from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Market Screener")

        self.button = QPushButton("Press me.")
        self.button.clicked.connect(self.the_button_was_clicked)  # Connect button click with function

        # Set the central widget of the window.
        self.setCentralWidget(self.button)

    def the_button_was_clicked(self):
        self.button.setText("You clicked me.")
        print("Clicked")


def testing():
    app = QApplication([])

    window = MainWindow()
    window.show()

    # Start the event loop.
    app.exec()

Hope this helps. Sorry for not posting the reduced code in the beginning.

CodePudding user response:

So guys..
I got it to work. Thanks for all you suggestions. First, I stumpled uppon an indentation mistake I made, which gave me inconsistent results. I had the time.sleep(10) method outside of the if statement. Which acutally makes no sense there. I fixed that.

I implemented the threading inside the Get4hForexData class. which seems to do the trick.

class Get4hForexData(threading.Thread):

    """
    Instantiating the different market_data objects
    """
    def __init__(self):
        # Gets list containing the markets
        super().__init__()
        self.markets = get_forex_market_to_process()
        print(self.markets)
        self.list_with_market_data_objects = []

        threading.Thread(target=self.collect_market_data).start()

    def collect_market_data(self):

        # Loop does something once every minute in the first 3-8 seconds of each minute
        while True:

            seconds_in_current_minute = dt.datetime.now().second
            if 3 < seconds_in_current_minute < 12:
                print("now")  # Testing print statement

                # Creating all 4h timeframe marketdata objects
                for market in self.markets:
                    self.list_with_market_data_objects.append(
                        MarketData(from_currency=market[1], to_currency=market[2], timeframe="4h", outputsize=50)
                    )

                print(self.list_with_market_data_objects)  # Testing print statement
                print(self.list_with_market_data_objects[0].structure_x_coord)  # Testing print statement

                # Here was the mistake I made
                time.sleep(10)  # Stop maxing out CPU

The main.py is no looking like this..

import gui
import datacontroller


def main():

    datacontroller.Get4hForexData()
    gui.testing()


if __name__ == '__main__':
    main()

CodePudding user response:

Ok, to make things clearer and to answer the question @musicamante has, here another answer to make things clearer.

Here the logic/flow of my programm.

enter image description here

Here the Get4hForexData Class --> This is what updates the data.

class Get4hForexData(threading.Thread):
    """
    Instantiating the different market_data objects
    """

    def __init__(self):
        # Gets list containing the markets
        super().__init__()
        self.markets = get_forex_market_to_process()
        self.list_with_market_data_objects = []
        self.market_basket_dataframe = pd.DataFrame(columns=[
            "market",
            "ST_direction",
            "range_location"]
            )

        threading.Thread(target=self.collect_market_data).start()

    def collect_market_data(self):

        # Loop does something once every minute in the first 3-8 seconds of each minute
        while True:

            seconds_in_current_minute = dt.datetime.now().second
            if 3 < seconds_in_current_minute < 12:

                # Creating all 4h timeframe marketdata objects
                for market in self.markets:
                    self.list_with_market_data_objects.append(
                        MarketData(from_currency=market[1], to_currency=market[2], timeframe="4h", outputsize=50)
                    )

                for data_object in self.list_with_market_data_objects:
                    self.market_basket_dataframe.loc[len(self.market_basket_dataframe.index)] = [
                        data_object.market_name,
                        data_object.structure_direction,
                        data_object.range_location,
                        ]

                self.market_basket_dataframe.to_csv("market_basket_dataframe.csv")
                self.market_basket_dataframe = self.market_basket_dataframe[0:0]

                time.sleep(10)  # Stop maxing out CPU

The MarketData Class:

class MarketData:
    """
    Dataclass containing market specific attributes.
    """

    def __init__(self, from_currency, to_currency, timeframe, outputsize):
        super().__init__()

        # ---Market data from twelvedata API
        self.market_dataframe = API.twelvedata_API.get_data(
            from_currency=from_currency,
            to_currency=to_currency,
            timeframe=timeframe,
            outputsize=outputsize)

        # ---MarketData
        self.market_name = f"{from_currency.upper()}/{to_currency.upper()}"
        self.timeframe = timeframe

        # --- Setting the high and low series of the dataframe.
        self.dataframe_length = self.market_dataframe.shape[0]
        self.highs = self.market_dataframe.high
        self.lows = self.market_dataframe.low
        self.open = self.market_dataframe.open
        self.close = self.market_dataframe.close

        self.market_structure_dataframe = market_functions.get_market_structure(self.market_dataframe)

        self.structure_x_coord = self.market_structure_dataframe.market_dataframe_index
        self.structure_y_coord = self.market_structure_dataframe.structure_value

        self.current_range_is_ext = market_functions.is_current_range_ext(self.market_structure_dataframe)
        self.structure_direction = market_functions.get_current_range_direction(self.market_structure_dataframe)
        self.range_location = (
            market_functions.get_range_location(self.market_structure_dataframe, self.market_dataframe))

I hope this makes things clearer, in what I am trying to achieve here.

  • Related