Пример #1
0
        private async void StreamingEventReceivedHandler(object sender, StreamingEventReceivedEventArgs args)
        {
            if (args.Response is OrderbookResponse response)
            {
                var ticker = _tickersByFigi[response.Payload.Figi];

                if (!Quotes.ContainsKey(ticker))
                {
                    Debug.WriteLine($"Received unexpected Tinkoff orderbook for ticker \"{ticker}\"");
                    var request = StreamingRequest.UnsubscribeOrderbook(response.Payload.Figi, StockQuoteDepth);
                    await _context.SendStreamingRequestAsync(request).ConfigureAwait(false);

                    return;
                }

                var quote = Quotes[ticker];

                if (response.Payload.Bids.Count > 0)
                {
                    quote.TinkoffBidPrice = response.Payload.Bids[0][0];
                    quote.TinkoffBidSize  = response.Payload.Bids[0][1];
                }

                if (response.Payload.Asks.Count > 0)
                {
                    quote.TinkoffAskPrice = response.Payload.Asks[0][0];
                    quote.TinkoffAskSize  = response.Payload.Asks[0][1];
                }

                quote.TinkoffMarketPrice =
                    (quote.TinkoffBidPrice * quote.TinkoffBidSize + quote.TinkoffAskPrice * quote.TinkoffAskSize) /
                    (quote.TinkoffBidSize + quote.TinkoffAskSize);

                quote.TinkoffUpdatedAt = response.Time;
                quote.LongDelta        = quote.BidPrice - quote.TinkoffAskPrice;
                quote.ShortDelta       = quote.TinkoffBidPrice - quote.AskPrice;

                quote.LongDeltaPercent  = quote.LongDelta * 100 / quote.TinkoffMarketPrice;
                quote.ShortDeltaPercent = quote.ShortDelta * 100 / quote.TinkoffMarketPrice;
            }
        }
Пример #2
0
        private void StreamingEventReceivedHandler(object sender, StreamingEventReceivedEventArgs args)
        {
            switch (args.Response)
            {
            case CandleResponse response:

                var ticker        = _tickersByFigi[response.Payload.Figi];
                var currentValue  = (double)response.Payload.Close;
                var previousValue = (double?)null;

                if (!Candles.ContainsKey(ticker))
                {
                    Candles[ticker] = response.Payload;
                }
                else
                {
                    previousValue = (double?)Candles[ticker].Close;
                }

                if (!NextSignalTime.ContainsKey(ticker) || NextSignalTime[ticker] < DateTime.UtcNow)
                {
                    var signalValue = GetSignalValue(currentValue, previousValue);

                    if (signalValue.HasValue)
                    {
                        RaiseSendingSignalEvent(ticker, signalValue.Value);
                    }
                }

                break;

            case StreamingErrorResponse response:
                _logger.LogError("Error response received: {StreamingErrorResponse}", response);
                break;

            default:
                _logger.LogError("Received unrecognized type of streaming response. {StreamingResponse}", args.Response);
                break;
            }
        }
 private void _sandboxContext_StreamingEventReceived(object sender, StreamingEventReceivedEventArgs e)
 {
     StreamingEventReceived(sender, e);
 }
