public async Task SendNotification(NotificationRule notificationRule, MarketInstrument instrument, CandlePayload firstCandle, CandlePayload lastCandle)
        {
            if (_notificationTimestampToTicker == null)
            {
                await LoadLastSendTimes();
            }

            try
            {
                if (!_notificationTimestampToTicker.ContainsKey(instrument.Ticker) ||
                    (_notificationTimestampToTicker.ContainsKey(instrument.Ticker) &&
                     DateTime.UtcNow - _notificationTimestampToTicker[instrument.Ticker] >= TimeSpan.FromHours(notificationRule.TimePeriodInHours)))
                {
                    var msg = MakeNotificationMessage(notificationRule, instrument, firstCandle, lastCandle);

                    await _telegramBot.SendNotification(msg);

                    _notificationTimestampToTicker[instrument.Ticker] = DateTime.UtcNow;
                    await SaveLastSendTimes();
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex.ToString());
                await Task.Delay(TimeSpan.FromSeconds(1));
            }
        }
示例#2
0
        public override IStockModel CreateStockModel(MarketInstrument instrument)
        {
            var stock = base.CreateStockModel(instrument);

            //_hub.Clients.All.SendAsync("stock", stock);
            return(stock);
        }
        private async Task <CandlePayload?> MeetRequirements(MarketInstrument instrument, CancellationToken ct)
        {
            try
            {
                var candles = await _contextProvider.Do(ctx => ctx.MarketCandlesAsync(
                                                            instrument.Figi, _timeProvider.Today.Subtract(TimeSpan.FromDays(7)), _timeProvider.Today, CandleInterval.Day
                                                            ), ct);

                ct.ThrowIfCancellationRequested();

                var dayCandle = candles.Candles.LastOrDefault();
                if (dayCandle == null)
                {
                    return(null);
                }
                var body = dayCandle.Close - dayCandle.Open;
                if (body >= 0)
                {
                    return(null);
                }

                var shadow = dayCandle.Low - dayCandle.Close;
                return(shadow / body < 0.2M ? dayCandle : null);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"{ex}");
                return(null);
            }
        }
示例#4
0
        private async Task HandleInstrument(Context context, MarketInstrument instrument, NotificationRule notificationRule)
        {
            // try get candles
            var timePeriodInHours = notificationRule.TimePeriodInHours;
            var interval          = CandleInterval.FiveMinutes;

            if (timePeriodInHours >= 12)
            {
                interval = CandleInterval.Hour;
            }

            var start   = DateTime.UtcNow.AddHours(-2.5 * timePeriodInHours);
            var end     = DateTime.UtcNow;
            var candles = await context.MarketCandlesAsync(instrument.Figi, start, end, interval);

            if (candles.Candles.Count == 0)
            {
                Log.Debug($"No candles for {instrument.Ticker}\t{start:dd.MM.yy HH:mm} - {end:dd.MM.yy HH:mm}");
                await Task.Delay(_sleepTime);

                return;
            }

            // handle a candle with maximum timestamp
            var lastCandle = candles.Candles.OrderByDescending(i => i.Time).First();

            // try to find a previuos candle
            var previousCandleTimestamp = lastCandle.Time.AddHours(-1 * timePeriodInHours);
            var previousCandles         = candles.Candles.Where(i => i.Time <= previousCandleTimestamp).ToList();
            var attempNumber            = 1;

            //in case it is the start of the day then try to get the last price from the first previous working day
            while (previousCandles.Count == 0)
            {
                start = previousCandleTimestamp.AddHours(-12 * attempNumber);
                end   = previousCandleTimestamp.AddHours(-12 * (attempNumber - 1));
                Log.Debug($"Can not find a previous candle for {instrument.Ticker} for {end:dd.MM.yy HH:mm}");
                Log.Debug($"Try to fetch candles for {instrument.Ticker} for {previousCandleTimestamp.AddHours(-12 * attempNumber):dd.MM.yy HH:mm} - {previousCandleTimestamp:dd.MM.yy HH:mm}");

                previousCandles = (await context.MarketCandlesAsync(instrument.Figi,
                                                                    start,
                                                                    end,
                                                                    interval)).Candles;
                attempNumber++;
                continue;
            }
            var firstCandle = previousCandles.OrderByDescending(i => i.Time).First();

            if (notificationRule.IsActual(firstCandle.Close, lastCandle.Close))
            {
                await _sendNotification(notificationRule, instrument, firstCandle, lastCandle);
            }

            LogTicker(instrument, notificationRule, lastCandle, firstCandle);
        }
