JKorf / Binance.Net

A C# .netstandard client library for the Binance REST and Websocket Spot and Futures API focusing on clear usage and models
https://jkorf.github.io/Binance.Net/
MIT License
1.04k stars 429 forks source link

Multiple client instances #117

Closed pyerpl closed 6 years ago

pyerpl commented 6 years ago

Hi JKorf when i tried to collect kline data from many symbols (20 - 40) with using statement i had an exception „System.ObjectDisposedException” w mscorlib.dll

so i solved this in that way :

        public async Task get_data()
        {
             var client = new BinanceClient();
            var klinesRslt = await client.GetKlinesAsync(Symbol, KineIntvDict[Intvl], limit: kline_limit);
            if (klinesRslt.Success)
            {
                lineData = klinesRslt.Data.ToList();
                ready = true;
                client.Dispose();
            }
            else
            {
                client.Dispose();
            }
        }

i realized that this is not the best solution but it works now I'am trying to add this code at the beginning of my app and again i have problem with System.ObjectDisposedException

        public void GetPrices()
        {
            using (var clnt = new BinanceClient())
            {
                var allPrices = clnt.GetAllBookPrices();
                if (allPrices.Success)
                {
                    Debug.WriteLine($"allPrices: {JsonConvert.SerializeObject(allPrices)}");
                }
                else
                {
                    Debug.WriteLine($"Error: {allPrices.Error.Message}");
                }
            }

        }

what is the best solution for managing multiple client instances ?

JKorf commented 6 years ago

Hi, are you using the latest version of the library? Currently 3.2.1. If not please try that. If you are, can you provide debug logging by setting the LogVerbosity to Debug in the BinanceClientOptions?

You shouldn't see the ObjectDisposedException you're getting, so let me see if I need to fix a bug.

pyerpl commented 6 years ago

Yes I'm using 3.2.1 version here is my code for connection :

public void ConnetServer()
        {

            BinanceClient.SetDefaultOptions(new BinanceClientOptions()
            {
                ApiCredentials = new ApiCredentials("APIKEY", "APISECRET"),
                LogVerbosity = LogVerbosity.Debug
            });
            BinanceSocketClient.SetDefaultOptions(new BinanceSocketClientOptions()
            {
                ApiCredentials = new ApiCredentials("APIKEY", "APISECRET"),
                LogVerbosity = LogVerbosity.Debug
            });
            var socketClient = new BinanceSocketClient();

            GetPrices(); // here is the first instance of client
            var successTicker = socketClient.SubscribeToAllSymbolTicker((data) =>
            {
                active_mrkts.TckrAnalize(data); // in this function i'am trying to get a lot of data from klines
            });
        }

maybe i'am doing something wrong with socketClient ? ... DEBUG : image

JKorf commented 6 years ago

Yeah the problem is with the usage of the socket client. You create the socket client in a function but as soon as the function is done running the socket client gets disposed by the garbage collector. If you make the socket client a field in your class instead of a local variable it should be fine:

        private BinanceSocketClient socketClient;

        public void ConnetServer()
        {

            BinanceClient.SetDefaultOptions(new BinanceClientOptions()
            {
                ApiCredentials = new ApiCredentials("APIKEY", "APISECRET"),
                LogVerbosity = LogVerbosity.Debug
            });
            BinanceSocketClient.SetDefaultOptions(new BinanceSocketClientOptions()
            {
                ApiCredentials = new ApiCredentials("APIKEY", "APISECRET"),
                LogVerbosity = LogVerbosity.Debug
            });
            socketClient = new BinanceSocketClient();

            GetPrices(); // here is the first instance of client
            var successTicker = socketClient.SubscribeToAllSymbolTicker((data) =>
            {
                active_mrkts.TckrAnalize(data); // in this function i'am trying to get a lot of data from klines
            });
        }
pyerpl commented 6 years ago

Previous solution doesn't work i modified code so You can use it just paste it:

        private BinanceSocketClient socketClient;
        public MainWindow()
        {
            InitializeComponent();
            ConnetServer();
        }
        public void ConnetServer()
        {

            BinanceClient.SetDefaultOptions(new BinanceClientOptions()
            {
                ApiCredentials = new ApiCredentials("APIKEY", "APISECRET"),
                LogVerbosity = LogVerbosity.Debug
            });
            BinanceSocketClient.SetDefaultOptions(new BinanceSocketClientOptions()
            {
                ApiCredentials = new ApiCredentials("APIKEY", "APISECRET"),
                LogVerbosity = LogVerbosity.Debug
            });
            socketClient = new BinanceSocketClient();

            GetPrices();
            var successTicker = socketClient.SubscribeToAllSymbolTicker((data) =>
            {
                for (int i = 0; i < Math.Min(5,data.Length); i++)
                {
                    GetData(data[i].Symbol);
                }
            });
        }
        public void GetPrices()
        {
            using (var client = new BinanceClient())
            {
                var allPrices = client.GetAllBookPrices();
                if (allPrices.Success)
                {
                    Debug.WriteLine($"allPrices: {JsonConvert.SerializeObject(allPrices)}");
                }
                else
                {
                    Debug.WriteLine($"Error: {allPrices.Error.Message}");
                }
            }

        }
        public async Task GetData(string symbol)
        {
            Debug.WriteLine($"try to get data from : {symbol}");
            using (var client = new BinanceClient())
            {
                var klinesRslt = await client.GetKlinesAsync(symbol, KlineInterval.OneMinute);
                if (klinesRslt.Success)
                {
                    Debug.WriteLine($"KLINE DATA : {klinesRslt.Data}");
                }
            }
        }

i have te same exception with this code

JKorf commented 6 years ago

Ah I see, thanks for the snippet. There was indeed a small bug in the library, I pushed a fix in v3.2.2 which should be available on Nuget in a few minutes.

A note though; the subscribe callbacks can provide a lot of data and it's best to keep the time spend in the callbacks spend to a minimum. Doing webrequests in a callback method isn't recommended.

JKorf commented 6 years ago

Actually, I was a bit too quick on the trigger, use 3.2.3 which should be available in a few minutes.

pyerpl commented 6 years ago

Thanks for Your time now its works perfectly ;)

what should look function to collect a lot of data... I'm doing this when i'm starting the app, and then on each minut i want to update data from 1m interval. To fully complete this task it takes about 40s - 70s in time and therefore i'm doing this asynchronously ...

JKorf commented 6 years ago

Doing it async is fine, just not in the callback of a socket subscription. Requesting data of the api will always take time, and isn't the best for realtime data. I suggest at startup request the data from the API to get the initial data, then subscribe to the kline stream using websockets to be updated on new information

var successTicker = socketClient.SubscribeToKlineStream(symbol, KlineInterval.OneMinute, (data) =>
            {
                // Process the data
            });
pyerpl commented 6 years ago

Ok thank You