Exemple #1
0
        /// <summary>
        /// Constructor for brokerage
        /// </summary>
        /// <param name="apiKey">api key</param>
        /// <param name="apiSecret">api secret</param>
        /// <param name="algorithm">the algorithm instance is required to retrieve account type</param>
        /// <param name="aggregator">the aggregator for consolidating ticks</param>
        /// <param name="job">The live job packet</param>
        public BinanceBrokerage(string apiKey, string apiSecret, IAlgorithm algorithm, IDataAggregator aggregator, LiveNodePacket job)
            : base(WebSocketBaseUrl, new WebSocketClientWrapper(), null, apiKey, apiSecret, "Binance")
        {
            _job            = job;
            _algorithm      = algorithm;
            _aggregator     = aggregator;
            _messageHandler = new BrokerageConcurrentMessageHandler <WebSocketMessage>(OnMessageImpl);

            var subscriptionManager = new EventBasedDataQueueHandlerSubscriptionManager();

            subscriptionManager.SubscribeImpl += (s, t) =>
            {
                Subscribe(s);
                return(true);
            };
            subscriptionManager.UnsubscribeImpl += (s, t) => Unsubscribe(s);

            SubscriptionManager = subscriptionManager;

            _apiClient = new BinanceRestApiClient(
                _symbolMapper,
                algorithm?.Portfolio,
                apiKey,
                apiSecret);

            _apiClient.OrderSubmit        += (s, e) => OnOrderSubmit(e);
            _apiClient.OrderStatusChanged += (s, e) => OnOrderEvent(e);
            _apiClient.Message            += (s, e) => OnMessage(e);

            // User data streams will close after 60 minutes. It's recommended to send a ping about every 30 minutes.
            // Source: https://github.com/binance-exchange/binance-official-api-docs/blob/master/user-data-stream.md#pingkeep-alive-a-listenkey
            _keepAliveTimer = new Timer
            {
                // 30 minutes
                Interval = 30 * 60 * 1000
            };
            _keepAliveTimer.Elapsed += (s, e) => _apiClient.SessionKeepAlive();

            WebSocket.Open   += (s, e) => { _keepAliveTimer.Start(); };
            WebSocket.Closed += (s, e) => { _keepAliveTimer.Stop(); };

            // A single connection to stream.binance.com is only valid for 24 hours; expect to be disconnected at the 24 hour mark
            // Source: https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#general-wss-information
            _reconnectTimer = new Timer
            {
                // 23.5 hours
                Interval = 23.5 * 60 * 60 * 1000
            };
            _reconnectTimer.Elapsed += (s, e) =>
            {
                Log.Trace("Daily websocket restart: disconnect");
                Disconnect();

                Log.Trace("Daily websocket restart: connect");
                Connect();
            };
        }
        public void MessagesHandledCorrectly()
        {
            const int expectedCount = 10000;
            var       numbers       = new List <string>();

            void Action(string number) => numbers.Add(number);

            var handler = new BrokerageConcurrentMessageHandler <string>(Action);

            var task = Task.Factory.StartNew(() =>
            {
                var counter = 0;
                for (var i = 0; i < expectedCount; i++)
                {
                    handler.HandleNewMessage($"{Interlocked.Increment(ref counter)}");

                    if (i % 50 == 0)
                    {
                        Thread.Sleep(1);
                    }
                }
            });

            for (var i = 0; i < expectedCount;)
            {
                handler.WithLockedStream(() =>
                {
                    // place order
                    i++;
                });

                if (i % 50 == 0)
                {
                    Thread.Sleep(1);
                }
            }

            if (!task.Wait(TimeSpan.FromSeconds(5)))
            {
                Assert.Fail("BrokerageConcurrentMessageHandlerTests.MessagesHandledCorrectly(): timeout waiting for task to finish");
            }

            // all processed
            Assert.AreEqual(expectedCount, numbers.Count);

            for (var i = 0; i < numbers.Count; i++)
            {
                // all in order
                Assert.AreEqual($"{i + 1}", numbers[i]);
            }
        }