示例#5
0
 public virtual IStockModel CreateStockModel(MarketInstrument instrument)
 {
     return(new StockModel {
         Figi = instrument.Figi,
         Isin = instrument.Isin,
         Name = instrument.Name,
         Lot = instrument.Lot,
         MinPriceIncrement = instrument.MinPriceIncrement,
         Ticker = instrument.Ticker,
         Currency = instrument.Currency.ToString()
     });
 }
        public async Task TryAdd(MarketInstrument instrument)
        {
            var models = _repository.GetAll();

            if (models.Any(m => m.Isin == instrument.Isin))
            {
                _logger.LogTrace($"Instrument '{instrument.Isin}' already present");
                return;
            }
            _logger.LogTrace($"Add instrument: {instrument}");
            await _repository.Add(new AssetMetadataModel(
                                      instrument.Isin, instrument.Figi, instrument.Name, instrument.Type.ToString()));
        }
示例#7
0
        public static Infrastructure.Common.Models.Market.CurrencyPair ToOuterModel(this MarketInstrument source)
        {
            var target = new Infrastructure.Common.Models.Market.CurrencyPair
            {
                Id                = source.Figi,
                BaseCurrencyId    = source.Ticker,
                QuoteCurrencyId   = source.Currency.ToString(),
                QuantityIncrement = source.MinPriceIncrement,
                TickSize          = source.Lot,
                FeeCurrencyId     = source.Currency.ToString()
            };

            return(target);
        }
 public static YesterdayCandleData Create(MarketInstrument stock, CandlePayload candle)
 {
     return(new YesterdayCandleData(
                stock.Figi,
                stock.Name,
                Convert.ToInt32(candle.Volume),
                candle.Open,
                candle.Close,
                candle.Low,
                candle.High,
                stock.Currency,
                stock.MinPriceIncrement
                ));
 }
        public async Task MarketSearchByFigiTest()
        {
            const string figi = Figi;

            _handler.Expect(HttpMethod.Get, $"{BaseUri}market/search/by-figi")
            .WithQueryString("figi", figi)
            .WithoutContent()
            .RespondJsonFromFile("market-search-by-figi-response");

            var instrumentList = await _context.MarketSearchByFigiAsync(figi);

            var expected = new MarketInstrument(figi, "NFLX", "US64110L1061", 0.01m, 1, Currency.Usd, "Netflix", InstrumentType.Stock);

            instrumentList.Should().BeEquivalentTo(expected);
        }
示例#10
0
        public TestingTrading(MarketInstrument activeInstrument)
        {
            InitializeComponent();

            if (activeInstrument == null)
            {
                throw new ArgumentNullException();
            }

            TradingChart.instrument = new Instrument(activeInstrument);

            DataContext = this;

            IntervalComboBox.SelectedIndex = 5;
            StrategyComboBox.SelectedIndex = 0;
        }
示例#11
0
        private static void LogTicker(MarketInstrument instrument, NotificationRule notificationRule, CandlePayload lastCandle, CandlePayload firstCandle)
        {
            var priceChange          = lastCandle.Close - firstCandle.Close;
            var priceChangeInPercent = 100 * priceChange / firstCandle.Close;

            var msg =
                $"${instrument.Ticker} " +
                $"{notificationRule.TimePeriodInHours}h / {priceChangeInPercent.ToString("F2")} % / {(priceChange >= 0 ? "+" : "")}{priceChange.ToString("F2")} {instrument.Currency} / " +
                $"{firstCandle.Close} {instrument.Currency} -> {lastCandle.Close} {instrument.Currency} / " +
                $"{firstCandle.Time:dd.MM.yyyy HH:mm} -> {lastCandle.Time:dd.MM.yyyy HH:mm}";

            Log.Write(notificationRule.IsActual(firstCandle.Close, lastCandle.Close)
                ? Serilog.Events.LogEventLevel.Warning
                : Serilog.Events.LogEventLevel.Information,
                      msg);
        }
        public static Instrument ToInstrument(this MarketInstrument marketInstrument)
        {
            if (marketInstrument == null)
            {
                return(null);
            }

            return(new Instrument
            {
                Figi = marketInstrument.Figi,
                Isin = marketInstrument.Isin,
                Ticker = marketInstrument.Ticker,
                Lot = marketInstrument.Lot,
                MinPriceIncrement = marketInstrument.MinPriceIncrement,
                Name = marketInstrument.Name,
                Type = marketInstrument.Type,
                Currency = marketInstrument.Currency
            });
        }
