public async Task MarketCandlesTest()
        {
            const string figi = Figi;
            const string from = "2019-10-17T18:38:33.1316420Z";
            const string to   = "2019-10-17T18:39:33.1316420Z";

            _handler.Expect(HttpMethod.Get, $"{BaseUri}market/candles")
            .WithQueryString(new Dictionary <string, string>
            {
                ["figi"]     = figi,
                ["from"]     = from,
                ["to"]       = to,
                ["interval"] = "1min"
            })
            .WithoutContent()
            .RespondJsonFromFile("market-candles-response");


            var candles = await _context.MarketCandlesAsync(figi,
                                                            DateTime.Parse(from).ToUniversalTime(),
                                                            DateTime.Parse(to).ToUniversalTime(), CandleInterval.Minute);

            var expected = new CandleList(figi, CandleInterval.Minute, new List <CandlePayload>
            {
                new CandlePayload(299.5m, 298.87m, 299.59m, 298.8m, 18887,
                                  DateTime.Parse("2019-10-17T15:39Z").ToUniversalTime(), CandleInterval.Minute, figi)
            });

            candles.Should().BeEquivalentTo(expected);
        }
Exemple #2
0
        /// <summary>
        /// 親専用
        /// Tickerでローソクを更新する
        /// </summary>
        /// <param name="ticker">Ticker</param>
        public void Update(Ticker ticker)
        {
            // 現在のTickerに設定
            CurrentTicker = ticker;

            if (CurrentCandle == null)
            {
                // 起動してから初回の動作
                if (SystemConstants.IsFirstDeleteCandle)
                {
                    // この板の全ローソクデータを削除
                    Logger.LogInformation($"ローソクデータ全削除:{Board.Name}");
                    var delList = DbContext.Candles.Include(x => x.MBoard).Where(d => d.MBoard.MBoardId == Board.MBoardId).ToList();
                    DbContext.Candles.RemoveRange(delList);
                    DbContext.SaveChanges();
                }

                // 新しいローソクの準備
                CurrentCandle = new Candle(Board, TimeScale, CurrentTicker);

                // 子要素を新しいローソクで更新
                UpdateChildren(CurrentCandle);
            }
            else // 初回ではない場合
            {
                // ローソクを更新
                var newCandles = CurrentCandle.UpdateByTicker(CurrentTicker);

                foreach (var item in newCandles)
                {
                    // 新しいローソクがある場合
                    // 現在のローソクでDB更新
                    Logger.LogDebug($"DB:Candles更新:{Board.Name} {TimeScale.DisplayName}");
                    DbContext.Candles.Add(CurrentCandle);

                    // 今まで作成したローソクに追加
                    CandleList.Add(CurrentCandle);

                    // 子要素を新しいローソクで更新
                    UpdateChildren(item);

                    // 新しいローソクをセット
                    CurrentCandle = item;
                }
                if (newCandles.Count > 0)
                {
                    // 更新があった場合
                    // 最大データ数を超えていたら、古いデータを1件削除
                    DeleteOldData();

                    // 子要素も更新が終わったらコミット
                    DbContext.SaveChanges(SystemConstants.SystemName);
                }
            }
        }
Exemple #3
0
        public async Task <decimal> GetPrice(string figi, DateTime moment = default)
        {
            //по стакану
            if (moment == default)
            {
                return(await GetPriceByOrderbook(figi));
            }

            //по истории свечей
            CandleList candleList = await _context.MarketCandlesAsync(figi, moment.AddDays(-7), moment, CandleInterval.Week);

            if (candleList.Candles.Any())
            {
                return(candleList.Candles.OrderBy(candle => candle.Time).Last().Close);
            }

            throw new Exception($"Не удалось найти цену на {moment.ToShortDateString()} с FIGI {figi}");
        }
Exemple #4
0
        public async Task AddOrAppendCandles(CurrencyCode currency, AssetFIGI figi, CandleList candles)
        {
            var model        = TryGetModel(figi);
            var candleModels = candles.Candles
                               .Select(c => new CandleModel(new DateTimeOffset(c.Time), c.Open, c.Close, c.Low, c.High))
                               .ToList();

            if (model != null)
            {
                _logger.LogTrace($"Add {candleModels.Count} candles to existing model '{currency}' with FIGI '{figi}'");
                model.Candles.AddRange(candleModels);
                await _repository.Update(model);
            }
            else
            {
                _logger.LogTrace($"Creating new model '{currency}' with FIGI '{figi}'");
                var newModel = new CurrencyPriceModel(currency, candles.Figi, candleModels);
                await _repository.Add(newModel);
            }
        }