Пример #4
0
        private async void Broker_StreamingEventReceived(object sender, StreamingEventReceivedEventArgs e)
        {
            Debug.WriteLine(JsonConvert.SerializeObject(e.Response));
            switch (e.Response)
            {
            case CandleResponse cr:
            {
                _lastEventReceived = DateTime.Now;
                var candle = cr.Payload;
                var stock  = _tradingVM.Stocks.FirstOrDefault(s => s.Figi == candle.Figi);
                if (stock != null)
                {
                    stock.IsNotifying = false;
                    if (candle.Interval == CandleInterval.Day)
                    {
                        stock.TodayOpen  = candle.Open;
                        stock.TodayDate  = candle.Time;
                        stock.LastUpdate = DateTime.Now;
                        stock.Price      = candle.Close;
                        if (stock.TodayOpen > 0)
                        {
                            stock.DayChange = (stock.Price - stock.TodayOpen) / stock.TodayOpen;
                        }
                        stock.DayVolume = candle.Volume;
                        Interlocked.Increment(ref _refreshPendingCount);
                        // отписываемся от дневного апдейта и подписываемся на 5минутную свечу
                        QueueBrokerAction(b => b.SendStreamingRequestAsync(
                                              UnsubscribeCandle(stock.Figi, CandleInterval.Day)),
                                          $"Отписка от часовой свечи {stock.Ticker} ({stock.Figi})");
                        QueueBrokerAction(b => b.SendStreamingRequestAsync(
                                              SubscribeCandle(stock.Figi, CandleInterval.Minute)),
                                          $"Подписка на минутную свечу {stock.Ticker} ({stock.Figi})");
                    }
                    #region 5min code
                    //else if (candle.Interval == CandleInterval.FiveMinutes)
                    //{
                    //    if (candle.Time.Date > stock.TodayDate)
                    //    {
                    //        QueueBrokerAction(b => b.SendStreamingRequestAsync(
                    //           UnsubscribeCandle(stock.Figi, CandleInterval.FiveMinutes)),
                    //           $"Отписка от 5-ти минутной свечи {stock.Ticker} ({stock.Figi})");
                    //        QueueBrokerAction(b => b.SendStreamingRequestAsync(
                    //            SubscribeCandle(stock.Figi, CandleInterval.Day)),
                    //            $"Подписка на дневную свечу {stock.Ticker} ({stock.Figi})");
                    //        break;
                    //    }
                    //    var change = (candle.Close - candle.Open) / candle.Open;
                    //    stock.Price = candle.Close;

                    //    stock.LastUpdate = DateTime.Now;
                    //    if (stock.TodayOpen > 0)
                    //        stock.DayChange = (stock.Price - stock.TodayOpen) / stock.TodayOpen;
                    //    if (stock.DayChange > (decimal)0.05
                    //        && (stock.LastAboveThreshholdDate == null
                    //        || stock.LastAboveThreshholdDate.Value.Date < stock.LastUpdate.Date))
                    //    {
                    //        stock.LastAboveThreshholdDate = stock.LastUpdate;

                    //        var infoReq = StreamingRequest.SubscribeInstrumentInfo(stock.Figi);
                    //        QueueBrokerAction(b => b.SendStreamingRequestAsync(infoReq),
                    //            $"Подписка на статус инструмента {stock.Ticker} ({stock.Figi})");
                    //        //if (stock.MonthVolume == 0)
                    //        //await GetMonthStats(stock);
                    //        //_telegram.PostMessage(stock.GetChangeInfoText());
                    //        //_telegram.PostMessage($"Цена {stock.Ticker} изменилась на {stock.DayChange:P2} с начала дня. Объем (5 минут): {candle.Volume}" +
                    //        //    $"\r\nЦена на начало дня: {stock.TodayOpenF}, Текущая: {stock.PriceF}");
                    //        _uiContext.Post(obj => {
                    //            _tradingVM.Messages.Add(new MessageViewModel
                    //            {
                    //                Ticker = stock.Ticker,
                    //                Date = DateTime.Now,
                    //                Change = stock.DayChange,
                    //                Volume = candle.Volume,
                    //                Text = $"Цена {stock.Ticker} изменилась на {stock.DayChange:P2} с начала дня."
                    //            });
                    //        }, null);
                    //        Interlocked.Increment(ref _refreshPendingCount);
                    //    }

                    //    if ((change > (decimal)0.05 || change < (decimal)-0.05) && (stock.LastAboveThreshholdCandleTime == null
                    //        || stock.LastAboveThreshholdCandleTime < candle.Time))
                    //    {
                    //        stock.LastAboveThreshholdCandleTime = candle.Time;
                    //        if (stock.MonthVolume == 0)
                    //            await GetMonthStats(stock);
                    //        _telegram.PostMessage(stock.GetFiveMinChangeInfoText());
                    //        //_telegram.PostMessage($"Цена {stock.Ticker} изменилась на {change:P2} за 5 минут. Объем за 5 минут: {candle.Volume}" +
                    //        //    $"\r\nКурс на начало дня: {stock.TodayOpenF}, Текущий: {stock.PriceF}, Изменение за день: {stock.DayChangeF}");
                    //        _uiContext.Post(obj => {
                    //            _tradingVM.Messages.Add(new MessageViewModel
                    //            {
                    //                Ticker = stock.Ticker,
                    //                Date = DateTime.Now,
                    //                Change = change,
                    //                Volume = candle.Volume,
                    //                Text = $"Цена {stock.Ticker} изменилась на {change:P2} за 5 минут."
                    //            });
                    //        }, null);
                    //        Interlocked.Increment(ref _refreshPendingCount);
                    //    }

                    //    QueueBrokerAction(b => b.SendStreamingRequestAsync(
                    //        UnsubscribeCandle(stock.Figi, CandleInterval.FiveMinutes)),
                    //        $"Отписка от 5-ти минутной свечи {stock.Ticker} ({stock.Figi})");
                    //    QueueBrokerAction(b => b.SendStreamingRequestAsync(
                    //        SubscribeCandle(stock.Figi, CandleInterval.Minute)),
                    //        $"Подписка на минутную свечу {stock.Ticker} ({stock.Figi})");
                    //}
                    #endregion
                    else if (candle.Interval == CandleInterval.Minute)
                    {
                        if (candle.Time.Date > stock.TodayDate)
                        {
                            QueueBrokerAction(b => b.SendStreamingRequestAsync(
                                                  UnsubscribeCandle(stock.Figi, CandleInterval.Minute)),
                                              $"Отписка от минутной свечи {stock.Ticker} ({stock.Figi})");
                            QueueBrokerAction(b => b.SendStreamingRequestAsync(
                                                  SubscribeCandle(stock.Figi, CandleInterval.Day)),
                                              $"Подписка на дневную свечу {stock.Ticker} ({stock.Figi})");
                            break;
                        }

                        stock.Price = candle.Close;
                        if (stock.TodayOpen > 0)
                        {
                            stock.DayChange = (stock.Price - stock.TodayOpen) / stock.TodayOpen;
                        }

                        stock.LastUpdate = DateTime.Now;
                        stock.LogCandle(candle);

                        if (TradeBot != null)
                        {
                            await TradeBot.Check(stock);
                        }

                        if (stock.DayChange > DayChangeTrigger &&
                            (stock.LastAboveThreshholdDate == null ||
                             stock.LastAboveThreshholdDate.Value.Date < stock.LastUpdate.Date))
                        {
                            stock.LastAboveThreshholdDate = stock.LastUpdate;

                            var infoReq = StreamingRequest.SubscribeInstrumentInfo(stock.Figi);
                            QueueBrokerAction(b => b.SendStreamingRequestAsync(infoReq),
                                              $"Подписка на статус инструмента {stock.Ticker} ({stock.Figi})");

                            if (IsTelegramEnabled)
                            {
                                _telegram.PostMessage(stock.GetDayChangeInfoText(), stock.Ticker);
                            }

                            BackgroundInvoke(() =>
                                {
                                    _tradingVM.Messages.Add(new MessageViewModel
                                    {
                                        Ticker = stock.Ticker,
                                        Date   = DateTime.Now,
                                        Change = stock.DayChange,
                                        Volume = candle.Volume,
                                        Text   = $"Цена {stock.Ticker} изменилась на {stock.DayChange:P2} с начала дня."
                                    });
                                });
                            Interlocked.Increment(ref _refreshPendingCount);
                        }

                        var change = stock.GetLast10MinChange(TenMinChangeTrigger);
                        if (Math.Abs(change.change) > TenMinChangeTrigger && stock.DayChange > TenMinChangeTrigger && (stock.LastAboveThreshholdCandleTime == null ||
                                                                                                                       stock.LastAboveThreshholdCandleTime < candle.Time.AddMinutes(-change.minutes)))
                        {
                            stock.LastAboveThreshholdCandleTime = candle.Time;
                            try
                            {
                                await GetMonthStats(stock);
                            }
                            catch (Exception ex)
                            {
                                await ResetConnection("Ошибка при получении статистики за месяц: " + ex.Message);
                            }
                            if (IsTelegramEnabled)
                            {
                                _telegram.PostMessage(stock.GetMinutesChangeInfoText(change.change, change.minutes, change.candles), stock.Ticker);
                            }
                            _uiContext.Post(obj => {
                                    _tradingVM.Messages.Add(new MessageViewModel
                                    {
                                        Ticker = stock.Ticker,
                                        Date   = DateTime.Now,
                                        Change = change.change,
                                        Volume = candle.Volume,
                                        Text   = $"Цена {stock.Ticker} изменилась на {change.change:P2} за {change.minutes} мин."
                                    });
                                }, null);

                            if (TradeBot != null && change.change > TenMinChangeTrigger && stock.DayChange < 0.2m && change.candles.Sum(c => c.Volume) > 100)
                            {
                                await TradeBot.Buy(stock);
                            }

                            Interlocked.Increment(ref _refreshPendingCount);
                        }
                    }
                    stock.IsNotifying = true;
                }

                break;
            }

            case OrderbookResponse or:
            {
                var stock = _tradingVM.Stocks.FirstOrDefault(s => s.Figi == or.Payload.Figi);
                if (stock != null && or.Payload.Asks.Count > 0 && or.Payload.Bids.Count > 0)
                {
                    stock.Price = (or.Payload.Asks[0][0] + or.Payload.Bids[0][0]) / 2;
                    if (stock.TodayOpen > 0)
                    {
                        stock.DayChange  = (stock.Price - stock.TodayOpen) / stock.TodayOpen;
                        stock.LastUpdate = or.Time.ToLocalTime();
                    }
                }

                break;
            }

            case InstrumentInfoResponse ir:
            {
                var info  = ir.Payload;
                var stock = _tradingVM.Stocks.FirstOrDefault(s => s.Figi == info.Figi);
                if (stock != null)
                {
                    stock.Status = info.TradeStatus;
                }

                break;
            }
            }
        }
