Search code examples
pythonwebsocketbybit

How to detect changed dictionary value?


The dictionary has 3 keys . The keys are price,size,side . The data comes from websocket. How can I detect same price same side but changed size ? if price and side is same I want size changes. how can I do that ?

from BybitWebsocket import BybitWebsocket
from time import sleep
if __name__ == "__main__":
    ws = BybitWebsocket(wsURL="wss://stream.bybit.com/realtime",
                         api_key="", api_secret=""
                        )

    ws.subscribe_orderBookL2("XRPUSD")

    while(1):
        orders = ws.get_data("orderBookL2_25.XRPUSD")
        if orders != []:
            orders2 = orders["update"]

            data = {'price':[],'size':[],'side':[]}

            for i,val in enumerate(orders2):
                data["price"].append(val["price"])
                data["size"].append(val["size"])
                data["side"].append(val["side"])


            print(data)



        sleep(0.1)



{'price': ['0.7779'], 'size': [31804], 'side': ['Buy']}
{'price': ['0.7779', '0.7782'], 'size': [31766, 33014], 'side': ['Buy', 'Sell']}
{'price': ['0.7773', '0.7770'], 'size': [27029, 83875], 'side': ['Buy', 'Buy']}
{'price': ['0.7779', '0.7778'], 'size': [71, 148372], 'side': ['Sell', 'Sell']}
{'price': ['0.7777', '0.7770'], 'size': [1515, 85432], 'side': ['Buy', 'Buy']}
{'price': ['0.7778', '0.7765', '0.7782'], 'size': [141913, 1290, 5842], 'side': ['Sell', 'Buy', 'Sell']}
{'price': ['0.7777'], 'size': [24794], 'side': ['Buy']}

for that outcome price 0.7779 size changed 31804 to 33014 , price 0.7777 size changed 1515 to 24794 and so on.

Solution

  • I not 100% sure I understand your question, but if so this may help. I hope the sample data I used is sufficient. I use comments in-line to explain:

    # from BybitWebsocket import BybitWebsocket
    from time import sleep
    
    
    def sample_gen():
        """Generator return one list item for each order with updates."""
        samples = [
            {"update": [{"price": "1", "side": "Buy", "size": 10}]},
            {"update": [{"price": "1", "side": "Buy", "size": 11}]},
            {
                "update": [
                    {"price": "1", "side": "Buy", "size": 12},
                    {"price": "1", "side": "Buy", "size": 13},
                    {"price": "2", "side": "Sell", "size": 21},
                ]
            },
            [],
            {
                "update": [
                    {"price": "1", "side": "Buy", "size": 14},
                    {"price": "2", "side": "Sell", "size": 22},
                ]
            },
            [],
            {"update": [{"price": "1", "side": "Sell", "size": 11}]},
            {"update": [{"price": "1", "side": "Buy", "size": 15}]},
        ]
        for sample in samples:
            yield sample
    
    
    if __name__ == "__main__":
        # Commenting out the websockets bit.
        # ws = BybitWebsocket(
        #     wsURL="wss://stream.bybit.com/realtime", api_key="", api_secret=""
        # )
        # ws.subscribe_orderBookL2("XRPUSD")
    
        # Since tuples are hashable and you are operating based on size per
        # combination of price and side, I suggest using price and side as
        # a tuple key for a slightly different data structure.
        price_side = {}  # Initialized here for scope.
        g = sample_gen()  # Creating the generator for the sample data.
        while True:  # While True I see more commonly that `While 1`, but they are the same.
            # Get one item from the sample data, and for each at the `update`
            # key or an empty list.
            order = next(g)
            # order = ws.get_data("orderBookL2_25.XRPUSD")
            if order:
                for update in order.get("update", []):
                    price, side, size = (
                        update.get("price"),
                        update.get("side"),
                        update.get("size"),
                    )
                    # Using setdefault lets us start an empty list or append.
                    # This way for each price, side combination we can keep a
                    # running list of all size updates.
                    price_side.setdefault((price, side), []).append(size)
                    if len(price_side[(price, side)]) < 2:  # Case where list has only 1.
                        print(f"{price} {side}: new price/side with size {size}")
                        continue  # Continue to next update.
                    if price_side[(price, side)][-1] != price_side[(price, side)][-2]:
                        print(f"{price} {side}: price/side updated with size {size}")
            sleep(0.1)
    

    This yields:

    1 Buy: new price/side with size 10
    1 Buy: price/side updated with size 11
    1 Buy: price/side updated with size 12
    1 Buy: price/side updated with size 13
    2 Sell: new price/side with size 21
    1 Buy: price/side updated with size 14
    2 Sell: price/side updated with size 22
    1 Sell: new price/side with size 11
    1 Buy: price/side updated with size 15
    Traceback (most recent call last):
      File "/Users/h4s/projects/github.com/theherk/tmp-py/ws/./main.py", line 50, in <module>
        for order in next(g).get("update", []):
    StopIteration
    

    The StopIteration here is just getting to the end of the generator.


    With your code in place of sample data, this would be:

    from BybitWebsocket import BybitWebsocket
    from time import sleep
    
    
    if __name__ == "__main__":
        ws = BybitWebsocket(
            wsURL="wss://stream.bybit.com/realtime", api_key="", api_secret=""
        )
        ws.subscribe_orderBookL2("XRPUSD")
    
        price_side = {}
        while True:
            order = ws.get_data("orderBookL2_25.XRPUSD")
            if order:
                for update in order.get("update", []):
                    price, side, size = (
                        update.get("price"),
                        update.get("side"),
                        update.get("size"),
                    )
                    price_side.setdefault((price, side), []).append(size)
                    if len(price_side[(price, side)]) < 2:
                        print(f"{price} {side}: new price/side with size {size}")
                        continue
                    if price_side[(price, side)][-1] != price_side[(price, side)][-2]:
                        print(f"{price} {side}: price/side updated with size {size}")
            sleep(0.1)