Exemple #5
0
        /// <summary>
        /// 子専用
        /// 親から送られてきたローソクで更新する
        /// </summary>
        /// <param name="candle">ローソクデータ</param>
        public void UpdateByCandle(Candle candle)
        {
            Logger.LogDebug($"DB:Candles更新:{Board.Name} {TimeScale.DisplayName}");
            if (CurrentCandle == null)
            {
                // 初回
                // 新しいローソクの準備
                CurrentCandle = new Candle(Board, TimeScale, candle);

                // 子要素を更新
                UpdateChildren(candle);
            }
            else
            {
                // 2回目以降
                var newCandles = CurrentCandle.UpdateByCandle(candle);

                foreach (var item in newCandles)
                {
                    // 新しいローソクがある場合
                    // 現在のローソクでDB更新
                    DbContext.Candles.Add(CurrentCandle);

                    // 今まで作成したローソクに追加
                    CandleList.Add(CurrentCandle);

                    // 子要素を新しいローソクで更新
                    UpdateChildren(item);

                    // 新しいローソクをセット
                    CurrentCandle = item;
                }
                if (newCandles.Count > 0)
                {
                    // 更新があった場合
                    // 最大データ数を超えていたら、古いデータを1件削除
                    DeleteOldData();
                }
            }
        }
Exemple #6
0
        public async Task MarketCandlesTest()
        {
            var handler    = new HttpMessageHandlerStub(HttpStatusCode.OK, "{\"trackingId\":\"QBASTAN\",\"payload\":{\"candles\":[{\"o\":299.5,\"c\":298.87,\"h\":299.59,\"l\":298.8,\"v\":18887,\"time\":\"2019-10-17T15:39Z\",\"interval\":\"1min\",\"figi\":\"BBG000CL9VN6\"}],\"interval\":\"1min\",\"figi\":\"BBG000CL9VN6\"},\"status\":\"Ok\"}");
            var connection = new Connection(BaseUri, WebSocketBaseUri, Token, new HttpClient(handler));
            var context    = connection.Context;
            var candles    = await context.MarketCandlesAsync("BBG000CL9VN6", DateTime.Parse("2019-10-17T18:38:33.1316420+03:00"), DateTime.Parse("2019-10-17T18:39:33.1316420+03:00"), CandleInterval.Minute);

            Assert.NotNull(handler.RequestMessage);
            Assert.Equal(HttpMethod.Get, handler.RequestMessage.Method);
            Assert.Equal(new Uri($"{BaseUri}market/candles?figi=BBG000CL9VN6&from={HttpUtility.UrlEncode("2019-10-17T18:38:33.1316420+03:00")}&to={HttpUtility.UrlEncode("2019-10-17T18:39:33.1316420+03:00")}&interval=1min"), handler.RequestMessage.RequestUri);
            Assert.Null(handler.RequestMessage.Content);

            Assert.NotNull(candles);

            var expected = new CandleList("BBG000CL9VN6", CandleInterval.Minute, new List <CandlePayload>
            {
                new CandlePayload(299.5m, 298.87m, 299.59m, 298.8m, 18887, DateTime.Parse("2019-10-17T15:39Z").ToUniversalTime(), CandleInterval.Minute, "BBG000CL9VN6")
            });

            Assert.Equal(expected.Figi, candles.Figi);
            Assert.Equal(expected.Interval, candles.Interval);
            Assert.Equal(expected.Candles.Count, candles.Candles.Count);

            for (var i = 0; i < expected.Candles.Count; ++i)
            {
                var expectedCandle = expected.Candles[i];
                var actualCandle   = candles.Candles[i];
                Assert.Equal(expectedCandle.Time, actualCandle.Time);
                Assert.Equal(expectedCandle.Interval, actualCandle.Interval);
                Assert.Equal(expectedCandle.Figi, actualCandle.Figi);
                Assert.Equal(expectedCandle.Open, actualCandle.Open);
                Assert.Equal(expectedCandle.Close, actualCandle.Close);
                Assert.Equal(expectedCandle.High, actualCandle.High);
                Assert.Equal(expectedCandle.Low, actualCandle.Low);
                Assert.Equal(expectedCandle.Volume, actualCandle.Volume);
            }
        }