示例#13
0
        private Instrument MarketInstrumentConverter(MarketInstrument marketInstrument)
        {
            if (marketInstrument == null)
            {
                return(null);
            }

            return(new Instrument
            {
                Figi = marketInstrument.Figi,
                Isin = marketInstrument.Isin,
                Ticker = marketInstrument.Ticker,
                Lot = marketInstrument.Lot,
                MinPriceIncrement = marketInstrument.MinPriceIncrement,
                Name = marketInstrument.Name,
                Type = marketInstrument.Type,
                Currency = marketInstrument.Currency
            });
        }
示例#14
0
        public async Task MarketSearchByTickerTest()
        {
            var handler    = new HttpMessageHandlerStub(HttpStatusCode.OK, "{\"trackingId\":\"QBASTAN\",\"status\":\"OK\",\"payload\":{\"figi\":\"BBG000CL9VN6\",\"ticker\":\"NFLX\",\"isin\":\"US64110L1061\",\"minPriceIncrement\":0.01,\"lot\":1,\"currency\":\"USD\"}}");
            var connection = new Connection(BaseUri, WebSocketBaseUri, Token, new HttpClient(handler));
            var context    = connection.Context;
            var instrument = await context.MarketSearchByTickerAsync("NFLX");

            Assert.NotNull(handler.RequestMessage);
            Assert.Equal(HttpMethod.Get, handler.RequestMessage.Method);
            Assert.Equal(new Uri($"{BaseUri}market/search/by-ticker?ticker=NFLX"), handler.RequestMessage.RequestUri);
            Assert.Null(handler.RequestMessage.Content);

            Assert.NotNull(instrument);

            var expected = new MarketInstrument("BBG000CL9VN6", "NFLX", "US64110L1061", 0.01m, 1, Currency.Usd);

            Assert.Equal(expected.Figi, instrument.Figi);
            Assert.Equal(expected.Ticker, instrument.Ticker);
            Assert.Equal(expected.Isin, instrument.Isin);
            Assert.Equal(expected.MinPriceIncrement, instrument.MinPriceIncrement);
            Assert.Equal(expected.Lot, instrument.Lot);
            Assert.Equal(expected.Currency, instrument.Currency);
        }
示例#15
0
        public RealTimeTrading(MarketInstrument activeInstrument)
        {
            InitializeComponent();

            if (activeInstrument == null)
            {
                throw new ArgumentNullException();
            }

            TradingChart.instrument = new Instrument(activeInstrument);

            candlesTimer = new Timer(e => CandlesTimerElapsed(),
                                     null,
                                     TimeSpan.FromSeconds(5),
                                     TimeSpan.FromSeconds(0.3)
                                     );

            DataContext = this;

            ShowBalance();

            IntervalComboBox.SelectedIndex = 5;
            StrategyComboBox.SelectedIndex = 0;
        }
        public MarketInstrumentSearchResponse([JsonProperty("payload")] MarketInstrument instrument)

        {
            Instrument = instrument;
        }
        private static string MakeNotificationMessage(NotificationRule notificationRule, MarketInstrument instrument, CandlePayload firstCandle, CandlePayload lastCandle)
        {
            var priceChange          = lastCandle.Close - firstCandle.Close;
            var priceChangeInPercent = 100 * priceChange / firstCandle.Close;

            var msg =
                $"{(notificationRule.PriceDirection == PriceDirection.Decrased ? "📉" : "📈") } " +
                $"${instrument.Ticker} {lastCandle.Close} {instrument.Currency}\r\n" +
                $"{notificationRule.TimePeriodInHours}h / {priceChangeInPercent.ToString("F2")} % / {(priceChange >= 0 ? "+" : "")}{priceChange.ToString("F2")} {instrument.Currency}\r\n" +
                $"{"https://www.tinkoff.ru/invest/stocks/"}{instrument.Ticker}";

            return(msg);
        }
示例#18
0
 public TinknoffInvestTicker(Exchange e, MarketInstrument instrument) : base(e)
 {
     Instrument = instrument;
 }