Exemple #3
0
        /// <summary>
        /// Initialize the instance of this class
        /// </summary>
        /// <param name="wssUrl">The web socket base url</param>
        /// <param name="restApiUrl">The rest api url</param>
        /// <param name="apiKey">api key</param>
        /// <param name="apiSecret">api secret</param>
        /// <param name="algorithm">the algorithm instance is required to retrieve account type</param>
        /// <param name="aggregator">the aggregator for consolidating ticks</param>
        /// <param name="job">The live job packet</param>
        private void Initialize(string wssUrl, string restApiUrl, string apiKey, string apiSecret,
                                IAlgorithm algorithm, IDataAggregator aggregator, LiveNodePacket job)
        {
            if (IsInitialized)
            {
                return;
            }
            base.Initialize(wssUrl, new WebSocketClientWrapper(), null, apiKey, apiSecret);
            _job              = job;
            _algorithm        = algorithm;
            _aggregator       = aggregator;
            _webSocketBaseUrl = wssUrl;
            _messageHandler   = new BrokerageConcurrentMessageHandler <WebSocketMessage>(OnUserMessage);

            var maximumWebSocketConnections = Config.GetInt("binance-maximum-websocket-connections");
            var symbolWeights = maximumWebSocketConnections > 0 ? FetchSymbolWeights() : null;

            var subscriptionManager = new BrokerageMultiWebSocketSubscriptionManager(
                wssUrl,
                MaximumSymbolsPerConnection,
                maximumWebSocketConnections,
                symbolWeights,
                () => new BinanceWebSocketWrapper(null),
                Subscribe,
                Unsubscribe,
                OnDataMessage,
                new TimeSpan(23, 45, 0));

            SubscriptionManager = subscriptionManager;

            // can be null, if BinanceBrokerage is used as DataQueueHandler only
            if (_algorithm != null)
            {
                // Binance rest api endpoint is different for sport and margin trading
                // we need to delay initialization of rest api client until Algorithm is initialized
                // and user brokerage choise is actually applied
                _apiClientLazy = new Lazy <BinanceBaseRestApiClient>(() =>
                {
                    BinanceBaseRestApiClient apiClient = _algorithm.BrokerageModel.AccountType == AccountType.Cash
                        ? new BinanceSpotRestApiClient(_symbolMapper, algorithm?.Portfolio, apiKey, apiSecret, restApiUrl)
                        : new BinanceCrossMarginRestApiClient(_symbolMapper, algorithm?.Portfolio, apiKey, apiSecret,
                                                              restApiUrl);

                    apiClient.OrderSubmit        += (s, e) => OnOrderSubmit(e);
                    apiClient.OrderStatusChanged += (s, e) => OnOrderEvent(e);
                    apiClient.Message            += (s, e) => OnMessage(e);

                    // once we know the api endpoint we can subscribe to user data stream
                    apiClient.CreateListenKey();
                    _keepAliveTimer.Elapsed += (s, e) => apiClient.SessionKeepAlive();

                    Connect(apiClient.SessionId);

                    return(apiClient);
                });
            }

            // User data streams will close after 60 minutes. It's recommended to send a ping about every 30 minutes.
            // Source: https://github.com/binance-exchange/binance-official-api-docs/blob/master/user-data-stream.md#pingkeep-alive-a-listenkey
            _keepAliveTimer = new Timer
            {
                // 30 minutes
                Interval = 30 * 60 * 1000
            };

            WebSocket.Open += (s, e) =>
            {
                _keepAliveTimer.Start();
            };
            WebSocket.Closed += (s, e) =>
            {
                ApiClient.StopSession();
                _keepAliveTimer.Stop();
            };

            // A single connection to stream.binance.com is only valid for 24 hours; expect to be disconnected at the 24 hour mark
            // Source: https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#general-wss-information
            _reconnectTimer = new Timer
            {
                // 23.5 hours
                Interval = 23.5 * 60 * 60 * 1000
            };
            _reconnectTimer.Elapsed += (s, e) =>
            {
                Log.Trace("Daily websocket restart: disconnect");
                Disconnect();

                Log.Trace("Daily websocket restart: connect");
                Connect();
            };
        }
Exemple #4
0
        /// <summary>
        /// Initialize the instance of this class
        /// </summary>
        /// <param name="wssUrl">The web socket base url</param>
        /// <param name="restApiUrl">The rest api url</param>
        /// <param name="apiKey">api key</param>
        /// <param name="apiSecret">api secret</param>
        /// <param name="algorithm">the algorithm instance is required to retrieve account type</param>
        /// <param name="aggregator">the aggregator for consolidating ticks</param>
        /// <param name="job">The live job packet</param>
        private void Initialize(string wssUrl, string restApiUrl, string apiKey, string apiSecret,
                                IAlgorithm algorithm, IDataAggregator aggregator, LiveNodePacket job)
        {
            if (IsInitialized)
            {
                return;
            }
            base.Initialize(wssUrl, new WebSocketClientWrapper(), null, apiKey, apiSecret);
            _job              = job;
            _algorithm        = algorithm;
            _aggregator       = aggregator;
            _webSocketBaseUrl = wssUrl;
            _messageHandler   = new BrokerageConcurrentMessageHandler <WebSocketMessage>(OnUserMessage);

            var maximumWebSocketConnections = Config.GetInt("binance-maximum-websocket-connections");
            var symbolWeights = maximumWebSocketConnections > 0 ? FetchSymbolWeights() : null;

            var subscriptionManager = new BrokerageMultiWebSocketSubscriptionManager(
                wssUrl,
                MaximumSymbolsPerConnection,
                maximumWebSocketConnections,
                symbolWeights,
                () => new BinanceWebSocketWrapper(null),
                Subscribe,
                Unsubscribe,
                OnDataMessage,
                new TimeSpan(23, 45, 0));

            SubscriptionManager = subscriptionManager;

            _apiClient = new BinanceRestApiClient(_symbolMapper,
                                                  algorithm?.Portfolio,
                                                  apiKey,
                                                  apiSecret,
                                                  restApiUrl);

            _apiClient.OrderSubmit        += (s, e) => OnOrderSubmit(e);
            _apiClient.OrderStatusChanged += (s, e) => OnOrderEvent(e);
            _apiClient.Message            += (s, e) => OnMessage(e);

            // User data streams will close after 60 minutes. It's recommended to send a ping about every 30 minutes.
            // Source: https://github.com/binance-exchange/binance-official-api-docs/blob/master/user-data-stream.md#pingkeep-alive-a-listenkey
            _keepAliveTimer = new Timer
            {
                // 30 minutes
                Interval = 30 * 60 * 1000
            };
            _keepAliveTimer.Elapsed += (s, e) => _apiClient.SessionKeepAlive();

            WebSocket.Open   += (s, e) => { _keepAliveTimer.Start(); };
            WebSocket.Closed += (s, e) => { _keepAliveTimer.Stop(); };

            // A single connection to stream.binance.com is only valid for 24 hours; expect to be disconnected at the 24 hour mark
            // Source: https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#general-wss-information
            _reconnectTimer = new Timer
            {
                // 23.5 hours
                Interval = 23.5 * 60 * 60 * 1000
            };
            _reconnectTimer.Elapsed += (s, e) =>
            {
                Log.Trace("Daily websocket restart: disconnect");
                Disconnect();

                Log.Trace("Daily websocket restart: connect");
                Connect();
            };
        }