Exemple #7
0
        /// <summary>
        /// 親子共通
        /// 最大データ数を超えていたら古いデータを削除する
        /// 1件だけ
        /// </summary>
        private void DeleteOldData()
        {
            // コミットしていない分は数えられないことに注意
            // 今は起動のたびに消しているから良いが、メモリ内ローソクとDBのローソクの数が異なる場合があることも注意
            // →コミット済みに関して、メモリローソクの数を上回った分を削除するようにする
            if (CandleList.Count > SystemConstants.MaxCandle)
            {
                // 今まで作成したローソクから削除
                int delCount = CandleList.Count - SystemConstants.MaxCandle;
                for (int i = 0; i < delCount; i++)
                {
                    CandleList.RemoveAt(0);
                }
            }

            var count = DbContext.Candles.Include(x => x.MTimeScale).Include(x => x.MBoard).Where(d => d.MTimeScale.Id == TimeScale.Id && d.MBoard.MBoardId == Board.MBoardId).Count();

            // DBの、メモリのローソクよりも多い分を削除(今回コミットされてないものは除くので、1件ズレたりする)
            // ※遅いようだったらOrderByの使用をやめておく
            if (count > CandleList.Count)
            {
                int delCount = count - CandleList.Count;
                Logger.LogDebug($"Candle{delCount}件削除:{Board.Name} {TimeScale.DisplayName}");
                var delList  = new List <Candle>(delCount);
                var dataList = DbContext.Candles.Where(d => d.MTimeScale.Id == TimeScale.Id && d.MBoard.MBoardId == Board.MBoardId).OrderBy(d => d.Id).ToList();

                for (int i = 0; i < delCount; i++)
                {
                    delList.Add(dataList[i]);
                }
                foreach (var item in delList)
                {
                    DbContext.Candles.Remove(item);
                }
            }
        }
Exemple #8
0
        private async Task <bool> GetMonthStats(IStockModel stock)
        {
            if (!stock.MonthStatsExpired)
            {
                return(true);
            }

            _apiCount++;
            //Debug.WriteLine($"API Request {++_apiCount} for {stock.Ticker} {stock.PriceF} {stock.DayChangeF} {DateTime.Now}");

            CandleList prices = null;

            try
            {
                prices = await CommonConnection.Context.MarketCandlesAsync(stock.Figi,
                                                                           DateTime.Now.Date.AddMonths(-1),
                                                                           DateTime.Now.Date.AddDays(1), CandleInterval.Day);

                stock.LastMonthDataUpdate = DateTime.Now;
            }
            catch
            {
                return(false);
            }

            if (prices.Candles.Count == 0)
            {
                return(false);
            }

            decimal monthVolume = 0, monthHigh = 0, monthLow = 0, monthAvgPrice = 0,
                    avgDayVolumePerMonth = 0, avgDayPricePerMonth = 0, monthOpen = -1,
                    yesterdayVolume = 0, yesterdayMin = 0, yesterdayMax = 0, yesterdayAvgPrice = 0;

            var todayCandle = prices.Candles[prices.Candles.Count - 1];

            foreach (var candle in prices.Candles)
            {
                if (monthOpen == -1)
                {
                    monthOpen = candle.Open;
                }

                monthLow             = monthLow == 0 ? candle.Low : Math.Min(monthLow, candle.Low);
                monthHigh            = monthHigh == 0 ? candle.High : Math.Min(monthHigh, candle.High);
                monthVolume         += candle.Volume;
                avgDayPricePerMonth += (candle.High + candle.Low) / 2;
                yesterdayVolume      = candle.Volume;
                yesterdayMin         = candle.Low;
                yesterdayMax         = candle.High;

                AddCandleToStock(Tuple.Create(stock, candle));
            }

            monthAvgPrice        = (monthLow + monthHigh) / 2;
            yesterdayAvgPrice    = (yesterdayMin + yesterdayMax) / 2;
            avgDayPricePerMonth /= prices.Candles.Count;
            avgDayVolumePerMonth = monthVolume / prices.Candles.Count;

            stock.MonthOpen                = monthOpen;
            stock.MonthHigh                = monthHigh;
            stock.MonthLow                 = monthLow;
            stock.MonthVolume              = monthVolume;
            stock.MonthVolumeCost          = monthVolume * monthAvgPrice * stock.Lot;
            stock.AvgDayVolumePerMonth     = Math.Round(avgDayVolumePerMonth);
            stock.AvgDayPricePerMonth      = avgDayPricePerMonth;
            stock.AvgDayVolumePerMonthCost = avgDayPricePerMonth * avgDayVolumePerMonth * stock.Lot;
            stock.DayVolChgOfAvg           = stock.DayVolume / stock.AvgDayVolumePerMonth;
            stock.YesterdayAvgPrice        = yesterdayAvgPrice;
            stock.YesterdayVolume          = yesterdayVolume;
            stock.YesterdayVolumeCost      = yesterdayVolume * yesterdayAvgPrice * stock.Lot;

            return(true);
        }