Search code examples
pythonmultithreadingparallel-processingalgorithmic-tradingtrading

How to update attribute value of one class from another class in parallel in python?


This is my first question in here. Question is mostly about Python but a little bit about writing crypto trading bot. I need to calculate some indicators about trading like Bollinger Bands, RSI or etc in my bot.

Indicators are calculated from candlesticks data in trading. And candlesticks data updated in their time period. For example if use candlestiks data in period 5 minute i need to calculate indicators every 5 min (after candlesticks update), or if i use candlesticks data in period 1 hour period i need to calculate indicators every 1 hour.

So, think that i have two classes. One is named with "TradeControl" and it has a attribute named with "candlestick_data". And second class is named with "CandlestickUpdater". I want to manage updates for "candlestick_data" in "TradeControl" class from "CandlestickUpdater" class.

My problem is about parallel process (or threading) in python. I don't know how to do it proper way. Is there anybody here to give me some advice or sample code. And i am also wondering if i should use mutex-like structures to guard against conditions like race condition. What i am trying to do in code is like below. Also, if you have a different suggestion, I would like to consider it.

class TradeControl():
    def __init__(self):
        self.candlestick_data = 0

    def update_candlestick(self):
        """Candlesticks data will be requested from exchange and updated in here"""
        pass

    def run_trading_bot(self):
        while True:
            """Main trading algorithm is running and using self.candlestick_data in here"""
            pass
        pass

    pass

class CandlestickUpdater():
    def __init__(self, controller: TradeControl):
        self.controller = controller
             
    def run_candlestick_updater(self):
        while True:
            """Candlesticks data updates will be checked in here"""
            
            if need_to_update:
                """TradeControl will be informed in here"""
                self.controller.update_candlestick()
                pass
            pass
        pass
    pass

Thanks for your replies,


Solution

  • It's not quite obvious from your description what CandlestickUpdater is for. It looks like its purpose is to notify TradeControl that time has come to update candlestick_data, whereas updating logic itself is in the TradeControl.update_candlestick method. So basically CandlestickUpdater is a timer.

    There are different python libs from scheduling events. sched for example. It seems that it can be used for scheduling TradeControl.update_candlestick method with a required time period.

    If you still want to have CandlestickUpdater class, I think it can actually work as it's written in your code. You can these classes in threads this way:

    from threading import Thread
    
    trade_control = TradeControl()
    candlestick_updater = CandlestickUpdater(controller=trace_control)
    
    Thread(target=trade_control.update_candlestick).start()
    Thread(target=candlestick_updater.run_candlestick_updater).start()
    

    Speaking of race condition. Well, it can be the case, but it depends on your implementation of update_candlestick and run_trading_bot. It's better to create TradeControl.lock: threading.Lock attribute and use it when updating candlestick_data: https://docs.python.org/3/library/threading.html#lock-objects.

    There is also another way of communicating between threads without direct methods calls. Look at the blinker. It's nice lib to implement event-driven scenarios. You just need to create a "signal" object (outside of TradeControl and CandlestickUpdater classes) and connect TradeControl.update_candlestick method to it. Then you just call "signal.send" method in "CandlestickUpdater.run_candlestick_updater" and connected functions will be executed. It can be a little bit tricky to connect instance method to signal. But there are some solutions for it. The easiest one is to make CandlestickUpdater.run_candlestick_updater static if it's possible for you.