Пример #5
0
        private async void Broker_StreamingEventReceived(object sender, StreamingEventReceivedEventArgs e)
        {
            //Debug.WriteLine(JsonConvert.SerializeObject(e.Response));
            _lastEventReceived = DateTime.Now;
            switch (e.Response)
            {
            case CandleResponse cr:
            {
                _stockProcessingQueue.Enqueue(cr);
                break;
            }

            case OrderbookResponse or:
            {
                var stock = _mainModel.Stocks.Values.FirstOrDefault(s => s.Figi == or.Payload.Figi);
                if (stock != null && or.Payload.Asks.Count > 0 && or.Payload.Bids.Count > 0)
                {
                    var bids = or.Payload.Bids.Where(b => b[1] >= 1).ToList();
                    var asks = or.Payload.Asks.Where(a => a[1] >= 1).ToList();
                    OrderbookInfoSpb[stock.Ticker] = new OrderbookModel(or.Payload.Depth, bids, asks,
                                                                        or.Payload.Figi, stock.Ticker, stock.Isin);
                    stock.BestBidSpb = bids[0][0];
                    stock.BestAskSpb = asks[0][0];
                    _stockProcessingQueue.Enqueue(stock);         // raise stock update (but only in sync with other updates)
                }

                break;
            }

            case InstrumentInfoResponse ir:
            {
                var info  = ir.Payload;
                var stock = _mainModel.Stocks.Values.FirstOrDefault(s => s.Figi == info.Figi);
                if (stock != null)
                {
                    if (String.IsNullOrWhiteSpace(stock.Status))
                    {
                        string status = info.TradeStatus;
                        if (status == "normal_trading")
                        {
                            status = "Торгуется";
                        }
                        stock.Status = status;
                        if (String.IsNullOrEmpty(stock.Status))
                        {
                            stock.Status = Instruments[stock.Ticker].InstrumentStatusShortDesc;
                        }
                    }
                    if (stock.LimitDown != ir.Payload.LimitDown)
                    {
                        stock.LimitDown = ir.Payload.LimitDown;
                    }
                    if (stock.LimitUp != ir.Payload.LimitUp)
                    {
                        stock.LimitUp = ir.Payload.LimitUp;
                    }
                    if (stock.MinPriceIncrement != ir.Payload.MinPriceIncrement)
                    {
                        stock.MinPriceIncrement = ir.Payload.MinPriceIncrement;
                    }
                }
                break;
            }
            }
        }