LUCIT-Systems-and-Development / unicorn-binance-websocket-api

A Python SDK by LUCIT to use the Binance Websocket API`s (com+testnet, com-margin+testnet, com-isolated_margin+testnet, com-futures+testnet, com-coin_futures, us, tr, dex/chain+testnet) in a simple, fast, flexible, robust and fully-featured way.
https://unicorn-binance-websocket-api.docs.lucit.tech/
Other
680 stars 165 forks source link

How to close websocket/stream using ctrl-c ? #130

Closed mfiro closed 3 years ago

mfiro commented 3 years ago

Hi! Firstly thank you for this awesome project.

Sorry, if I ask, but I don't understand how to stop a running script in while Trueloop with ctrl-c and close everything properly. I tried to use the following code , however, the stream keeps printing and doesn't stop the process. What is the proper and clean way to do this?

from binance.websockets import BinanceSocketManager
from unicorn_fy.unicorn_fy import UnicornFy
from unicorn_binance_websocket_api.unicorn_binance_websocket_api_manager import BinanceWebSocketApiManager

import logging
import os
import time
import threading

def print_stream_data_from_stream_buffer(binance_websocket_api_manager):
    while True:
        if binance_websocket_api_manager.is_manager_stopping():
            exit(0)
        oldest_stream_data_from_stream_buffer = binance_websocket_api_manager.pop_stream_data_from_stream_buffer()
        if oldest_stream_data_from_stream_buffer is False:
            time.sleep(0.01)
        else:
            try:
                # remove # to activate the print function:
                print(oldest_stream_data_from_stream_buffer)
            except Exception:
                # not able to process the data? write it back to the stream_buffer
                binance_websocket_api_manager.add_to_stream_buffer(oldest_stream_data_from_stream_buffer)

if __name__ == '__main__':
    try:
        binance_websocket_api_manager = BinanceWebSocketApiManager(exchange="binance.com")
        # start a worker process to process to move the received stream_data from the stream_buffer to a print function
        worker_thread = threading.Thread(target=print_stream_data_from_stream_buffer, args=(binance_websocket_api_manager,))
        worker_thread.start()

        kline_stream_id = binance_websocket_api_manager.create_stream(['kline', 'kline_1m'], ['btcusdt'])

    except KeyboardInterrupt:
        binance_websocket_api_manager.stop_stream(kline_stream_id)
        binance_websocket_api_manager.stop_manager_with_all_streams()
oliver-zehentleitner commented 3 years ago

actually that should work, i tested your code and if I hit ctrl+c it stops ...

Which OS do you use?

Maybe hit ctrl+c a second or third time, does this help?

mfiro commented 3 years ago

In Windows 10 it doens't stop. I tried to hit ctrl-c multiple time. Actually the problem is that KeyboardInterrupt exception is not caught at all (I don't know why). When I tried this with Raspbian (debian based os) ctrl-c stops the script but again not by catching exception.

I'm not even sure, if I need a KeyboardInterrupt exception to close the program with ctrl-c.

oliver-zehentleitner commented 3 years ago

i can confirm, its also not caught on linux.

I'm not even sure, if I need a KeyboardInterrupt exception to close the program with ctrl-c.

Actually not, its going to get closed by ctrl-c itself, but with catching the exception you can decide to not stop or do some logging or any action before you close.

mfiro commented 3 years ago

That's true. Actually the reason I wrote exception handling in the first place was because I couldn't stop the script with ctrl+c. So I tried exception handling with sys.exit(0). But it didn't work either.

oliver-zehentleitner commented 3 years ago

Hm. Maybe you could wait for a console input that is equal to "exit" in your script and if met, you exit the script...

mfiro commented 3 years ago

This solves the problem:

if __name__ == '__main__':
    binance_websocket_api_manager = BinanceWebSocketApiManager(exchange="binance.com")

    # start a worker process to process to move the received stream_data from the stream_buffer to a print function
    worker_thread = threading.Thread(target=print_stream_data_from_stream_buffer, args=(binance_websocket_api_manager,))
    worker_thread.start()
    kline_stream_id = binance_websocket_api_manager.create_stream(['kline', 'kline_1m'], ['btcusdt'])

    try:
        while True:
            time.sleep(60)

    except KeyboardInterrupt:
        binance_websocket_api_manager.stop_stream(kline_stream_id)
        binance_websocket_api_manager.stop_manager_with_all_streams()

The exception is also caught properly. The time.sleep() amount doesn't matter also in functionality as far as I've experienced.

oliver-zehentleitner commented 3 years ago

Thank you very much for sharing your solution! I think i am going to put it into an example! best regards!

oliver-zehentleitner commented 3 years ago

I uploaded an example: https://github.com/oliver-zehentleitner/unicorn-binance-websocket-api/blob/master/example_ctrl-c.py

@mfiro Thanks for sharing the snippet! I just saw that you are importing UnicornFy, thats not neccessary anymore, its a dependency of unicorn-binance-websocket-api.

just use output_default parameter for all streams as mentioned here: https://oliver-zehentleitner.github.io/unicorn-binance-websocket-api/unicorn_binance_websocket_api.html#unicorn_binance_websocket_api.unicorn_binance_websocket_api_manager.BinanceWebSocketApiManager

or in create_stream() the output parameter as mentioned here: https://oliver-zehentleitner.github.io/unicorn-binance-websocket-api/unicorn_binance_websocket_api.html#unicorn_binance_websocket_api.unicorn_binance_websocket_api_manager.BinanceWebSocketApiManager.create_stream

mfiro commented 3 years ago

Thank you for adding it to examples and also for pointing that out:)

I'll then use the parameter instead of that.