public async void StoreInstrumentCandles_WithExistingData() { // Arrange var instrument = InstrumentName.EUR_USD; var granularity = Granularity.H1; var candles = new List <Candle>() { new Candle() { Time = DateTime.UtcNow.AddDays(-3).AddHours(1), Volume = 1234, Bid = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, Mid = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, Ask = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, } }; var instrumentWithCandles = new InstrumentWithCandles() { InstrumentName = instrument, Granularity = granularity, Candles = candles }; var blobClientMock = new Mock <BlobClient>(); blobClientMock.Setup(bc => bc.UploadAsync(It.IsAny <Stream>(), true, It.IsAny <CancellationToken>())); blobClientMock.Setup(bc => bc.DownloadToAsync(It.IsAny <Stream>())).Callback <Stream>(candleStream => WriteSerializedCandlesToStream(candleStream)); // There is already existing data for the month var blobContainerClientMock = new Mock <BlobContainerClient>(); blobContainerClientMock.Setup(bcc => bcc.CreateIfNotExistsAsync(It.IsAny <PublicAccessType>(), null, null, It.IsAny <CancellationToken>())); blobContainerClientMock.Setup(bcc => bcc.GetBlobClient(It.IsAny <string>())).Returns(blobClientMock.Object); _storageClientMock.Setup(sc => sc.GetBlobContainerClient(It.IsAny <string>())).Returns(blobContainerClientMock.Object); // Act await _instrumentStorageService.StoreInstrumentCandles(instrumentWithCandles); // Assert blobClientMock.Verify(bc => bc.UploadAsync(It.IsAny <Stream>(), true, It.IsAny <CancellationToken>()), Times.Exactly(1)); }
/// <summary> /// Get instrument with it's candles for a specific timerange /// with a specific granularity /// </summary> /// <param name="instrument">Name of the instrument</param> /// <param name="granularity">Granularity of the instrument</param> /// <param name="utcFrom">Time to get the candles from (taken as an UTC time)</param> /// <param name="utcTo">Time to get the candles to (taken as an UTC time)</param> /// <returns>The instrument object with it's candles</returns> public async Task <InstrumentWithCandles> GetInstrumentCandles(InstrumentName instrument, Granularity granularity, DateTime utcFrom, DateTime utcTo) { // Collect all blob names needed var blobNames = GetBlobPaths(instrument, granularity, utcFrom, utcTo); // Get the container client var containerClient = _storageService.GetBlobContainerClient(INSTRUMENT_CONTAINER); // Create returning instrument object var instrumentWithCandles = new InstrumentWithCandles() { InstrumentName = instrument, Granularity = granularity, Candles = new List <Candle>() }; // Loop through the required blob files to get all candles data foreach (string blob in blobNames) { // Get the blob client var blobClient = containerClient.GetBlobClient(blob); // Download blob to stream using var stream = new MemoryStream(); await blobClient.DownloadToAsync(stream); // Deserialize stream to object stream.Position = 0; var serializer = new JsonSerializer(); using var streamReader = new StreamReader(stream); using var jsonTextReader = new JsonTextReader(streamReader); var candles = serializer.Deserialize <IEnumerable <Candle> >(jsonTextReader); // Add it to the instrument // Since it is abstract ICollection // Do a loop foreach (var candle in candles) { instrumentWithCandles.Candles.Add(candle); } } // Order candles by time (better safe then sorry) instrumentWithCandles.Candles.OrderBy(candle => candle.Time); // Return instrument with it's candles return(instrumentWithCandles); }
/// <summary> /// Store candles /// </summary> /// <param name="instrument">The instrument object to store candles for</param> /// <returns></returns> public async Task StoreInstrumentCandles(InstrumentWithCandles instrument) { // Get or create container var containerClient = _storageService.GetBlobContainerClient(INSTRUMENT_CONTAINER); await containerClient.CreateIfNotExistsAsync(); // Explode instrument to monthly candles list var candlesMonthly = instrument.Candles.ToLookup(c => new { c.Time.ToUniversalTime().Year, c.Time.ToUniversalTime().Month }); // Base folder name var instrumentGranularityFolder = GetInstrumentFolder(instrument.InstrumentName, instrument.Granularity); // Upload that monthly data foreach (var yearAndMonth in candlesMonthly) { // Candles to upload var candlesToUpload = candlesMonthly[yearAndMonth.Key].ToList(); // Download monthly data if exists try { var startTime = new DateTime(yearAndMonth.Key.Year, yearAndMonth.Key.Month, 1, 0, 0, 0, DateTimeKind.Utc); var endTime = new DateTime(yearAndMonth.Key.Year, yearAndMonth.Key.Month, DateTime.DaysInMonth(yearAndMonth.Key.Year, yearAndMonth.Key.Month), 0, 0, 0, DateTimeKind.Utc); var monthlyCandlesAlreadyThere = await GetInstrumentCandles(instrument.InstrumentName, instrument.Granularity, startTime, endTime); candlesToUpload.AddRange(monthlyCandlesAlreadyThere.Candles); } catch { // Swallow blob not found exception } // Serialize object to memory stream var serializedCandles = JsonConvert.SerializeObject(candlesToUpload); using var stream = new MemoryStream(Encoding.UTF8.GetBytes(serializedCandles)); // Upload to blob await containerClient.GetBlobClient($"{instrumentGranularityFolder}/{GetMonthlyFile(yearAndMonth.Key.Year, yearAndMonth.Key.Month)}").UploadAsync(stream, true); } }
public async void StoreInstrumentCandles_WithoutExistingData() { // Arrange var instrument = InstrumentName.EUR_USD; var granularity = Granularity.H1; var candles = new List <Candle>() { new Candle() { Time = new DateTime(2015, 5, 12, 10, 00, 00, DateTimeKind.Utc), Volume = 1234, Bid = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, Mid = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, Ask = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, }, new Candle() { Time = new DateTime(2015, 6, 12, 10, 00, 00, DateTimeKind.Utc), Volume = 1234, Bid = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, Mid = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, Ask = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, } }; var instrumentWithCandles = new InstrumentWithCandles() { InstrumentName = instrument, Granularity = granularity, Candles = candles }; var blobClientMock = new Mock <BlobClient>(); blobClientMock.Setup(bc => bc.UploadAsync(It.IsAny <Stream>(), true, It.IsAny <CancellationToken>())); blobClientMock.Setup(bc => bc.DownloadToAsync(It.IsAny <Stream>())).Throws(new Exception()); // No already existing data found for the given months var blobContainerClientMock = new Mock <BlobContainerClient>(); blobContainerClientMock.Setup(bcc => bcc.CreateIfNotExistsAsync(It.IsAny <PublicAccessType>(), null, null, It.IsAny <CancellationToken>())); blobContainerClientMock.Setup(bcc => bcc.GetBlobClient(It.IsAny <string>())).Returns(blobClientMock.Object); _storageClientMock.Setup(sc => sc.GetBlobContainerClient(It.IsAny <string>())).Returns(blobContainerClientMock.Object); // Act await _instrumentStorageService.StoreInstrumentCandles(instrumentWithCandles); // Assert blobClientMock.Verify(bc => bc.DownloadToAsync(It.IsAny <Stream>()), Times.Exactly(2)); blobClientMock.Verify(bc => bc.UploadAsync(It.IsAny <Stream>(), true, It.IsAny <CancellationToken>()), Times.Exactly(2)); }
public async void GetInstrumentCandles() { // Arrange var instrument = InstrumentName.EUR_USD; var granularity = Granularity.H1; var from = DateTime.UtcNow.AddDays(-5); var to = DateTime.UtcNow.AddDays(-5).AddHours(1); var mockCandles = new InstrumentWithCandles() { InstrumentName = instrument, Granularity = granularity, Candles = new List <Candle>() { new Candle() { Time = DateTime.UtcNow.AddDays(-5), Volume = 1234, Bid = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, Mid = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, Ask = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, }, new Candle() { Time = DateTime.UtcNow.AddDays(1), Volume = 1234, Bid = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, Mid = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, Ask = new Candlestick() { Open = 1.1234, High = 1.1234, Low = 1.1234, Close = 1.1234 }, } } }; _instrumentStorageServiceMock.Setup(iss => iss.GetInstrumentCandles(instrument, granularity, from, to)).Returns(Task.FromResult(mockCandles)); // Act var instrumentWithCandles = await _instrumentCandlesController.GetInstrumentCandles(instrument, granularity, from, to); // Assert _instrumentStorageServiceMock.Verify(iss => iss.GetInstrumentCandles(instrument, granularity, from, to), Times.Once()); Assert.Equal(mockCandles, instrumentWithCandles); }