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:
- Tested the GUI and the Get4hForexData class each on their own. Both are working as they should.
- 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.
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.