quotes = new(barSet.Items.Count); // compose foreach (IBar bar in barSet.Items) { - quotes.Add(new Quote { - Date = bar.TimeUtc, - Open = bar.Open, - High = bar.High, - Low = bar.Low, - Close = bar.Close, - Volume = bar.Volume - }); + quotes.Add(new Quote(bar.TimeUtc, bar.Open, bar.High, bar.Low, bar.Close, bar.Volume)); } string json = JsonSerializer - .Serialize(quotes.OrderBy(x => x.Date)); + .Serialize(quotes.OrderBy(x => x.Timestamp)); // store in Azure Blob Storage string blobName = $"{symbol}-DAILY.json"; - await _storage.PutBlobAsync(blobName, json); + await _storage.PutBlobAsync(blobName, json, ct); LogBlobUpdated(blobName); } diff --git a/server/Functions/local.settings.example.json b/server/Functions/local.settings.example.json index e3ad2c72..3b713bd4 100644 --- a/server/Functions/local.settings.example.json +++ b/server/Functions/local.settings.example.json @@ -3,9 +3,9 @@ "Values": { "AzureWebJobsStorage": "UseDevelopmentStorage=true", "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated", - "ALPACA_KEY": "your-alpaca-api-key-here", - "ALPACA_SECRET": "your-alpaca-secret-here", "KEY_VAULT_URL": "", - "FUNCTIONS_RUN_ON_STARTUP_ENABLED": "true" + "FUNCTIONS_RUN_ON_STARTUP_ENABLED": "true", + "ALPACA_KEY": "", + "ALPACA_SECRET": "" } } diff --git a/server/Functions/packages.lock.json b/server/Functions/packages.lock.json index fcaffc06..4ad0ee42 100644 --- a/server/Functions/packages.lock.json +++ b/server/Functions/packages.lock.json @@ -23,11 +23,11 @@ }, "Azure.Security.KeyVault.Secrets": { "type": "Direct", - "requested": "[4.10.0, )", - "resolved": "4.10.0", - "contentHash": "lcJtcgTkk1gGy59RQhGLJLMyad+zgASMn975PVjMft69q+jjFTo6Nyq5SCtOhPY1WvA0gNI1qYIVN2oikVXDjw==", + "requested": "[4.11.0, )", + "resolved": "4.11.0", + "contentHash": "tjpVczILiXTR9bEynSL1JBU80169hGnTECtGsFjnRz9E1xoIhfUsaUTnB79k995zDkOG61hOI+YBtf5bNqgRIQ==", "dependencies": { - "Azure.Core": "1.53.0" + "Azure.Core": "1.54.0" } }, "Microsoft.Azure.Functions.Worker": { @@ -68,11 +68,11 @@ }, "Azure.Storage.Common": { "type": "Transitive", - "resolved": "12.26.0", - "contentHash": "XaT6CDcSshZb7KaCTwc6m4EouZbLBg7ciOEpsJSdJCvkNsZJQCvPKw7V5TtXno19AA1NpwtsZriYque8mzbQVg==", + "resolved": "12.27.0", + "contentHash": "PBucMNzot6cYyN0isdte50iPCefJ4Ylg0B+KP4kxmqsc3ciOiDYh1MwVV6fPZPjoPnPvNRLN9TI6J5hgNf4huA==", "dependencies": { - "Azure.Core": "1.50.0", - "System.IO.Hashing": "10.0.1" + "Azure.Core": "1.51.1", + "System.IO.Hashing": "10.0.3" } }, "Google.Protobuf": { @@ -499,8 +499,8 @@ }, "System.IO.Hashing": { "type": "Transitive", - "resolved": "10.0.1", - "contentHash": "Dy6ULPb2S0GmNndjKrEIpfibNsc8+FTOoZnqygtFDuyun8vWboQbfMpQtKUXpgTxokR5E4zFHETpNnGfeWY6NA==" + "resolved": "10.0.3", + "contentHash": "La6ICwsdTKhVX+LKN+pvFjQRR3LhLwq3uKdi2knjLzRyPYBSydF4cjXidYxIiTcDD6XVYdsBWQEI8ZxiZ/OdIg==" }, "System.Memory.Data": { "type": "Transitive", @@ -516,17 +516,17 @@ "type": "Project", "dependencies": { "Azure.Identity": "[1.21.0, )", - "Azure.Security.KeyVault.Secrets": "[4.10.0, )", - "Azure.Storage.Blobs": "[12.27.0, )", + "Azure.Security.KeyVault.Secrets": "[4.11.0, )", + "Azure.Storage.Blobs": "[12.28.0, )", "Microsoft.Extensions.Azure": "[1.14.0, )", - "Skender.Stock.Indicators": "[2.7.1, )" + "Skender.Stock.Indicators": "[3.0.0-preview.3.1, )" } }, "Azure.Core": { "type": "CentralTransitive", "requested": "[1.50.0, )", - "resolved": "1.53.0", - "contentHash": "x9c/toFMOtRrlTdFuE7rlGCVAduQzWVfKmLz5juj41zJAXEhYD5hluiUyyAEzJ6OxpBnKtiaBztzwpZITAVjtg==", + "resolved": "1.54.0", + "contentHash": "m6hHbx1q9+GCBZ5A9ykzFylPdTwscX2APH7PlnqV+yu+DH3RRtuIDJMRqdU17cMyinv0hCPofpegoyQ6qWPW7g==", "dependencies": { "Microsoft.Bcl.AsyncInterfaces": "10.0.3", "Microsoft.Extensions.Configuration.Abstractions": "10.0.3", @@ -539,12 +539,12 @@ }, "Azure.Storage.Blobs": { "type": "CentralTransitive", - "requested": "[12.27.0, )", - "resolved": "12.27.0", - "contentHash": "zI5rg1tTtnA8T2g2/21l+1iIUdDjpEQQ0FI1BabJVEQJ1JUyTQKrc41eNabAHs0SBHprl6pu/6OqIMK9Ve+4tQ==", + "requested": "[12.28.0, )", + "resolved": "12.28.0", + "contentHash": "OK6slT3Hq3Yp2HWA0e23YHheHzKNbYjBZOwdT4fQ1iMH6I/8e6X8kAJLuKqVUeFBy160QSwhsynA3HxhVSHEcg==", "dependencies": { - "Azure.Core": "1.50.0", - "Azure.Storage.Common": "12.26.0" + "Azure.Core": "1.51.1", + "Azure.Storage.Common": "12.27.0" } }, "Microsoft.Extensions.Azure": { @@ -560,9 +560,9 @@ }, "Skender.Stock.Indicators": { "type": "CentralTransitive", - "requested": "[2.7.1, )", - "resolved": "2.7.1", - "contentHash": "HsHVlg9Tcb1gUV50dpazlUh2Qy1F9NtG7Fe4pYcxgnnloW4Fdh8TQTA7IB5M7rWubEvtFgzx+1U1vI2LzJPWXg==" + "requested": "[3.0.0-preview.3.1, )", + "resolved": "3.0.0-preview.3.1", + "contentHash": "oBzrKgtwRRGfJyotPufP1tpNUnNeUgyiv58aY9E/Z4qaKfLL0pOqPUtcS9/5z/mnmhtyRCe/BKPkRKTD4kHUKw==" } } } diff --git a/server/WebApi.Tests/Endpoints/MainEndpointsTests.cs b/server/WebApi.Tests/Endpoints/MainEndpointsTests.cs new file mode 100644 index 00000000..079690d6 --- /dev/null +++ b/server/WebApi.Tests/Endpoints/MainEndpointsTests.cs @@ -0,0 +1,237 @@ +using System.Net; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using WebApi.Controllers; +using Xunit; + +namespace WebApi.Tests.Endpoints; + +///+/// Unit tests for Main controller endpoints. +/// Tests endpoint initialization and basic functionality. +/// +public class MainEndpointsTests +{ + private readonly Mock_quoteServiceMock; + private readonly Main _controller; + + public MainEndpointsTests() + { + _quoteServiceMock = new Mock (); + _controller = new Main(_quoteServiceMock.Object); + } + + [Fact] + public void Get_ReturnsHealthCheckMessage() + { + // Act + var result = _controller.Get(); + + // Assert + Assert.NotNull(result); + Assert.Contains("functioning", result, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public async Task GetQuotes_WithValidData_ReturnsOkResult() + { + // Arrange + var sampleQuotes = new[] + { + new Quote(DateTime.UtcNow, 100m, 102m, 99m, 101m, 1000000), + new Quote(DateTime.UtcNow.AddDays(-1), 99m, 101m, 98m, 100m, 900000) + }; + + _quoteServiceMock + .Setup(q => q.Get(It.IsAny ())) + .ReturnsAsync(sampleQuotes); + + // Setup HttpContext for the controller + var httpContext = new DefaultHttpContext(); + _controller.ControllerContext = new ControllerContext { + HttpContext = httpContext + }; + + // Act + var result = await _controller.GetQuotes(); + + // Assert + Assert.IsType (result); + var okResult = (OkObjectResult)result; + Assert.NotNull(okResult.Value); + } + + [Fact] + public void GetIndicatorCatalog_ReturnsOkResultWithMetadata() + { + // Arrange + var httpContext = new DefaultHttpContext(); + var request = httpContext.Request; + request.Scheme = "https"; + request.Host = new HostString("localhost:5001"); + + _controller.ControllerContext = new ControllerContext { + HttpContext = httpContext + }; + + // Act + var result = _controller.GetIndicatorCatalog(); + + // Assert + Assert.IsType (result); + var okResult = (OkObjectResult)result; + Assert.NotNull(okResult.Value); + } + + [Fact] + public async Task GetAdl_WithValidQuotes_ReturnsOkResult() + { + // Arrange + var sampleQuotes = GenerateSampleQuotes(50); + _quoteServiceMock + .Setup(q => q.Get(It.IsAny ())) + .ReturnsAsync(sampleQuotes); + + var httpContext = new DefaultHttpContext(); + _controller.ControllerContext = new ControllerContext { + HttpContext = httpContext + }; + + // Act + var result = await _controller.GetAdl(); + + // Assert + Assert.IsType (result); + } + + [Fact] + public async Task GetAdx_WithValidParameters_ReturnsOkResult() + { + // Arrange + var sampleQuotes = GenerateSampleQuotes(50); + _quoteServiceMock + .Setup(q => q.Get(It.IsAny ())) + .ReturnsAsync(sampleQuotes); + + var httpContext = new DefaultHttpContext(); + _controller.ControllerContext = new ControllerContext { + HttpContext = httpContext + }; + + // Act + var result = await _controller.GetAdx(14); + + // Assert + Assert.IsType (result); + } + + [Fact] + public async Task GetRsi_WithValidParameters_ReturnsOkResult() + { + // Arrange + var sampleQuotes = GenerateSampleQuotes(50); + _quoteServiceMock + .Setup(q => q.Get(It.IsAny ())) + .ReturnsAsync(sampleQuotes); + + var httpContext = new DefaultHttpContext(); + _controller.ControllerContext = new ControllerContext { + HttpContext = httpContext + }; + + // Act + var result = await _controller.GetRsi(14); + + // Assert + Assert.IsType (result); + } + + [Fact] + public async Task GetMacd_WithValidParameters_ReturnsOkResult() + { + // Arrange + var sampleQuotes = GenerateSampleQuotes(50); + _quoteServiceMock + .Setup(q => q.Get(It.IsAny ())) + .ReturnsAsync(sampleQuotes); + + var httpContext = new DefaultHttpContext(); + _controller.ControllerContext = new ControllerContext { + HttpContext = httpContext + }; + + // Act + var result = await _controller.GetMacd(12, 26, 9); + + // Assert + Assert.IsType (result); + } + + [Fact] + public async Task GetBollingerBands_WithValidParameters_ReturnsOkResult() + { + // Arrange + var sampleQuotes = GenerateSampleQuotes(50); + _quoteServiceMock + .Setup(q => q.Get(It.IsAny ())) + .ReturnsAsync(sampleQuotes); + + var httpContext = new DefaultHttpContext(); + _controller.ControllerContext = new ControllerContext { + HttpContext = httpContext + }; + + // Act + var result = await _controller.GetBollingerBands(20, 2.0); + + // Assert + Assert.IsType (result); + } + + [Fact] + public async Task GetSma_WithValidParameters_ReturnsOkResult() + { + // Arrange + var sampleQuotes = GenerateSampleQuotes(50); + _quoteServiceMock + .Setup(q => q.Get(It.IsAny ())) + .ReturnsAsync(sampleQuotes); + + var httpContext = new DefaultHttpContext(); + _controller.ControllerContext = new ControllerContext { + HttpContext = httpContext + }; + + // Act + var result = await _controller.GetSma(20); + + // Assert + Assert.IsType (result); + } + + /// + /// Helper to generate sample quote data for tests. + /// + private static ListGenerateSampleQuotes(int count) + { + var quotes = new List(); + var startDate = DateTime.UtcNow.AddDays(-count); + + for (int i = 0; i < count; i++) + { + var date = startDate.AddDays(i); + var basePrice = 100m + i * 0.5m; + + quotes.Add(new Quote( + date, + basePrice, + basePrice + 2m, + basePrice - 2m, + basePrice + 1m, + 1000000 + i * 10000)); + } + + return quotes; + } +} diff --git a/server/WebApi.Tests/Services/RandomQuotesTests.cs b/server/WebApi.Tests/Services/RandomQuotesTests.cs index 3de7b163..aabc7a2e 100644 --- a/server/WebApi.Tests/Services/RandomQuotesTests.cs +++ b/server/WebApi.Tests/Services/RandomQuotesTests.cs @@ -98,8 +98,8 @@ public void Constructor_ExcludeWeekends_RemovesWeekendBars() // Verify no weekend dates when weekends are excluded Assert.All(quotesWithoutWeekends, quote => { - Assert.True(quote.Date.DayOfWeek is not DayOfWeek.Saturday and not DayOfWeek.Sunday, - $"Found weekend date {quote.Date:yyyy-MM-dd} ({quote.Date.DayOfWeek}) when weekends should be excluded"); + Assert.True(quote.Timestamp.DayOfWeek is not DayOfWeek.Saturday and not DayOfWeek.Sunday, + $"Found weekend date {quote.Timestamp:yyyy-MM-dd} ({quote.Timestamp.DayOfWeek}) when weekends should be excluded"); }); } diff --git a/server/WebApi.Tests/Services/UtilitiesTests.cs b/server/WebApi.Tests/Services/UtilitiesTests.cs index 3cf8948b..ac29d96e 100644 --- a/server/WebApi.Tests/Services/UtilitiesTests.cs +++ b/server/WebApi.Tests/Services/UtilitiesTests.cs @@ -12,7 +12,7 @@ public class UtilitiesTests public void ToTimeSpan_KnownMappings_ReturnsExpected(PeriodSize periodSize, int expectedMinutes) { // Arrange & Act - TimeSpan result = periodSize.ToTimeSpan(); + TimeSpan result = Utilities.ToTimeSpan(periodSize); // Assert Assert.Equal(TimeSpan.FromMinutes(expectedMinutes), result); @@ -25,7 +25,7 @@ public void ToTimeSpan_KnownMappings_ReturnsExpected(PeriodSize periodSize, int public void ToTimeSpan_KnownHourMappings_ReturnsExpected(PeriodSize periodSize, int expectedHours) { // Arrange & Act - TimeSpan result = periodSize.ToTimeSpan(); + TimeSpan result = Utilities.ToTimeSpan(periodSize); // Assert Assert.Equal(TimeSpan.FromHours(expectedHours), result); @@ -37,7 +37,7 @@ public void ToTimeSpan_KnownHourMappings_ReturnsExpected(PeriodSize periodSize, public void ToTimeSpan_KnownDayMappings_ReturnsExpected(PeriodSize periodSize, int expectedDays) { // Arrange & Act - TimeSpan result = periodSize.ToTimeSpan(); + TimeSpan result = Utilities.ToTimeSpan(periodSize); // Assert Assert.Equal(TimeSpan.FromDays(expectedDays), result); @@ -50,7 +50,7 @@ public void ToTimeSpan_Unsupported_ThrowsArgumentOutOfRange() const PeriodSize unsupportedPeriod = PeriodSize.Month; // Act & Assert - ArgumentOutOfRangeException exception = Assert.Throws(() => unsupportedPeriod.ToTimeSpan()); + ArgumentOutOfRangeException exception = Assert.Throws (() => Utilities.ToTimeSpan(unsupportedPeriod)); Assert.Equal("periodSize", exception.ParamName); Assert.Contains("Unsupported PeriodSize value", exception.Message); Assert.Contains("Month", exception.Message); diff --git a/server/WebApi.Tests/WebApi.Tests.csproj b/server/WebApi.Tests/WebApi.Tests.csproj index 14d8d5b1..3f2bb705 100644 --- a/server/WebApi.Tests/WebApi.Tests.csproj +++ b/server/WebApi.Tests/WebApi.Tests.csproj @@ -13,6 +13,8 @@ diff --git a/server/WebApi.Tests/packages.lock.json b/server/WebApi.Tests/packages.lock.json index eda59661..eae845a8 100644 --- a/server/WebApi.Tests/packages.lock.json +++ b/server/WebApi.Tests/packages.lock.json @@ -8,14 +8,34 @@ "resolved": "10.0.0", "contentHash": "WFejCcOUR6k8UYyDnnR6Gk+obFYMsWrZuNqPJnsVFGVhpPSN0y20D4qbdKJnXinYGx9PQ397Hf9TnU1NBST8vA==" }, + "Microsoft.AspNetCore.Mvc.Testing": { + "type": "Direct", + "requested": "[10.0.0, )", + "resolved": "10.0.0", + "contentHash": "Gdtv34h2qvynOEu+B2+6apBiiPhEs39namGax02UgaQMRetlxQ88p2/jK1eIdz3m1NRgYszNBN/jBdXkucZhvw==", + "dependencies": { + "Microsoft.AspNetCore.TestHost": "10.0.0", + "Microsoft.Extensions.DependencyModel": "10.0.0", + "Microsoft.Extensions.Hosting": "10.0.0" + } + }, "Microsoft.NET.Test.Sdk": { "type": "Direct", - "requested": "[18.4.0, )", - "resolved": "18.4.0", - "contentHash": "w49iZdL4HL6V25l41NVQLXWQ+e71GvSkKVteMrOL02gP/PUkcnO/1yEb2s9FntU4wGmJWfKnyrRAhcMHd9ZZNA==", + "requested": "[18.5.1, )", + "resolved": "18.5.1", + "contentHash": "SfqVaLiIqAbRWuPg5BP4QFwBIirQj/YIL8Dhxl6zntBKbXp0cQykoV480SmwG+yRMiWptxEI6NbHQuGSZ8b97w==", "dependencies": { - "Microsoft.CodeCoverage": "18.4.0", - "Microsoft.TestPlatform.TestHost": "18.4.0" + "Microsoft.CodeCoverage": "18.5.1", + "Microsoft.TestPlatform.TestHost": "18.5.1" + } + }, + "Moq": { + "type": "Direct", + "requested": "[4.20.70, )", + "resolved": "4.20.70", + "contentHash": "4rNnAwdpXJBuxqrOCzCyICXHSImOTRktCgCWXWykuF1qwoIsVvEnR7PjbMk/eLOxWvhmj5Kwt+kDV3RGUYcNwg==", + "dependencies": { + "Castle.Core": "5.1.1" } }, "xunit.runner.visualstudio": { @@ -35,11 +55,19 @@ }, "Azure.Storage.Common": { "type": "Transitive", - "resolved": "12.26.0", - "contentHash": "XaT6CDcSshZb7KaCTwc6m4EouZbLBg7ciOEpsJSdJCvkNsZJQCvPKw7V5TtXno19AA1NpwtsZriYque8mzbQVg==", + "resolved": "12.27.0", + "contentHash": "PBucMNzot6cYyN0isdte50iPCefJ4Ylg0B+KP4kxmqsc3ciOiDYh1MwVV6fPZPjoPnPvNRLN9TI6J5hgNf4huA==", "dependencies": { - "Azure.Core": "1.50.0", - "System.IO.Hashing": "10.0.1" + "Azure.Core": "1.51.1", + "System.IO.Hashing": "10.0.3" + } + }, + "Castle.Core": { + "type": "Transitive", + "resolved": "5.1.1", + "contentHash": "rpYtIczkzGpf+EkZgDr9CClTdemhsrwA/W5hMoPjLkRFnXzH44zDLoovXeKtmxb1ykXK9aJVODSpiJml8CTw2g==", + "dependencies": { + "System.Diagnostics.EventLog": "6.0.0" } }, "Microsoft.ApplicationInsights": { @@ -47,6 +75,11 @@ "resolved": "2.23.0", "contentHash": "nWArUZTdU7iqZLycLKWe0TDms48KKGE6pONH2terYNa8REXiqixrMOkf1sk5DHGMaUTqONU2YkS4SAXBhLStgw==" }, + "Microsoft.AspNetCore.TestHost": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "Q3ia+k+wYM3Iv/Qq5IETOdpz/R0xizs3WNAXz699vEQx5TMVAfG715fBSq9Thzopvx8dYZkxQ/mumTn6AJ/vGQ==" + }, "Microsoft.Bcl.AsyncInterfaces": { "type": "Transitive", "resolved": "10.0.3", @@ -54,8 +87,8 @@ }, "Microsoft.CodeCoverage": { "type": "Transitive", - "resolved": "18.4.0", - "contentHash": "9O0BtCfzCWrkAmK187ugKdq72HHOXoOUjuWFDVc2LsZZ0pOnA9bTt+Sg9q4cF+MoAaUU+MuWtvBuFsnduviJow==" + "resolved": "18.5.1", + "contentHash": "vMFDR1ZjqzzgKmM0zrPie7Gv9Y+ZppjODB5Quzu9Eq0TlIusUfUCYFPEawO91zQuqwzvdFbJSU7WHNtjStffJQ==" }, "Microsoft.Extensions.Configuration": { "type": "Transitive", @@ -83,6 +116,58 @@ "Microsoft.Extensions.Configuration.Abstractions": "10.0.3" } }, + "Microsoft.Extensions.Configuration.CommandLine": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "CRj5clwZciVs46GMhAthkFq3+JiNM15Bz9CRlCZLBmRdggD6RwoBphRJ+EUDK2f+cZZ1L2zqVaQrn1KueoU5Kg==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.0" + } + }, + "Microsoft.Extensions.Configuration.EnvironmentVariables": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "TmFegsI/uCdwMBD4yKpmO+OkjVNHQL49Dh/ep83NI5rPUEoBK9OdsJo1zURc1A2FuS/R/Pos3wsTjlyLnguBLA==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.0" + } + }, + "Microsoft.Extensions.Configuration.FileExtensions": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "LqCTyF0twrG4tyEN6PpSC5ewRBDwCBazRUfCOdRddwaQ3n2S57GDDeYOlTLcbV/V2dxSSZWg5Ofr48h6BsBmxw==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.0", + "Microsoft.Extensions.FileProviders.Physical": "10.0.0", + "Microsoft.Extensions.Primitives": "10.0.0" + } + }, + "Microsoft.Extensions.Configuration.Json": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "BIOPTEAZoeWbHlDT9Zudu+rpecZizFwhdIFRiyZKDml7JbayXmfTXKUt+ezifsSXfBkWDdJM10oDOxo8pufEng==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "10.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.0" + } + }, + "Microsoft.Extensions.Configuration.UserSecrets": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "B4qHB6gQ2B3I52YRohSV7wetp01BQzi8jDmrtiVm6e4l8vH5vjqwxWcR5wumGWjdBkj1asJLLsDIocdyTQSP0A==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "10.0.0", + "Microsoft.Extensions.Configuration.Json": "10.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.0", + "Microsoft.Extensions.FileProviders.Physical": "10.0.0" + } + }, "Microsoft.Extensions.DependencyInjection": { "type": "Transitive", "resolved": "10.0.3", @@ -96,6 +181,21 @@ "resolved": "10.0.3", "contentHash": "bwGMrRcAMWx2s/RDgja97p27rxSz2pEQW0+rX5cWAUWVETVJ/eyxGfjAl8vuG5a+lckWmPIE+vcuaZNVB5YDdw==" }, + "Microsoft.Extensions.DependencyModel": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "RFYJR7APio/BiqdQunRq6DB+nDB6nc2qhHr77mlvZ0q0BT8PubMXN7XicmfzCbrDE/dzhBnUKBRXLTcqUiZDGg==" + }, + "Microsoft.Extensions.Diagnostics": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "xjkxIPgrT0mKTfBwb+CVqZnRchyZgzKIfDQOp8z+WUC6vPe3WokIf71z+hJPkH0YBUYJwa7Z/al1R087ib9oiw==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.0", + "Microsoft.Extensions.Diagnostics.Abstractions": "10.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "10.0.0" + } + }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", "resolved": "10.0.3", @@ -113,6 +213,50 @@ "Microsoft.Extensions.Primitives": "10.0.3" } }, + "Microsoft.Extensions.FileProviders.Physical": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "UZUQ74lQMmvcprlG8w+XpxBbyRDQqfb7GAnccITw32hdkUBlmm9yNC4xl4aR9YjgV3ounZcub194sdmLSfBmPA==", + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "10.0.0", + "Microsoft.Extensions.Primitives": "10.0.0" + } + }, + "Microsoft.Extensions.FileSystemGlobbing": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "5hfVl/e+bx1px2UkN+1xXhd3hu7Ui6ENItBzckFaRDQXfr+SHT/7qrCDrlQekCF/PBtEu2vtk87U2+gDEF8EhQ==" + }, + "Microsoft.Extensions.Hosting": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "yKJiVdXkSfe9foojGpBRbuDPQI8YD71IO/aE8ehGjRHE0VkEF/YWkW6StthwuFF146pc2lypZrpk/Tks6Plwhw==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.0", + "Microsoft.Extensions.Configuration.Binder": "10.0.0", + "Microsoft.Extensions.Configuration.CommandLine": "10.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "10.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "10.0.0", + "Microsoft.Extensions.Configuration.Json": "10.0.0", + "Microsoft.Extensions.Configuration.UserSecrets": "10.0.0", + "Microsoft.Extensions.DependencyInjection": "10.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.0", + "Microsoft.Extensions.Diagnostics": "10.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.0", + "Microsoft.Extensions.FileProviders.Physical": "10.0.0", + "Microsoft.Extensions.Hosting.Abstractions": "10.0.0", + "Microsoft.Extensions.Logging": "10.0.0", + "Microsoft.Extensions.Logging.Abstractions": "10.0.0", + "Microsoft.Extensions.Logging.Configuration": "10.0.0", + "Microsoft.Extensions.Logging.Console": "10.0.0", + "Microsoft.Extensions.Logging.Debug": "10.0.0", + "Microsoft.Extensions.Logging.EventLog": "10.0.0", + "Microsoft.Extensions.Logging.EventSource": "10.0.0", + "Microsoft.Extensions.Options": "10.0.0" + } + }, "Microsoft.Extensions.Hosting.Abstractions": { "type": "Transitive", "resolved": "10.0.3", @@ -143,6 +287,67 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.3" } }, + "Microsoft.Extensions.Logging.Configuration": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "j8zcwhS6bYB6FEfaY3nYSgHdpiL2T+/V3xjpHtslVAegyI1JUbB9yAt/BFdvZdsNbY0Udm4xFtvfT/hUwcOOOg==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.0", + "Microsoft.Extensions.Configuration.Binder": "10.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.0", + "Microsoft.Extensions.Logging": "10.0.0", + "Microsoft.Extensions.Logging.Abstractions": "10.0.0", + "Microsoft.Extensions.Options": "10.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "10.0.0" + } + }, + "Microsoft.Extensions.Logging.Console": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "treWetuksp8LVb09fCJ5zNhNJjyDkqzVm83XxcrlWQnAdXznR140UUXo8PyEPBvFlHhjKhFQZEOP3Sk/ByCvEw==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.0", + "Microsoft.Extensions.Logging": "10.0.0", + "Microsoft.Extensions.Logging.Abstractions": "10.0.0", + "Microsoft.Extensions.Logging.Configuration": "10.0.0", + "Microsoft.Extensions.Options": "10.0.0" + } + }, + "Microsoft.Extensions.Logging.Debug": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "A/4vBtVaySLBGj4qluye+KSbeVCCMa6GcTbxf2YgnSDHs9b9105+VojBJ1eJPel8F1ny0JOh+Ci3vgCKn69tNQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.0", + "Microsoft.Extensions.Logging": "10.0.0", + "Microsoft.Extensions.Logging.Abstractions": "10.0.0" + } + }, + "Microsoft.Extensions.Logging.EventLog": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "EWda5nSXhzQZr3yJ3+XgIApOek+Hm+txhWCEzWNVPp/OfimL4qmvctgXu87m+S2RXw/AoUP8aLMNicJ2KWblVA==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.0", + "Microsoft.Extensions.Logging": "10.0.0", + "Microsoft.Extensions.Logging.Abstractions": "10.0.0", + "Microsoft.Extensions.Options": "10.0.0", + "System.Diagnostics.EventLog": "10.0.0" + } + }, + "Microsoft.Extensions.Logging.EventSource": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "+Qc+kgoJi1w2A/Jm+7h04LcK2JoJkwAxKg7kBakkNRcemTmRGocqPa7rVNVGorTYruFrUS25GwkFNtOECnjhXg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.0", + "Microsoft.Extensions.Logging": "10.0.0", + "Microsoft.Extensions.Logging.Abstractions": "10.0.0", + "Microsoft.Extensions.Options": "10.0.0", + "Microsoft.Extensions.Primitives": "10.0.0" + } + }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "10.0.3", @@ -152,6 +357,18 @@ "Microsoft.Extensions.Primitives": "10.0.3" } }, + "Microsoft.Extensions.Options.ConfigurationExtensions": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "tL9cSl3maS5FPzp/3MtlZI21ExWhni0nnUCF8HY4npTsINw45n9SNDbkKXBMtFyUFGSsQep25fHIDN4f/Vp3AQ==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "10.0.0", + "Microsoft.Extensions.Configuration.Binder": "10.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.0", + "Microsoft.Extensions.Options": "10.0.0", + "Microsoft.Extensions.Primitives": "10.0.0" + } + }, "Microsoft.Extensions.Primitives": { "type": "Transitive", "resolved": "10.0.3", @@ -211,15 +428,15 @@ }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", - "resolved": "18.4.0", - "contentHash": "4L6m2kS2pY5uJ9cpeRxzW22opr6ttScIRqsOpMDQpgENp/ZwxkkQCcmc6LRSURo2dFaaSW5KVflQZvroiJ7Wzg==" + "resolved": "18.5.1", + "contentHash": "KNZd+M0S0rz5eNAln0pbZX+A/RbokYZCbGKx4fN4CkhtWhkz6nSJDO+9LGYjRE4d0WPVriJ2JnVubkjt3+PpMg==" }, "Microsoft.TestPlatform.TestHost": { "type": "Transitive", - "resolved": "18.4.0", - "contentHash": "gZsCHI+zOmZCcKZieIL4Jg14qKD2OGZOmX5DehuIk1EA9BN6Crm0+taXQNEuajOH1G9CCyBxw8VWR4t5tumcng==", + "resolved": "18.5.1", + "contentHash": "RM+3JNHEoHOCFXzVntUcIiYxzPjzBN0N8wto6HYXi76YyBTZ/3CeRL8U+Pk5zx3AUrOmHxDvKJwGUCdElU9bJg==", "dependencies": { - "Microsoft.TestPlatform.ObjectModel": "18.4.0", + "Microsoft.TestPlatform.ObjectModel": "18.5.1", "Newtonsoft.Json": "13.0.3" } }, @@ -244,10 +461,15 @@ "System.Memory.Data": "10.0.3" } }, + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "uaFRda9NjtbJRkdx311eXlAA3n2em7223c1A8d1VWyl+4FL9vkG7y2lpPfBU9HYdj/9KgdRNdn1vFK8ZYCYT/A==" + }, "System.IO.Hashing": { "type": "Transitive", - "resolved": "10.0.1", - "contentHash": "Dy6ULPb2S0GmNndjKrEIpfibNsc8+FTOoZnqygtFDuyun8vWboQbfMpQtKUXpgTxokR5E4zFHETpNnGfeWY6NA==" + "resolved": "10.0.3", + "contentHash": "La6ICwsdTKhVX+LKN+pvFjQRR3LhLwq3uKdi2knjLzRyPYBSydF4cjXidYxIiTcDD6XVYdsBWQEI8ZxiZ/OdIg==" }, "System.Memory.Data": { "type": "Transitive", @@ -330,17 +552,17 @@ "type": "Project", "dependencies": { "Azure.Identity": "[1.21.0, )", - "Azure.Security.KeyVault.Secrets": "[4.10.0, )", - "Azure.Storage.Blobs": "[12.27.0, )", + "Azure.Security.KeyVault.Secrets": "[4.11.0, )", + "Azure.Storage.Blobs": "[12.28.0, )", "Microsoft.Extensions.Azure": "[1.14.0, )", - "Skender.Stock.Indicators": "[2.7.1, )" + "Skender.Stock.Indicators": "[3.0.0-preview.3.1, )" } }, "Azure.Core": { "type": "CentralTransitive", "requested": "[1.50.0, )", - "resolved": "1.53.0", - "contentHash": "x9c/toFMOtRrlTdFuE7rlGCVAduQzWVfKmLz5juj41zJAXEhYD5hluiUyyAEzJ6OxpBnKtiaBztzwpZITAVjtg==", + "resolved": "1.54.0", + "contentHash": "m6hHbx1q9+GCBZ5A9ykzFylPdTwscX2APH7PlnqV+yu+DH3RRtuIDJMRqdU17cMyinv0hCPofpegoyQ6qWPW7g==", "dependencies": { "Microsoft.Bcl.AsyncInterfaces": "10.0.3", "Microsoft.Extensions.Configuration.Abstractions": "10.0.3", @@ -362,21 +584,21 @@ }, "Azure.Security.KeyVault.Secrets": { "type": "CentralTransitive", - "requested": "[4.10.0, )", - "resolved": "4.10.0", - "contentHash": "lcJtcgTkk1gGy59RQhGLJLMyad+zgASMn975PVjMft69q+jjFTo6Nyq5SCtOhPY1WvA0gNI1qYIVN2oikVXDjw==", + "requested": "[4.11.0, )", + "resolved": "4.11.0", + "contentHash": "tjpVczILiXTR9bEynSL1JBU80169hGnTECtGsFjnRz9E1xoIhfUsaUTnB79k995zDkOG61hOI+YBtf5bNqgRIQ==", "dependencies": { - "Azure.Core": "1.53.0" + "Azure.Core": "1.54.0" } }, "Azure.Storage.Blobs": { "type": "CentralTransitive", - "requested": "[12.27.0, )", - "resolved": "12.27.0", - "contentHash": "zI5rg1tTtnA8T2g2/21l+1iIUdDjpEQQ0FI1BabJVEQJ1JUyTQKrc41eNabAHs0SBHprl6pu/6OqIMK9Ve+4tQ==", + "requested": "[12.28.0, )", + "resolved": "12.28.0", + "contentHash": "OK6slT3Hq3Yp2HWA0e23YHheHzKNbYjBZOwdT4fQ1iMH6I/8e6X8kAJLuKqVUeFBy160QSwhsynA3HxhVSHEcg==", "dependencies": { - "Azure.Core": "1.50.0", - "Azure.Storage.Common": "12.26.0" + "Azure.Core": "1.51.1", + "Azure.Storage.Common": "12.27.0" } }, "Microsoft.Extensions.Azure": { @@ -392,9 +614,9 @@ }, "Skender.Stock.Indicators": { "type": "CentralTransitive", - "requested": "[2.7.1, )", - "resolved": "2.7.1", - "contentHash": "HsHVlg9Tcb1gUV50dpazlUh2Qy1F9NtG7Fe4pYcxgnnloW4Fdh8TQTA7IB5M7rWubEvtFgzx+1U1vI2LzJPWXg==" + "requested": "[3.0.0-preview.3.1, )", + "resolved": "3.0.0-preview.3.1", + "contentHash": "oBzrKgtwRRGfJyotPufP1tpNUnNeUgyiv58aY9E/Z4qaKfLL0pOqPUtcS9/5z/mnmhtyRCe/BKPkRKTD4kHUKw==" } } } diff --git a/server/WebApi/Endpoints.cs b/server/WebApi/Endpoints.cs index 8f21de44..d1b299e2 100644 --- a/server/WebApi/Endpoints.cs +++ b/server/WebApi/Endpoints.cs @@ -19,7 +19,7 @@ public string Get() [HttpGet("quotes")] public async Task + + GetQuotes() { - IEnumerable quotes = await quoteFeed.Get(); + IEnumerablequotes = await quoteFeed.Get(HttpContext.RequestAborted); return Ok(quotes.TakeLast(limitLast)); } @@ -33,11 +33,11 @@ public IActionResult GetIndicatorCatalog() return Ok(Metadata.IndicatorListing($"{Request.Scheme}://{Request.Host}")); } - private async TaskGet (Func , IEnumerable > indicatorFunc) + private async Task Get (Func , IEnumerable > indicatorFunc) { try { - IEnumerable quotes = await quoteFeed.Get(); + IReadOnlyListquotes = (await quoteFeed.Get(HttpContext.RequestAborted)).ToList(); IEnumerableresults = indicatorFunc(quotes).TakeLast(limitLast); return Ok(results); } @@ -51,53 +51,53 @@ private async Task Get (Func , IEnumerable // INDICATORS (sorted alphabetically) [HttpGet("ADL")] - public Task GetAdl(int smaPeriods) - => Get(quotes => quotes.GetAdl(smaPeriods)); + public Task GetAdl() + => Get(quotes => quotes.ToAdl()); [HttpGet("ADX")] public Task GetAdx(int lookbackPeriods) - => Get(quotes => quotes.GetAdx(lookbackPeriods)); + => Get(quotes => quotes.ToAdx(lookbackPeriods)); [HttpGet("ALLIGATOR")] public Task GetAlligator(int jawPeriods, int jawOffset, int teethPeriods, int teethOffset, int lipsPeriods, int lipsOffset) - => Get(quotes => quotes.GetAlligator(jawPeriods, jawOffset, teethPeriods, teethOffset, lipsPeriods, lipsOffset)); + => Get(quotes => quotes.ToAlligator(jawPeriods, jawOffset, teethPeriods, teethOffset, lipsPeriods, lipsOffset)); [HttpGet("ALMA")] public Task GetAlma(int lookbackPeriods, double offset, double sigma) - => Get(quotes => quotes.GetAlma(lookbackPeriods, offset, sigma)); + => Get(quotes => quotes.ToAlma(lookbackPeriods, offset, sigma)); [HttpGet("AROON")] public Task GetAroon(int lookbackPeriods) - => Get(quotes => quotes.GetAroon(lookbackPeriods)); + => Get(quotes => quotes.ToAroon(lookbackPeriods)); [HttpGet("ATR")] public Task GetAtr(int lookbackPeriods) - => Get(quotes => quotes.GetAtr(lookbackPeriods)); + => Get(quotes => quotes.ToAtr(lookbackPeriods)); [HttpGet("ATR-STOP-CLOSE")] public Task GetAtrStopClose(int lookbackPeriods, double multiplier) - => Get(quotes => quotes.GetAtrStop(lookbackPeriods, multiplier, EndType.Close)); + => Get(quotes => quotes.ToAtrStop(lookbackPeriods, multiplier, EndType.Close)); [HttpGet("ATR-STOP-HL")] public Task GetAtrStopHL(int lookbackPeriods, double multiplier) - => Get(quotes => quotes.GetAtrStop(lookbackPeriods, multiplier, EndType.HighLow)); + => Get(quotes => quotes.ToAtrStop(lookbackPeriods, multiplier, EndType.HighLow)); [HttpGet("AWESOME")] public Task GetAwesome(int fastPeriods, int slowPeriods) - => Get(quotes => quotes.GetAwesome(fastPeriods, slowPeriods)); + => Get(quotes => quotes.ToAwesome(fastPeriods, slowPeriods)); [HttpGet("BB")] public Task GetBollingerBands(int lookbackPeriods, double standardDeviations) - => Get(quotes => quotes.GetBollingerBands(lookbackPeriods, standardDeviations)); + => Get(quotes => quotes.ToBollingerBands(lookbackPeriods, standardDeviations)); [HttpGet("BETA")] public async Task GetBeta(int lookbackPeriods, BetaType type) { try { - IEnumerable quotes = await quoteFeed.Get(); - IEnumerablemarket = await quoteFeed.Get("SPY"); - IEnumerableresults = quotes.GetBeta(market, lookbackPeriods, type).TakeLast(limitLast); + IReadOnlyList quotes = (await quoteFeed.Get(HttpContext.RequestAborted)).ToList(); + IReadOnlyListmarket = (await quoteFeed.Get("SPY", HttpContext.RequestAborted)).ToList(); + IEnumerableresults = quotes.ToBeta(market, lookbackPeriods, type).TakeLast(limitLast); return Ok(results); } catch (ArgumentOutOfRangeException rex) @@ -108,265 +108,265 @@ public async Task GetBeta(int lookbackPeriods, BetaType type) [HttpGet("BOP")] public Task GetBop(int smoothPeriods) - => Get(quotes => quotes.GetBop(smoothPeriods)); + => Get(quotes => quotes.ToBop(smoothPeriods)); [HttpGet("CCI")] public Task GetCci(int lookbackPeriods) - => Get(quotes => quotes.GetCci(lookbackPeriods)); + => Get(quotes => quotes.ToCci(lookbackPeriods)); [HttpGet("CHAIKIN")] public Task GetChaikinOsc(int fastPeriods, int slowPeriods) - => Get(quotes => quotes.GetChaikinOsc(fastPeriods, slowPeriods)); + => Get(quotes => quotes.ToChaikinOsc(fastPeriods, slowPeriods)); [HttpGet("CHEXIT-LONG")] public Task GetChandelierLong(int lookbackPeriods, double multiplier) - => Get(quotes => quotes.GetChandelier(lookbackPeriods, multiplier, ChandelierType.Long)); + => Get(quotes => quotes.ToChandelier(lookbackPeriods, multiplier, Direction.Long)); [HttpGet("CHEXIT-SHORT")] public Task GetChandelierShort(int lookbackPeriods, double multiplier) - => Get(quotes => quotes.GetChandelier(lookbackPeriods, multiplier, ChandelierType.Short)); + => Get(quotes => quotes.ToChandelier(lookbackPeriods, multiplier, Direction.Short)); [HttpGet("CHOP")] public Task GetChop(int lookbackPeriods) - => Get(quotes => quotes.GetChop(lookbackPeriods)); + => Get(quotes => quotes.ToChop(lookbackPeriods)); [HttpGet("CMF")] public Task GetCmf(int lookbackPeriods) - => Get(quotes => quotes.GetCmf(lookbackPeriods)); + => Get(quotes => quotes.ToCmf(lookbackPeriods)); [HttpGet("CMO")] public Task GetCmo(int lookbackPeriods) - => Get(quotes => quotes.GetCmo(lookbackPeriods)); + => Get(quotes => quotes.ToCmo(lookbackPeriods)); [HttpGet("CRSI")] public Task GetConnorsRsi(int rsiPeriods, int streakPeriods, int rankPeriods) - => Get(quotes => quotes.GetConnorsRsi(rsiPeriods, streakPeriods, rankPeriods)); + => Get(quotes => quotes.ToConnorsRsi(rsiPeriods, streakPeriods, rankPeriods)); [HttpGet("DEMA")] public Task GetDema(int lookbackPeriods) - => Get(quotes => quotes.GetDema(lookbackPeriods)); + => Get(quotes => quotes.ToDema(lookbackPeriods)); [HttpGet("DOJI")] public Task GetDoji(double maxPriceChangePercent) - => Get(quotes => quotes.GetDoji(maxPriceChangePercent)); + => Get(quotes => quotes.ToDoji(maxPriceChangePercent)); [HttpGet("DONCHIAN")] public Task GetDonchian(int lookbackPeriods) - => Get(quotes => quotes.GetDonchian(lookbackPeriods)); + => Get(quotes => quotes.ToDonchian(lookbackPeriods)); [HttpGet("DPO")] public Task GetDpo(int lookbackPeriods) - => Get(quotes => quotes.GetDpo(lookbackPeriods)); + => Get(quotes => quotes.ToDpo(lookbackPeriods)); [HttpGet("DYN")] public Task GetDynamic(int lookbackPeriods) - => Get(quotes => quotes.GetDynamic(lookbackPeriods)); + => Get(quotes => quotes.ToDynamic(lookbackPeriods)); [HttpGet("ELDER-RAY")] public Task GetElderRay(int lookbackPeriods) - => Get(quotes => quotes.GetElderRay(lookbackPeriods)); + => Get(quotes => quotes.ToElderRay(lookbackPeriods)); [HttpGet("EMA")] public Task GetEma(int lookbackPeriods) - => Get(quotes => quotes.GetEma(lookbackPeriods)); + => Get(quotes => quotes.ToEma(lookbackPeriods)); [HttpGet("EPMA")] public Task GetEpma(int lookbackPeriods) - => Get(quotes => quotes.GetEpma(lookbackPeriods)); + => Get(quotes => quotes.ToEpma(lookbackPeriods)); [HttpGet("FCB")] public Task GetFcb(int windowSpan) - => Get(quotes => quotes.GetFcb(windowSpan)); + => Get(quotes => quotes.ToFcb(windowSpan)); [HttpGet("FISHER")] public Task GetFisher(int lookbackPeriods) - => Get(quotes => quotes.GetFisherTransform(lookbackPeriods)); + => Get(quotes => quotes.ToFisherTransform(lookbackPeriods)); [HttpGet("FORCE")] public Task GetForceIndex(int lookbackPeriods) - => Get(quotes => quotes.GetForceIndex(lookbackPeriods)); + => Get(quotes => quotes.ToForceIndex(lookbackPeriods)); [HttpGet("FRACTAL")] public Task GetFractal(int windowSpan) - => Get(quotes => quotes.GetFractal(windowSpan)); + => Get(quotes => quotes.ToFractal(windowSpan)); [HttpGet("GATOR")] public Task GetGator() - => Get(quotes => quotes.GetGator()); + => Get(quotes => quotes.ToGator()); [HttpGet("HMA")] public Task GetHma(int lookbackPeriods) - => Get(quotes => quotes.GetHma(lookbackPeriods)); + => Get(quotes => quotes.ToHma(lookbackPeriods)); [HttpGet("HTL")] public Task GetHTL() - => Get(quotes => quotes.GetHtTrendline()); + => Get(quotes => quotes.ToHtTrendline()); [HttpGet("HURST")] public Task GetHurst(int lookbackPeriods) - => Get(quotes => quotes.GetHurst(lookbackPeriods)); + => Get(quotes => quotes.ToHurst(lookbackPeriods)); [HttpGet("ICHIMOKU")] public Task GetIchimoku(int tenkanPeriods, int kijunPeriods, int senkouBPeriods) - => Get(quotes => quotes.GetIchimoku(tenkanPeriods, kijunPeriods, senkouBPeriods)); + => Get(quotes => quotes.ToIchimoku(tenkanPeriods, kijunPeriods, senkouBPeriods)); [HttpGet("KAMA")] public Task GetKama(int erPeriods, int fastPeriods, int slowPeriods) - => Get(quotes => quotes.GetKama(erPeriods, fastPeriods, slowPeriods)); + => Get(quotes => quotes.ToKama(erPeriods, fastPeriods, slowPeriods)); [HttpGet("KELTNER")] public Task GetKeltner(int emaPeriods, double multiplier, int atrPeriods) - => Get(quotes => quotes.GetKeltner(emaPeriods, multiplier, atrPeriods)); + => Get(quotes => quotes.ToList().ToKeltner(emaPeriods, multiplier, atrPeriods)); [HttpGet("KVO")] public Task GetKvo(int fastPeriods, int slowPeriods, int signalPeriods) - => Get(quotes => quotes.GetKvo(fastPeriods, slowPeriods, signalPeriods)); + => Get(quotes => quotes.ToKvo(fastPeriods, slowPeriods, signalPeriods)); [HttpGet("MA-ENV")] public Task GetMaEnvelopes(int lookbackPeriods, double percentOffset) - => Get(quotes => quotes.GetMaEnvelopes(lookbackPeriods, percentOffset)); + => Get(quotes => quotes.ToMaEnvelopes(lookbackPeriods, percentOffset)); [HttpGet("MACD")] public Task GetMacd(int fastPeriods, int slowPeriods, int signalPeriods) - => Get(quotes => quotes.GetMacd(fastPeriods, slowPeriods, signalPeriods)); + => Get(quotes => quotes.ToMacd(fastPeriods, slowPeriods, signalPeriods)); [HttpGet("MAMA")] public Task GetMama(double fastLimit, double slowLimit) - => Get(quotes => quotes.GetMama(fastLimit, slowLimit)); + => Get(quotes => quotes.ToMama(fastLimit, slowLimit)); [HttpGet("MARUBOZU")] public Task GetMarubozu(double minBodyPercent) - => Get(quotes => quotes.GetMarubozu(minBodyPercent)); + => Get(quotes => quotes.ToMarubozu(minBodyPercent)); [HttpGet("MFI")] public Task GetMfi(int lookbackPeriods) - => Get(quotes => quotes.GetMfi(lookbackPeriods)); + => Get(quotes => quotes.ToMfi(lookbackPeriods)); [HttpGet("OBV")] - public Task GetObv(int smaPeriods) - => Get(quotes => quotes.GetObv(smaPeriods == 0 ? null : smaPeriods)); + public Task GetObv() + => Get(quotes => quotes.ToObv()); [HttpGet("PMO")] public Task GetPmo(int timePeriods, int smoothPeriods, int signalPeriods) - => Get(quotes => quotes.GetPmo(timePeriods, smoothPeriods, signalPeriods)); + => Get(quotes => quotes.ToPmo(timePeriods, smoothPeriods, signalPeriods)); [HttpGet("PSAR")] public Task GetParabolicSar(double accelerationStep, double maxAccelerationFactor) - => Get(quotes => quotes.GetParabolicSar(accelerationStep, maxAccelerationFactor)); + => Get(quotes => quotes.ToParabolicSar(accelerationStep, maxAccelerationFactor)); [HttpGet("PVO")] public Task GetPvo(int fastPeriods, int slowPeriods, int signalPeriods) - => Get(quotes => quotes.GetPvo(fastPeriods, slowPeriods, signalPeriods)); + => Get(quotes => quotes.ToPvo(fastPeriods, slowPeriods, signalPeriods)); [HttpGet("ROC")] - public Task GetRoc(int lookbackPeriods, int smaPeriods) - => Get(quotes => quotes.GetRoc(lookbackPeriods, smaPeriods)); + public Task GetRoc(int lookbackPeriods) + => Get(quotes => quotes.ToRoc(lookbackPeriods)); [HttpGet("ROCWB")] public Task GetRocWb(int lookbackPeriods, int emaPeriods, int stdDevPeriods) - => Get(quotes => quotes.GetRocWb(lookbackPeriods, emaPeriods, stdDevPeriods)); + => Get(quotes => quotes.ToRocWb(lookbackPeriods, emaPeriods, stdDevPeriods)); [HttpGet("RSI")] public Task GetRsi(int lookbackPeriods) - => Get(quotes => quotes.GetRsi(lookbackPeriods)); + => Get(quotes => quotes.ToRsi(lookbackPeriods)); [HttpGet("SLOPE")] public Task GetSlope(int lookbackPeriods) - => Get(quotes => quotes.GetSlope(lookbackPeriods)); + => Get(quotes => quotes.ToSlope(lookbackPeriods)); [HttpGet("SMA")] public Task GetSma(int lookbackPeriods) - => Get(quotes => quotes.GetSma(lookbackPeriods)); + => Get(quotes => quotes.ToSma(lookbackPeriods)); [HttpGet("SMI")] public Task GetSmi(int lookbackPeriods, int firstSmoothPeriods, int secondSmoothPeriods, int signalPeriods) - => Get(quotes => quotes.GetSmi(lookbackPeriods, firstSmoothPeriods, secondSmoothPeriods, signalPeriods)); + => Get(quotes => quotes.ToSmi(lookbackPeriods, firstSmoothPeriods, secondSmoothPeriods, signalPeriods)); [HttpGet("SMMA")] public Task GetSmma(int lookbackPeriods) - => Get(quotes => quotes.GetSmma(lookbackPeriods)); + => Get(quotes => quotes.ToSmma(lookbackPeriods)); [HttpGet("STARC")] public Task GetStarc(int smaPeriods, double multiplier, int atrPeriods) - => Get(quotes => quotes.GetStarcBands(smaPeriods, multiplier, atrPeriods)); + => Get(quotes => quotes.ToStarcBands(smaPeriods, multiplier, atrPeriods)); [HttpGet("STC")] public Task GetStc(int cyclePeriods, int fastPeriods, int slowPeriods) - => Get(quotes => quotes.GetStc(cyclePeriods, fastPeriods, slowPeriods)); + => Get(quotes => quotes.ToStc(cyclePeriods, fastPeriods, slowPeriods)); [HttpGet("STDEV")] - public Task GetStdDev(int lookbackPeriods, int smaPeriods) - => Get(quotes => quotes.GetStdDev(lookbackPeriods, smaPeriods == 0 ? 1 : smaPeriods)); + public Task GetStdDev(int lookbackPeriods) + => Get(quotes => quotes.ToStdDev(lookbackPeriods)); [HttpGet("STDEV-CH")] public Task GetStdDevChannels(int lookbackPeriods, double standardDeviations) - => Get(quotes => quotes.GetStdDevChannels(lookbackPeriods, standardDeviations)); + => Get(quotes => quotes.ToStdDevChannels(lookbackPeriods, standardDeviations)); [HttpGet("STO")] public Task GetStoch(int lookbackPeriods, int signalPeriods) - => Get(quotes => quotes.GetStoch(lookbackPeriods, signalPeriods)); + => Get(quotes => quotes.ToStoch(lookbackPeriods, signalPeriods)); [HttpGet("STORSI")] public Task GetStochRsi(int rsiPeriods, int stochPeriods, int signalPeriods, int smoothPeriods) - => Get(quotes => quotes.GetStochRsi(rsiPeriods, stochPeriods, signalPeriods, smoothPeriods)); + => Get(quotes => quotes.ToStochRsi(rsiPeriods, stochPeriods, signalPeriods, smoothPeriods)); [HttpGet("SUPERTREND")] public Task GetSuperTrend(int lookbackPeriods, double multiplier) - => Get(quotes => quotes.GetSuperTrend(lookbackPeriods, multiplier)); + => Get(quotes => quotes.ToSuperTrend(lookbackPeriods, multiplier)); [HttpGet("T3")] public Task GetT3(int lookbackPeriods, double volumeFactor) - => Get(quotes => quotes.GetT3(lookbackPeriods, volumeFactor)); + => Get(quotes => quotes.ToT3(lookbackPeriods, volumeFactor)); [HttpGet("TEMA")] public Task GetTema(int lookbackPeriods) - => Get(quotes => quotes.GetTema(lookbackPeriods)); + => Get(quotes => quotes.ToTema(lookbackPeriods)); + + [HttpGet("TR")] + public Task GetTr() + => Get(quotes => quotes.ToTr()); [HttpGet("TRIX")] - public Task GetTrix(int lookbackPeriods, int signalPeriods) - => Get(quotes => quotes.GetTrix(lookbackPeriods, signalPeriods == 0 ? null : signalPeriods)); + public Task GetTrix(int lookbackPeriods) + => Get(quotes => quotes.ToTrix(lookbackPeriods)); [HttpGet("TSI")] public Task GetTsi(int lookbackPeriods, int smoothPeriods, int signalPeriods) - => Get(quotes => quotes.GetTsi(lookbackPeriods, smoothPeriods, signalPeriods)); + => Get(quotes => quotes.ToTsi(lookbackPeriods, smoothPeriods, signalPeriods)); [HttpGet("ULCER")] public Task GetUlcer(int lookbackPeriods) - => Get(quotes => quotes.GetUlcerIndex(lookbackPeriods)); + => Get(quotes => quotes.ToUlcerIndex(lookbackPeriods)); [HttpGet("ULTIMATE")] public Task GetUltimate(int shortPeriods, int middlePeriods, int longPeriods) - => Get(quotes => quotes.GetUltimate(shortPeriods, middlePeriods, longPeriods)); + => Get(quotes => quotes.ToUltimate(shortPeriods, middlePeriods, longPeriods)); [HttpGet("VOL-STOP")] public Task GetVolatilityStop(int lookbackPeriods, double multiplier) - => Get(quotes => quotes.GetVolatilityStop(lookbackPeriods, multiplier)); + => Get(quotes => quotes.ToVolatilityStop(lookbackPeriods, multiplier)); [HttpGet("VORTEX")] public Task GetVortex(int lookbackPeriods) - => Get(quotes => quotes.GetVortex(lookbackPeriods)); - - [HttpGet("VWAP")] - public Task GetVwap() - => Get(quotes => quotes.GetVwap()); + => Get(quotes => quotes.ToVortex(lookbackPeriods)); [HttpGet("VWMA")] public Task GetVwma(int lookbackPeriods) - => Get(quotes => quotes.GetVwma(lookbackPeriods)); + => Get(quotes => quotes.ToVwma(lookbackPeriods)); [HttpGet("WILLIAMSR")] public Task GetWilliamsR(int lookbackPeriods) - => Get(quotes => quotes.GetWilliamsR(lookbackPeriods)); + => Get(quotes => quotes.ToWilliamsR(lookbackPeriods)); [HttpGet("WMA")] public Task GetWma(int lookbackPeriods) - => Get(quotes => quotes.GetWma(lookbackPeriods)); + => Get(quotes => quotes.ToWma(lookbackPeriods)); [HttpGet("ZIGZAG-CLOSE")] public Task GetZigZagClose(decimal percentChange) - => Get(quotes => quotes.GetZigZag(EndType.Close, percentChange)); + => Get(quotes => quotes.ToZigZag(EndType.Close, percentChange)); [HttpGet("ZIGZAG-HIGHLOW")] public Task GetZigZagHighLow(decimal percentChange) - => Get(quotes => quotes.GetZigZag(EndType.HighLow, percentChange)); + => Get(quotes => quotes.ToZigZag(EndType.HighLow, percentChange)); } diff --git a/server/WebApi/GlobalUsings.cs b/server/WebApi/GlobalUsings.cs index 62b9dfa3..122491c8 100644 --- a/server/WebApi/GlobalUsings.cs +++ b/server/WebApi/GlobalUsings.cs @@ -4,3 +4,4 @@ global using Azure.Storage.Blobs.Models; global using Skender.Stock.Indicators; global using WebApi.Models; +global using IndicatorListing = WebApi.Models.IndicatorListing; diff --git a/server/WebApi/Models/IndicatorListing.cs b/server/WebApi/Models/IndicatorListing.cs index 9a004818..a19199c2 100644 --- a/server/WebApi/Models/IndicatorListing.cs +++ b/server/WebApi/Models/IndicatorListing.cs @@ -13,6 +13,6 @@ public record IndicatorListing public ChartConfig? ChartConfig { get; set; } - public ICollection ? Parameters { get; set; } + public ICollection Parameters { get; set; } = []; public required ICollection Results { get; init; } } diff --git a/server/WebApi/Program.cs b/server/WebApi/Program.cs index 50ed7a5e..7b9450c4 100644 --- a/server/WebApi/Program.cs +++ b/server/WebApi/Program.cs @@ -13,10 +13,15 @@ services.AddControllers(); // Get CORS origins from appsettings (semicolon-separated list) -// reminder: production origins defined in cloud host settings Β» API Β» CORS -// so these are really only for localhost / development +// reminder: Website origins for production are in cloud host settings Β» API Β» CORS +// Demo origins supplement Website (CF Pages VitePress demo; not overridden by cloud host settings) string? allowedOriginConfig = configuration.GetValue ("CorsOrigins:Website"); -string[] allowedOrigins = allowedOriginConfig?.Split(';', StringSplitOptions.RemoveEmptyEntries) ?? []; +string[] websiteOrigins = allowedOriginConfig?.Split(';', StringSplitOptions.RemoveEmptyEntries) ?? []; + +string? demoOriginConfig = configuration.GetValue ("CorsOrigins:Demo"); +string[] demoOrigins = demoOriginConfig?.Split(';', StringSplitOptions.RemoveEmptyEntries) ?? []; + +string[] allowedOrigins = [.. websiteOrigins, .. demoOrigins]; if (allowedOrigins.Length > 0) { diff --git a/server/WebApi/Services/Service.Metadata.cs b/server/WebApi/Services/Service.Metadata.cs index 1bccd0ea..69c3fa11 100644 --- a/server/WebApi/Services/Service.Metadata.cs +++ b/server/WebApi/Services/Service.Metadata.cs @@ -9,20 +9,10 @@ public static IEnumerable IndicatorListing(string baseUrl) new() { Name = "Accumulation Distribution Line (ADL)", Uiid = "ADL", - LegendTemplate = "ADL w/ SMA([P1])", + LegendTemplate = "ADL", Endpoint = $"{baseUrl}/ADL/", Category = "volume-based", ChartType = "oscillator", - Parameters = [ - new() { - DisplayName = "SMA Periods", - ParamName = "smaPeriods", - DataType = "int", - DefaultValue = 3, - Minimum = 1, - Maximum = 50 - } - ], Results = [ new() { DisplayName = "ADL", @@ -31,14 +21,6 @@ public static IEnumerable IndicatorListing(string baseUrl) DataType = "number", LineType = "solid", DefaultColor = ChartColors.StandardBlue - }, - new() { - DisplayName = "SMA of ADL", - TooltipTemplate = "ADL SMA([P1])", - DataName = "adlSma", - DataType = "number", - LineType = "solid", - DefaultColor = ChartColors.StandardRed } ] }, @@ -1659,7 +1641,7 @@ public static IEnumerable IndicatorListing(string baseUrl) new IndicatorListing { Name = "Rate of Change", Uiid = "ROC", - LegendTemplate = "ROC([P1],[P2])", + LegendTemplate = "ROC([P1])", Endpoint = $"{baseUrl}/ROC/", Category = "oscillator", ChartType = "oscillator", @@ -1672,32 +1654,16 @@ public static IEnumerable IndicatorListing(string baseUrl) DefaultValue = 14, Minimum = 1, Maximum = 250 - }, - new() { - DisplayName = "SMA Periods", - ParamName = "smaPeriods", - DataType = "int", - DefaultValue = 3, - Minimum = 1, - Maximum = 50 } ], Results = [ new() { DisplayName = "Rate of Change", - TooltipTemplate = "ROC([P1],[P2])", + TooltipTemplate = "ROC([P1])", DataName = "roc", DataType = "number", LineType = "solid", DefaultColor = ChartColors.StandardBlue - }, - new() { - DisplayName = "SMA of ROC", - TooltipTemplate = "STO %D([P2])", - DataName = "rocSma", - DataType = "number", - LineType = "solid", - DefaultColor = ChartColors.StandardRed } ] }, @@ -1946,14 +1912,6 @@ public static IEnumerable IndicatorListing(string baseUrl) DefaultValue = 14, Minimum = 1, Maximum = 250 - }, - new() { - DisplayName = "SMA Periods", - ParamName = "smaPeriods", - DataType = "int", - DefaultValue = 3, - Minimum = 1, - Maximum = 50 } ], Results = [ @@ -1964,14 +1922,6 @@ public static IEnumerable IndicatorListing(string baseUrl) DataType = "number", LineType = "solid", DefaultColor = ChartColors.StandardBlue - }, - new() { - DisplayName = "SMA of Standard Deviation", - TooltipTemplate = "STDEV([P1]) SMA", - DataName = "stdDevSma", - DataType = "number", - LineType = "solid", - DefaultColor = ChartColors.StandardRed } ] }, @@ -2936,20 +2886,10 @@ public static IEnumerable IndicatorListing(string baseUrl) new IndicatorListing { Name = "On-Balance Volume (OBV)", Uiid = "OBV", - LegendTemplate = "OBV w/ SMA([P1])", + LegendTemplate = "OBV", Endpoint = $"{baseUrl}/OBV/", Category = "volume-based", ChartType = "oscillator", - Parameters = [ - new() { - DisplayName = "SMA Periods", - ParamName = "smaPeriods", - DataType = "int", - DefaultValue = 20, - Minimum = 0, - Maximum = 250 - } - ], Results = [ new() { DisplayName = "OBV", @@ -2958,14 +2898,6 @@ public static IEnumerable IndicatorListing(string baseUrl) DataType = "number", LineType = "solid", DefaultColor = ChartColors.StandardBlue - }, - new() { - DisplayName = "SMA of OBV", - TooltipTemplate = "OBV SMA([P1])", - DataName = "obvSma", - DataType = "number", - LineType = "solid", - DefaultColor = ChartColors.StandardRed } ] }, @@ -3136,11 +3068,31 @@ public static IEnumerable IndicatorListing(string baseUrl) ] }, + // True Range + new IndicatorListing { + Name = "True Range", + Uiid = "TR", + LegendTemplate = "TR", + Endpoint = $"{baseUrl}/TR/", + Category = "price-characteristic", + ChartType = "oscillator", + Results = [ + new() { + DisplayName = "True Range", + TooltipTemplate = "TR", + DataName = "tr", + DataType = "number", + LineType = "solid", + DefaultColor = ChartColors.StandardBlue + } + ] + }, + // TRIX Oscillator new IndicatorListing { Name = "TRIX Oscillator", Uiid = "TRIX", - LegendTemplate = "TRIX([P1],[P2])", + LegendTemplate = "TRIX([P1])", Endpoint = $"{baseUrl}/TRIX/", Category = "oscillator", ChartType = "oscillator", @@ -3163,32 +3115,16 @@ public static IEnumerable IndicatorListing(string baseUrl) DefaultValue = 14, Minimum = 1, Maximum = 250 - }, - new() { - DisplayName = "Signal Periods", - ParamName = "signalPeriods", - DataType = "int", - DefaultValue = 9, - Minimum = 0, - Maximum = 50 } ], Results = [ new() { DisplayName = "TRIX", - TooltipTemplate = "TRIX([P1],[P2])", + TooltipTemplate = "TRIX([P1])", DataName = "trix", DataType = "number", LineType = "solid", DefaultColor = ChartColors.StandardBlue - }, - new() { - DisplayName = "Signal", - TooltipTemplate = "TRIX Signal", - DataName = "signal", - DataType = "number", - LineType = "solid", - DefaultColor = ChartColors.StandardRed } ] }, @@ -3751,26 +3687,6 @@ public static IEnumerable IndicatorListing(string baseUrl) ] }, - // Volume Weighted Average Price (VWAP) - new IndicatorListing { - Name = "Volume Weighted Average Price (VWAP)", - Uiid = "VWAP", - LegendTemplate = "VWAP", - Endpoint = $"{baseUrl}/VWAP/", - Category = "moving-average", - ChartType = "overlay", - Results = [ - new() { - DisplayName = "VWAP", - TooltipTemplate = "VWAP", - DataName = "vwap", - DataType = "number", - LineType = "solid", - DefaultColor = ChartColors.StandardBlue - } - ] - }, - // Volume Weighted Moving Average (VWMA) new IndicatorListing { Name = "Volume Weighted Moving Average (VWMA)", diff --git a/server/WebApi/Services/Service.Quotes.Failover.cs b/server/WebApi/Services/Service.Quotes.Failover.cs index ef89efbf..69530d6d 100644 --- a/server/WebApi/Services/Service.Quotes.Failover.cs +++ b/server/WebApi/Services/Service.Quotes.Failover.cs @@ -3,513 +3,513 @@ namespace WebApi.Services; // Contains large static backup quote dataset used for failover (kept separate for readability) internal static class QuoteBackup { - internal static readonly IReadOnlyList BackupQuotes = GetBackup().OrderBy(x => x.Date).ToList(); + internal static readonly IReadOnlyListBackupQuotes = GetBackup().OrderBy(x => x.Timestamp).ToList(); private static ListGetBackup() => [ - new() { Date = DateTime.Parse("2018-12-31"), Open = 244.92m, High = 245.54m, Low = 242.87m, Close = 245.28m, Volume = 147031456 }, - new() { Date = DateTime.Parse("2018-12-28"), Open = 244.94m, High = 246.73m, Low = 241.87m, Close = 243.15m, Volume = 155998912 }, - new() { Date = DateTime.Parse("2018-12-27"), Open = 238.06m, High = 243.68m, Low = 234.52m, Close = 243.46m, Volume = 189794032 }, - new() { Date = DateTime.Parse("2018-12-26"), Open = 231.59m, High = 241.61m, Low = 229.42m, Close = 241.61m, Volume = 222622048 }, - new() { Date = DateTime.Parse("2018-12-24"), Open = 234.60m, High = 236.36m, Low = 229.92m, Close = 229.99m, Volume = 150100704 }, - new() { Date = DateTime.Parse("2018-12-21"), Open = 242.16m, High = 245.07m, Low = 235.52m, Close = 236.23m, Volume = 260180208 }, - new() { Date = DateTime.Parse("2018-12-20"), Open = 243.79m, High = 245.51m, Low = 238.71m, Close = 241.17m, Volume = 258325808 }, - new() { Date = DateTime.Parse("2018-12-19"), Open = 248.97m, High = 253.10m, Low = 243.30m, Close = 245.16m, Volume = 220342928 }, - new() { Date = DateTime.Parse("2018-12-18"), Open = 250.95m, High = 251.69m, Low = 247.13m, Close = 248.89m, Volume = 137862544 }, - new() { Date = DateTime.Parse("2018-12-17"), Open = 253.10m, High = 254.32m, Low = 247.37m, Close = 249.16m, Volume = 169610592 }, - new() { Date = DateTime.Parse("2018-12-14"), Open = 256.58m, High = 257.62m, Low = 253.54m, Close = 254.15m, Volume = 119871688 }, - new() { Date = DateTime.Parse("2018-12-13"), Open = 260.05m, High = 260.99m, Low = 257.71m, Close = 258.93m, Volume = 99068200 }, - new() { Date = DateTime.Parse("2018-12-12"), Open = 260.98m, High = 262.47m, Low = 258.93m, Close = 259.01m, Volume = 100414888 }, - new() { Date = DateTime.Parse("2018-12-11"), Open = 261.16m, High = 261.37m, Low = 256.11m, Close = 257.72m, Volume = 124528112 }, - new() { Date = DateTime.Parse("2018-12-10"), Open = 256.98m, High = 258.72m, Low = 252.34m, Close = 257.66m, Volume = 155214672 }, - new() { Date = DateTime.Parse("2018-12-07"), Open = 262.92m, High = 264.63m, Low = 256.25m, Close = 257.17m, Volume = 165025936 }, - new() { Date = DateTime.Parse("2018-12-06"), Open = 259.46m, High = 263.41m, Low = 256.07m, Close = 263.29m, Volume = 209266640 }, - new() { Date = DateTime.Parse("2018-12-04"), Open = 271.61m, High = 272.08m, Low = 263.35m, Close = 263.69m, Volume = 182415248 }, - new() { Date = DateTime.Parse("2018-12-03"), Open = 273.47m, High = 273.59m, Low = 270.77m, Close = 272.52m, Volume = 105581352 }, - new() { Date = DateTime.Parse("2018-11-30"), Open = 267.16m, High = 269.57m, Low = 266.81m, Close = 268.96m, Volume = 100648032 }, - new() { Date = DateTime.Parse("2018-11-29"), Open = 267.06m, High = 268.86m, Low = 265.82m, Close = 267.33m, Volume = 84395640 }, - new() { Date = DateTime.Parse("2018-11-28"), Open = 263.05m, High = 267.91m, Low = 261.81m, Close = 267.91m, Volume = 130805744 }, - new() { Date = DateTime.Parse("2018-11-27"), Open = 259.87m, High = 261.88m, Low = 259.21m, Close = 261.88m, Volume = 77381344 }, - new() { Date = DateTime.Parse("2018-11-26"), Open = 259.33m, High = 261.25m, Low = 258.90m, Close = 261.00m, Volume = 81971728 }, - new() { Date = DateTime.Parse("2018-11-23"), Open = 256.79m, High = 258.39m, Low = 256.68m, Close = 256.86m, Volume = 43873168 }, - new() { Date = DateTime.Parse("2018-11-21"), Open = 259.40m, High = 260.66m, Low = 258.58m, Close = 258.58m, Volume = 77444168 }, - new() { Date = DateTime.Parse("2018-11-20"), Open = 258.92m, High = 260.52m, Low = 256.76m, Close = 257.71m, Volume = 139406240 }, - new() { Date = DateTime.Parse("2018-11-19"), Open = 266.42m, High = 266.74m, Low = 261.56m, Close = 262.57m, Volume = 105626432 }, - new() { Date = DateTime.Parse("2018-11-16"), Open = 265.19m, High = 268.08m, Low = 264.62m, Close = 267.08m, Volume = 129820216 }, - new() { Date = DateTime.Parse("2018-11-15"), Open = 262.25m, High = 266.90m, Low = 260.53m, Close = 266.39m, Volume = 138463488 }, - new() { Date = DateTime.Parse("2018-11-14"), Open = 267.50m, High = 267.94m, Low = 261.93m, Close = 263.64m, Volume = 128454960 }, - new() { Date = DateTime.Parse("2018-11-13"), Open = 266.46m, High = 268.64m, Low = 264.66m, Close = 265.45m, Volume = 100619768 }, - new() { Date = DateTime.Parse("2018-11-12"), Open = 270.46m, High = 270.72m, Low = 265.39m, Close = 265.95m, Volume = 102153984 }, - new() { Date = DateTime.Parse("2018-11-09"), Open = 272.25m, High = 272.46m, Low = 269.47m, Close = 271.02m, Volume = 101271544 }, - new() { Date = DateTime.Parse("2018-11-08"), Open = 273.31m, High = 274.39m, Low = 272.44m, Close = 273.69m, Volume = 67216992 }, - new() { Date = DateTime.Parse("2018-11-07"), Open = 270.82m, High = 274.27m, Low = 270.35m, Close = 274.19m, Volume = 105309120 }, - new() { Date = DateTime.Parse("2018-11-06"), Open = 266.68m, High = 268.62m, Low = 266.62m, Close = 268.44m, Volume = 61581152 }, - new() { Date = DateTime.Parse("2018-11-05"), Open = 265.82m, High = 267.36m, Low = 264.76m, Close = 266.75m, Volume = 67255520 }, - new() { Date = DateTime.Parse("2018-11-02"), Open = 268.08m, High = 268.55m, Low = 263.04m, Close = 265.29m, Volume = 125685896 }, - new() { Date = DateTime.Parse("2018-11-01"), Open = 265.01m, High = 267.08m, Low = 263.81m, Close = 266.87m, Volume = 101971008 }, - new() { Date = DateTime.Parse("2018-10-31"), Open = 264.08m, High = 266.60m, Low = 263.56m, Close = 264.06m, Volume = 131489024 }, - new() { Date = DateTime.Parse("2018-10-30"), Open = 257.27m, High = 261.61m, Low = 256.73m, Close = 261.27m, Volume = 161025888 }, - new() { Date = DateTime.Parse("2018-10-29"), Open = 262.27m, High = 263.69m, Low = 253.54m, Close = 257.45m, Volume = 164749392 }, - new() { Date = DateTime.Parse("2018-10-26"), Open = 259.46m, High = 264.42m, Low = 255.92m, Close = 258.89m, Volume = 206590848 }, - new() { Date = DateTime.Parse("2018-10-25"), Open = 260.89m, High = 265.21m, Low = 259.77m, Close = 263.52m, Volume = 141497248 }, - new() { Date = DateTime.Parse("2018-10-24"), Open = 266.69m, High = 267.11m, Low = 258.27m, Close = 258.88m, Volume = 182231472 }, - new() { Date = DateTime.Parse("2018-10-23"), Open = 264.37m, High = 268.20m, Low = 262.09m, Close = 266.97m, Volume = 149994752 }, - new() { Date = DateTime.Parse("2018-10-22"), Open = 270.27m, High = 270.63m, Low = 267.75m, Close = 268.33m, Volume = 84466760 }, - new() { Date = DateTime.Parse("2018-10-19"), Open = 270.40m, High = 272.52m, Low = 268.78m, Close = 269.54m, Volume = 143383136 }, - new() { Date = DateTime.Parse("2018-10-18"), Open = 272.62m, High = 273.27m, Low = 268.29m, Close = 269.69m, Volume = 137906032 }, - new() { Date = DateTime.Parse("2018-10-17"), Open = 273.63m, High = 274.32m, Low = 270.82m, Close = 273.64m, Volume = 113378952 }, - new() { Date = DateTime.Parse("2018-10-16"), Open = 269.88m, High = 274.00m, Low = 269.37m, Close = 273.59m, Volume = 121198672 }, - new() { Date = DateTime.Parse("2018-10-15"), Open = 268.86m, High = 270.31m, Low = 267.64m, Close = 267.74m, Volume = 104808584 }, - new() { Date = DateTime.Parse("2018-10-12"), Open = 270.05m, High = 270.36m, Low = 265.76m, Close = 269.25m, Volume = 187745152 }, - new() { Date = DateTime.Parse("2018-10-11"), Open = 270.35m, High = 272.13m, Low = 263.80m, Close = 265.56m, Volume = 281680000 }, - new() { Date = DateTime.Parse("2018-10-10"), Open = 279.87m, High = 279.94m, Low = 271.13m, Close = 271.54m, Volume = 220074688 }, - new() { Date = DateTime.Parse("2018-10-09"), Open = 280.41m, High = 281.85m, Low = 279.81m, Close = 280.42m, Volume = 76188928 }, - new() { Date = DateTime.Parse("2018-10-08"), Open = 280.08m, High = 281.22m, Low = 278.57m, Close = 280.83m, Volume = 89925664 }, - new() { Date = DateTime.Parse("2018-10-05"), Open = 282.66m, High = 283.22m, Low = 279.27m, Close = 280.83m, Volume = 108588344 }, - new() { Date = DateTime.Parse("2018-10-04"), Open = 284.11m, High = 284.17m, Low = 280.68m, Close = 282.41m, Volume = 114321768 }, - new() { Date = DateTime.Parse("2018-10-03"), Open = 285.63m, High = 286.09m, Low = 284.25m, Close = 284.64m, Volume = 66304540 }, - new() { Date = DateTime.Parse("2018-10-02"), Open = 284.48m, High = 285.26m, Low = 284.07m, Close = 284.48m, Volume = 48434264 }, - new() { Date = DateTime.Parse("2018-10-01"), Open = 285.02m, High = 285.82m, Low = 283.91m, Close = 284.65m, Volume = 63623792 }, - new() { Date = DateTime.Parse("2018-09-28"), Open = 282.95m, High = 284.21m, Low = 282.91m, Close = 283.66m, Volume = 71835632 }, - new() { Date = DateTime.Parse("2018-09-27"), Open = 283.36m, High = 284.82m, Low = 283.06m, Close = 283.63m, Volume = 60723896 }, - new() { Date = DateTime.Parse("2018-09-26"), Open = 283.85m, High = 285.14m, Low = 282.38m, Close = 282.84m, Volume = 81724024 }, - new() { Date = DateTime.Parse("2018-09-25"), Open = 284.45m, High = 284.57m, Low = 283.43m, Close = 283.69m, Volume = 45474200 }, - new() { Date = DateTime.Parse("2018-09-24"), Open = 284.27m, High = 284.42m, Low = 283.32m, Close = 283.95m, Volume = 54738760 }, - new() { Date = DateTime.Parse("2018-09-21"), Open = 285.97m, High = 286.10m, Low = 284.72m, Close = 284.90m, Volume = 108104552 }, - new() { Date = DateTime.Parse("2018-09-20"), Open = 284.25m, High = 285.51m, Low = 282.88m, Close = 285.16m, Volume = 103323632 }, - new() { Date = DateTime.Parse("2018-09-19"), Open = 282.63m, High = 283.33m, Low = 282.48m, Close = 282.87m, Volume = 50529584 }, - new() { Date = DateTime.Parse("2018-09-18"), Open = 281.28m, High = 283.22m, Low = 281.25m, Close = 282.57m, Volume = 63758804 }, - new() { Date = DateTime.Parse("2018-09-17"), Open = 282.48m, High = 282.52m, Low = 280.74m, Close = 281.04m, Volume = 70258840 }, - new() { Date = DateTime.Parse("2018-09-14"), Open = 282.71m, High = 282.92m, Low = 281.68m, Close = 282.54m, Volume = 56706020 }, - new() { Date = DateTime.Parse("2018-09-13"), Open = 281.99m, High = 282.69m, Low = 281.68m, Close = 282.49m, Volume = 52540928 }, - new() { Date = DateTime.Parse("2018-09-12"), Open = 280.77m, High = 281.49m, Low = 279.96m, Close = 280.83m, Volume = 61576576 }, - new() { Date = DateTime.Parse("2018-09-11"), Open = 279.13m, High = 281.25m, Low = 278.75m, Close = 280.76m, Volume = 52022324 }, - new() { Date = DateTime.Parse("2018-09-10"), Open = 280.46m, High = 280.75m, Low = 279.62m, Close = 279.84m, Volume = 51693300 }, - new() { Date = DateTime.Parse("2018-09-07"), Open = 278.75m, High = 280.42m, Low = 278.49m, Close = 279.35m, Volume = 75695528 }, - new() { Date = DateTime.Parse("2018-09-06"), Open = 280.86m, High = 281.19m, Low = 278.77m, Close = 279.90m, Volume = 67855744 }, - new() { Date = DateTime.Parse("2018-09-05"), Open = 281.11m, High = 281.33m, Low = 279.63m, Close = 280.74m, Volume = 74591480 }, - new() { Date = DateTime.Parse("2018-09-04"), Open = 281.53m, High = 281.89m, Low = 280.40m, Close = 281.50m, Volume = 59294748 }, - new() { Date = DateTime.Parse("2018-08-31"), Open = 281.53m, High = 282.47m, Low = 280.99m, Close = 281.98m, Volume = 68093544 }, - new() { Date = DateTime.Parse("2018-08-30"), Open = 282.60m, High = 283.00m, Low = 281.32m, Close = 281.98m, Volume = 63037208 }, - new() { Date = DateTime.Parse("2018-08-29"), Open = 281.84m, High = 283.37m, Low = 281.57m, Close = 283.12m, Volume = 63300776 }, - new() { Date = DateTime.Parse("2018-08-28"), Open = 281.98m, High = 282.09m, Low = 281.10m, Close = 281.61m, Volume = 48329404 }, - new() { Date = DateTime.Parse("2018-08-27"), Open = 280.58m, High = 281.59m, Low = 280.40m, Close = 281.47m, Volume = 58757348 }, - new() { Date = DateTime.Parse("2018-08-24"), Open = 278.23m, High = 279.42m, Low = 278.17m, Close = 279.27m, Volume = 59184624 }, - new() { Date = DateTime.Parse("2018-08-23"), Open = 277.77m, High = 278.71m, Low = 277.24m, Close = 277.59m, Volume = 50657548 }, - new() { Date = DateTime.Parse("2018-08-22"), Open = 277.68m, High = 278.54m, Low = 277.39m, Close = 277.96m, Volume = 46321688 }, - new() { Date = DateTime.Parse("2018-08-21"), Open = 278.04m, High = 279.07m, Low = 277.52m, Close = 278.13m, Volume = 69258080 }, - new() { Date = DateTime.Parse("2018-08-20"), Open = 277.38m, High = 277.77m, Low = 276.89m, Close = 277.48m, Volume = 40982744 }, - new() { Date = DateTime.Parse("2018-08-17"), Open = 275.69m, High = 277.37m, Low = 275.24m, Close = 276.89m, Volume = 67555760 }, - new() { Date = DateTime.Parse("2018-08-16"), Open = 275.27m, High = 276.87m, Low = 275.23m, Close = 275.91m, Volume = 72033608 }, - new() { Date = DateTime.Parse("2018-08-15"), Open = 274.28m, High = 274.44m, Low = 272.13m, Close = 273.70m, Volume = 105964064 }, - new() { Date = DateTime.Parse("2018-08-14"), Open = 274.81m, High = 276.02m, Low = 274.38m, Close = 275.76m, Volume = 45136396 }, - new() { Date = DateTime.Parse("2018-08-13"), Open = 275.34m, High = 276.01m, Low = 273.69m, Close = 274.01m, Volume = 67673568 }, - new() { Date = DateTime.Parse("2018-08-10"), Open = 275.32m, High = 275.91m, Low = 274.26m, Close = 275.04m, Volume = 79351592 }, - new() { Date = DateTime.Parse("2018-08-09"), Open = 277.34m, High = 277.77m, Low = 276.74m, Close = 276.90m, Volume = 36771464 }, - new() { Date = DateTime.Parse("2018-08-08"), Open = 277.21m, High = 277.71m, Low = 276.77m, Close = 277.27m, Volume = 43357916 }, - new() { Date = DateTime.Parse("2018-08-07"), Open = 277.21m, High = 277.81m, Low = 277.06m, Close = 277.39m, Volume = 44471960 }, - new() { Date = DateTime.Parse("2018-08-06"), Open = 275.51m, High = 276.82m, Low = 275.08m, Close = 276.48m, Volume = 40564136 }, - new() { Date = DateTime.Parse("2018-08-03"), Open = 274.43m, High = 275.52m, Low = 274.23m, Close = 275.47m, Volume = 55527740 }, - new() { Date = DateTime.Parse("2018-08-02"), Open = 271.38m, High = 274.48m, Low = 271.15m, Close = 274.29m, Volume = 65298924 }, - new() { Date = DateTime.Parse("2018-08-01"), Open = 273.49m, High = 274.04m, Low = 272.10m, Close = 272.81m, Volume = 55443260 }, - new() { Date = DateTime.Parse("2018-07-31"), Open = 272.76m, High = 273.93m, Low = 272.34m, Close = 273.26m, Volume = 70594928 }, - new() { Date = DateTime.Parse("2018-07-30"), Open = 273.44m, High = 273.61m, Low = 271.35m, Close = 271.92m, Volume = 65624404 }, - new() { Date = DateTime.Parse("2018-07-27"), Open = 275.57m, High = 275.68m, Low = 272.34m, Close = 273.35m, Volume = 79050080 }, - new() { Date = DateTime.Parse("2018-07-26"), Open = 275.08m, High = 275.96m, Low = 274.97m, Close = 275.21m, Volume = 59629476 }, - new() { Date = DateTime.Parse("2018-07-25"), Open = 273.26m, High = 276.22m, Low = 273.21m, Close = 275.87m, Volume = 81211824 }, - new() { Date = DateTime.Parse("2018-07-24"), Open = 273.71m, High = 274.46m, Low = 272.58m, Close = 273.53m, Volume = 70035320 }, - new() { Date = DateTime.Parse("2018-07-23"), Open = 271.44m, High = 272.39m, Low = 271.06m, Close = 272.16m, Volume = 48436568 }, - new() { Date = DateTime.Parse("2018-07-20"), Open = 271.75m, High = 272.44m, Low = 271.48m, Close = 271.66m, Volume = 84804656 }, - new() { Date = DateTime.Parse("2018-07-19"), Open = 272.27m, High = 272.69m, Low = 271.45m, Close = 271.97m, Volume = 63225212 }, - new() { Date = DateTime.Parse("2018-07-18"), Open = 272.51m, High = 273.12m, Low = 272.03m, Close = 273.00m, Volume = 45910016 }, - new() { Date = DateTime.Parse("2018-07-17"), Open = 270.48m, High = 272.85m, Low = 270.43m, Close = 272.43m, Volume = 53860032 }, - new() { Date = DateTime.Parse("2018-07-16"), Open = 271.62m, High = 271.78m, Low = 270.84m, Close = 271.33m, Volume = 49624096 }, - new() { Date = DateTime.Parse("2018-07-13"), Open = 271.16m, High = 271.90m, Low = 270.67m, Close = 271.57m, Volume = 49659024 }, - new() { Date = DateTime.Parse("2018-07-12"), Open = 270.30m, High = 271.42m, Low = 269.64m, Close = 271.36m, Volume = 61899772 }, - new() { Date = DateTime.Parse("2018-07-11"), Open = 269.20m, High = 270.07m, Low = 268.59m, Close = 268.92m, Volume = 79329656 }, - new() { Date = DateTime.Parse("2018-07-10"), Open = 270.43m, High = 271.01m, Low = 270.11m, Close = 270.90m, Volume = 53501064 }, - new() { Date = DateTime.Parse("2018-07-09"), Open = 268.62m, High = 269.99m, Low = 268.57m, Close = 269.93m, Volume = 52042820 }, - new() { Date = DateTime.Parse("2018-07-06"), Open = 265.31m, High = 267.93m, Low = 264.89m, Close = 267.52m, Volume = 68456816 }, - new() { Date = DateTime.Parse("2018-07-05"), Open = 264.36m, High = 265.35m, Low = 263.19m, Close = 265.28m, Volume = 58606568 }, - new() { Date = DateTime.Parse("2018-07-03"), Open = 265.05m, High = 265.15m, Low = 262.67m, Close = 263.13m, Volume = 43432576 }, - new() { Date = DateTime.Parse("2018-07-02"), Open = 261.78m, High = 264.24m, Low = 261.52m, Close = 264.06m, Volume = 65431128 }, - new() { Date = DateTime.Parse("2018-06-29"), Open = 264.32m, High = 265.81m, Low = 263.37m, Close = 263.50m, Volume = 100473760 }, - new() { Date = DateTime.Parse("2018-06-28"), Open = 261.57m, High = 263.96m, Low = 260.79m, Close = 263.12m, Volume = 78913504 }, - new() { Date = DateTime.Parse("2018-06-27"), Open = 264.45m, High = 266.01m, Low = 261.46m, Close = 261.63m, Volume = 108213904 }, - new() { Date = DateTime.Parse("2018-06-26"), Open = 263.85m, High = 264.74m, Low = 263.02m, Close = 263.81m, Volume = 70710976 }, - new() { Date = DateTime.Parse("2018-06-25"), Open = 265.60m, High = 265.77m, Low = 261.38m, Close = 263.23m, Volume = 141924096 }, - new() { Date = DateTime.Parse("2018-06-22"), Open = 267.76m, High = 267.88m, Low = 266.62m, Close = 266.86m, Volume = 58283384 }, - new() { Date = DateTime.Parse("2018-06-21"), Open = 268.05m, High = 268.07m, Low = 265.83m, Close = 266.38m, Volume = 73159376 }, - new() { Date = DateTime.Parse("2018-06-20"), Open = 268.35m, High = 268.78m, Low = 267.69m, Close = 268.06m, Volume = 55373416 }, - new() { Date = DateTime.Parse("2018-06-19"), Open = 266.14m, High = 267.84m, Low = 265.69m, Close = 267.60m, Volume = 100410976 }, - new() { Date = DateTime.Parse("2018-06-18"), Open = 267.59m, High = 268.77m, Low = 267.07m, Close = 268.63m, Volume = 54479888 }, - new() { Date = DateTime.Parse("2018-06-15"), Open = 268.67m, High = 269.55m, Low = 267.45m, Close = 269.18m, Volume = 123585600 }, - new() { Date = DateTime.Parse("2018-06-14"), Open = 269.80m, High = 270.11m, Low = 268.88m, Close = 269.53m, Volume = 79730104 }, - new() { Date = DateTime.Parse("2018-06-13"), Open = 269.97m, High = 270.25m, Low = 268.63m, Close = 268.85m, Volume = 81770464 }, - new() { Date = DateTime.Parse("2018-06-12"), Open = 269.82m, High = 270.11m, Low = 269.00m, Close = 269.71m, Volume = 74798688 }, - new() { Date = DateTime.Parse("2018-06-11"), Open = 269.25m, High = 270.15m, Low = 269.12m, Close = 269.36m, Volume = 60903392 }, - new() { Date = DateTime.Parse("2018-06-08"), Open = 267.71m, High = 269.06m, Low = 267.53m, Close = 269.00m, Volume = 74602920 }, - new() { Date = DateTime.Parse("2018-06-07"), Open = 268.77m, High = 269.09m, Low = 267.22m, Close = 268.21m, Volume = 75460928 }, - new() { Date = DateTime.Parse("2018-06-06"), Open = 266.68m, High = 268.36m, Low = 266.01m, Close = 268.24m, Volume = 64874192 }, - new() { Date = DateTime.Parse("2018-06-05"), Open = 265.97m, High = 266.43m, Low = 265.13m, Close = 266.02m, Volume = 52881036 }, - new() { Date = DateTime.Parse("2018-06-04"), Open = 265.47m, High = 266.10m, Low = 265.20m, Close = 265.82m, Volume = 46934832 }, - new() { Date = DateTime.Parse("2018-06-01"), Open = 263.42m, High = 264.90m, Low = 263.34m, Close = 264.57m, Volume = 73691520 }, - new() { Date = DateTime.Parse("2018-05-31"), Open = 263.16m, High = 263.49m, Low = 261.33m, Close = 261.99m, Volume = 96713160 }, - new() { Date = DateTime.Parse("2018-05-30"), Open = 261.57m, High = 264.09m, Low = 261.49m, Close = 263.61m, Volume = 72057608 }, - new() { Date = DateTime.Parse("2018-05-29"), Open = 261.39m, High = 262.22m, Low = 258.92m, Close = 260.14m, Volume = 119866288 }, - new() { Date = DateTime.Parse("2018-05-25"), Open = 263.16m, High = 263.85m, Low = 262.61m, Close = 263.16m, Volume = 58299660 }, - new() { Date = DateTime.Parse("2018-05-24"), Open = 263.90m, High = 264.20m, Low = 261.84m, Close = 263.79m, Volume = 78640328 }, - new() { Date = DateTime.Parse("2018-05-23"), Open = 262.22m, High = 264.36m, Low = 262.04m, Close = 264.33m, Volume = 66903156 }, - new() { Date = DateTime.Parse("2018-05-22"), Open = 264.91m, High = 265.20m, Low = 263.25m, Close = 263.61m, Volume = 54774884 }, - new() { Date = DateTime.Parse("2018-05-21"), Open = 264.00m, High = 264.93m, Low = 262.39m, Close = 264.34m, Volume = 60007156 }, - new() { Date = DateTime.Parse("2018-05-18"), Open = 262.65m, High = 263.05m, Low = 261.98m, Close = 262.37m, Volume = 66565792 }, - new() { Date = DateTime.Parse("2018-05-17"), Open = 262.96m, High = 264.21m, Low = 262.18m, Close = 263.03m, Volume = 58466824 }, - new() { Date = DateTime.Parse("2018-05-16"), Open = 262.19m, High = 263.75m, Low = 262.16m, Close = 263.25m, Volume = 55784492 }, - new() { Date = DateTime.Parse("2018-05-15"), Open = 262.62m, High = 262.64m, Low = 261.11m, Close = 262.15m, Volume = 90007968 }, - new() { Date = DateTime.Parse("2018-05-14"), Open = 264.31m, High = 265.03m, Low = 263.37m, Close = 263.97m, Volume = 56661420 }, - new() { Date = DateTime.Parse("2018-05-11"), Open = 263.17m, High = 264.13m, Low = 262.61m, Close = 263.84m, Volume = 61915812 }, - new() { Date = DateTime.Parse("2018-05-10"), Open = 261.41m, High = 263.40m, Low = 261.30m, Close = 263.04m, Volume = 74524544 }, - new() { Date = DateTime.Parse("2018-05-09"), Open = 258.84m, High = 260.95m, Low = 258.27m, Close = 260.60m, Volume = 61703432 }, - new() { Date = DateTime.Parse("2018-05-08"), Open = 257.70m, High = 258.50m, Low = 256.40m, Close = 258.11m, Volume = 69804000 }, - new() { Date = DateTime.Parse("2018-05-07"), Open = 258.08m, High = 259.17m, Low = 257.32m, Close = 258.11m, Volume = 57193284 }, - new() { Date = DateTime.Parse("2018-05-04"), Open = 252.89m, High = 257.98m, Low = 252.53m, Close = 257.24m, Volume = 94336840 }, - new() { Date = DateTime.Parse("2018-05-03"), Open = 253.60m, High = 254.66m, Low = 250.50m, Close = 253.95m, Volume = 140965808 }, - new() { Date = DateTime.Parse("2018-05-02"), Open = 256.02m, High = 256.91m, Low = 254.08m, Close = 254.51m, Volume = 89317992 }, - new() { Date = DateTime.Parse("2018-05-01"), Open = 255.16m, High = 256.35m, Low = 253.46m, Close = 256.23m, Volume = 76737024 }, - new() { Date = DateTime.Parse("2018-04-30"), Open = 258.44m, High = 259.04m, Low = 255.70m, Close = 255.78m, Volume = 84988424 }, - new() { Date = DateTime.Parse("2018-04-27"), Open = 258.18m, High = 258.51m, Low = 256.73m, Close = 257.76m, Volume = 59001736 }, - new() { Date = DateTime.Parse("2018-04-26"), Open = 256.05m, High = 258.42m, Low = 255.56m, Close = 257.52m, Volume = 70044640 }, - new() { Date = DateTime.Parse("2018-04-25"), Open = 254.23m, High = 255.41m, Low = 252.24m, Close = 254.93m, Volume = 107386584 }, - new() { Date = DateTime.Parse("2018-04-24"), Open = 258.89m, High = 259.13m, Low = 252.65m, Close = 254.30m, Volume = 116739904 }, - new() { Date = DateTime.Parse("2018-04-23"), Open = 258.44m, High = 259.04m, Low = 256.59m, Close = 257.77m, Volume = 67796416 }, - new() { Date = DateTime.Parse("2018-04-20"), Open = 259.93m, High = 260.18m, Low = 256.84m, Close = 257.81m, Volume = 103366016 }, - new() { Date = DateTime.Parse("2018-04-19"), Open = 260.75m, High = 260.97m, Low = 258.88m, Close = 260.01m, Volume = 80307456 }, - new() { Date = DateTime.Parse("2018-04-18"), Open = 261.75m, High = 262.34m, Low = 260.96m, Close = 261.46m, Volume = 59260488 }, - new() { Date = DateTime.Parse("2018-04-17"), Open = 260.44m, High = 261.93m, Low = 259.88m, Close = 261.27m, Volume = 66890592 }, - new() { Date = DateTime.Parse("2018-04-16"), Open = 258.18m, High = 259.34m, Low = 257.29m, Close = 258.50m, Volume = 65570252 }, - new() { Date = DateTime.Parse("2018-04-13"), Open = 258.58m, High = 258.71m, Low = 255.29m, Close = 256.40m, Volume = 87984192 }, - new() { Date = DateTime.Parse("2018-04-12"), Open = 256.50m, High = 258.18m, Low = 256.31m, Close = 257.15m, Volume = 71242736 }, - new() { Date = DateTime.Parse("2018-04-11"), Open = 254.77m, High = 256.87m, Low = 254.69m, Close = 255.05m, Volume = 94252208 }, - new() { Date = DateTime.Parse("2018-04-10"), Open = 255.54m, High = 257.26m, Low = 254.30m, Close = 256.40m, Volume = 109178536 }, - new() { Date = DateTime.Parse("2018-04-09"), Open = 252.74m, High = 256.10m, Low = 251.35m, Close = 252.38m, Volume = 109043264 }, - new() { Date = DateTime.Parse("2018-04-06"), Open = 254.72m, High = 256.36m, Low = 249.48m, Close = 251.14m, Volume = 185650928 }, - new() { Date = DateTime.Parse("2018-04-05"), Open = 256.78m, High = 257.84m, Low = 255.59m, Close = 256.87m, Volume = 85474776 }, - new() { Date = DateTime.Parse("2018-04-04"), Open = 248.27m, High = 255.63m, Low = 248.13m, Close = 254.86m, Volume = 127939576 }, - new() { Date = DateTime.Parse("2018-04-03"), Open = 250.32m, High = 252.68m, Low = 248.36m, Close = 252.16m, Volume = 124052768 }, - new() { Date = DateTime.Parse("2018-04-02"), Open = 253.88m, High = 254.44m, Low = 246.26m, Close = 248.97m, Volume = 192647056 }, - new() { Date = DateTime.Parse("2018-03-29"), Open = 252.50m, High = 256.50m, Low = 251.26m, Close = 254.46m, Volume = 128487112 }, - new() { Date = DateTime.Parse("2018-03-28"), Open = 252.14m, High = 253.97m, Low = 250.04m, Close = 251.25m, Volume = 151452896 }, - new() { Date = DateTime.Parse("2018-03-27"), Open = 257.38m, High = 257.96m, Low = 250.29m, Close = 252.00m, Volume = 134378272 }, - new() { Date = DateTime.Parse("2018-03-26"), Open = 253.48m, High = 256.67m, Low = 250.84m, Close = 256.36m, Volume = 146803168 }, - new() { Date = DateTime.Parse("2018-03-23"), Open = 255.45m, High = 256.27m, Low = 249.32m, Close = 249.53m, Volume = 189801520 }, - new() { Date = DateTime.Parse("2018-03-22"), Open = 259.06m, High = 259.99m, Low = 254.66m, Close = 254.96m, Volume = 153866192 }, - new() { Date = DateTime.Parse("2018-03-21"), Open = 261.96m, High = 264.25m, Low = 261.27m, Close = 261.50m, Volume = 81397104 }, - new() { Date = DateTime.Parse("2018-03-20"), Open = 261.99m, High = 262.70m, Low = 261.26m, Close = 262.00m, Volume = 61797672 }, - new() { Date = DateTime.Parse("2018-03-19"), Open = 264.32m, High = 265.34m, Low = 259.75m, Close = 261.56m, Volume = 112937344 }, - new() { Date = DateTime.Parse("2018-03-16"), Open = 265.44m, High = 266.30m, Low = 265.09m, Close = 265.15m, Volume = 103769888 }, - new() { Date = DateTime.Parse("2018-03-15"), Open = 265.71m, High = 266.41m, Low = 264.31m, Close = 264.86m, Volume = 86627344 }, - new() { Date = DateTime.Parse("2018-03-14"), Open = 267.57m, High = 267.77m, Low = 264.54m, Close = 265.15m, Volume = 109949368 }, - new() { Date = DateTime.Parse("2018-03-13"), Open = 269.52m, High = 270.07m, Low = 265.85m, Close = 266.52m, Volume = 95490048 }, - new() { Date = DateTime.Parse("2018-03-12"), Open = 268.90m, High = 269.59m, Low = 267.83m, Close = 268.25m, Volume = 74678496 }, - new() { Date = DateTime.Parse("2018-03-09"), Open = 265.53m, High = 268.59m, Low = 265.19m, Close = 268.59m, Volume = 117975584 }, - new() { Date = DateTime.Parse("2018-03-08"), Open = 263.46m, High = 264.13m, Low = 262.37m, Close = 263.99m, Volume = 69462520 }, - new() { Date = DateTime.Parse("2018-03-07"), Open = 260.45m, High = 263.11m, Low = 260.24m, Close = 262.72m, Volume = 90396808 }, - new() { Date = DateTime.Parse("2018-03-06"), Open = 263.22m, High = 263.31m, Low = 261.18m, Close = 262.82m, Volume = 82245904 }, - new() { Date = DateTime.Parse("2018-03-05"), Open = 257.86m, High = 262.83m, Low = 257.74m, Close = 262.15m, Volume = 101032888 }, - new() { Date = DateTime.Parse("2018-03-02"), Open = 256.00m, High = 259.77m, Low = 255.05m, Close = 259.16m, Volume = 144408144 }, - new() { Date = DateTime.Parse("2018-03-01"), Open = 261.40m, High = 263.10m, Low = 256.19m, Close = 257.83m, Volume = 183626128 }, - new() { Date = DateTime.Parse("2018-02-28"), Open = 265.51m, High = 266.01m, Low = 261.29m, Close = 261.63m, Volume = 126575120 }, - new() { Date = DateTime.Parse("2018-02-27"), Open = 267.86m, High = 268.63m, Low = 264.24m, Close = 264.31m, Volume = 102893264 }, - new() { Date = DateTime.Parse("2018-02-26"), Open = 265.76m, High = 267.76m, Low = 265.11m, Close = 267.65m, Volume = 89802808 }, - new() { Date = DateTime.Parse("2018-02-23"), Open = 261.77m, High = 264.58m, Low = 261.25m, Close = 264.58m, Volume = 96318072 }, - new() { Date = DateTime.Parse("2018-02-22"), Open = 261.10m, High = 262.98m, Low = 259.70m, Close = 260.43m, Volume = 114742312 }, - new() { Date = DateTime.Parse("2018-02-21"), Open = 261.87m, High = 264.59m, Low = 259.99m, Close = 260.09m, Volume = 102669592 }, - new() { Date = DateTime.Parse("2018-02-20"), Open = 262.00m, High = 263.58m, Low = 260.53m, Close = 261.39m, Volume = 89676400 }, - new() { Date = DateTime.Parse("2018-02-16"), Open = 262.28m, High = 265.17m, Low = 262.23m, Close = 263.04m, Volume = 166561968 }, - new() { Date = DateTime.Parse("2018-02-15"), Open = 261.56m, High = 262.97m, Low = 258.86m, Close = 262.96m, Volume = 115457688 }, - new() { Date = DateTime.Parse("2018-02-14"), Open = 254.56m, High = 260.04m, Low = 254.55m, Close = 259.65m, Volume = 125358160 }, - new() { Date = DateTime.Parse("2018-02-13"), Open = 254.24m, High = 256.79m, Low = 253.60m, Close = 256.19m, Volume = 84333360 }, - new() { Date = DateTime.Parse("2018-02-12"), Open = 254.10m, High = 257.16m, Low = 252.02m, Close = 255.56m, Volume = 149239040 }, - new() { Date = DateTime.Parse("2018-02-09"), Open = 251.18m, High = 253.89m, Low = 243.59m, Close = 251.86m, Volume = 294421856 }, - new() { Date = DateTime.Parse("2018-02-08"), Open = 258.13m, High = 258.28m, Low = 248.09m, Close = 248.13m, Volume = 255885040 }, - new() { Date = DateTime.Parse("2018-02-07"), Open = 258.60m, High = 262.32m, Low = 257.71m, Close = 257.80m, Volume = 173784240 }, - new() { Date = DateTime.Parse("2018-02-06"), Open = 250.35m, High = 259.76m, Low = 249.16m, Close = 259.21m, Volume = 368619296 }, - new() { Date = DateTime.Parse("2018-02-05"), Open = 263.37m, High = 265.68m, Low = 253.60m, Close = 254.20m, Volume = 305963968 }, - new() { Date = DateTime.Parse("2018-02-02"), Open = 269.75m, High = 269.90m, Low = 265.25m, Close = 265.29m, Volume = 179804944 }, - new() { Date = DateTime.Parse("2018-02-01"), Open = 270.71m, High = 272.62m, Low = 270.33m, Close = 271.20m, Volume = 93552120 }, - new() { Date = DateTime.Parse("2018-01-31"), Open = 272.30m, High = 272.85m, Low = 270.33m, Close = 271.51m, Volume = 123502168 }, - new() { Date = DateTime.Parse("2018-01-30"), Open = 272.18m, High = 274.24m, Low = 270.85m, Close = 271.37m, Volume = 136842368 }, - new() { Date = DateTime.Parse("2018-01-29"), Open = 275.39m, High = 275.87m, Low = 274.01m, Close = 274.18m, Volume = 93568600 }, - new() { Date = DateTime.Parse("2018-01-26"), Open = 273.77m, High = 276.06m, Low = 273.49m, Close = 276.01m, Volume = 111868160 }, - new() { Date = DateTime.Parse("2018-01-25"), Open = 273.68m, High = 273.79m, Low = 271.99m, Close = 272.85m, Volume = 87825816 }, - new() { Date = DateTime.Parse("2018-01-24"), Open = 273.55m, High = 274.20m, Low = 271.45m, Close = 272.74m, Volume = 139977680 }, - new() { Date = DateTime.Parse("2018-01-23"), Open = 272.31m, High = 273.16m, Low = 271.96m, Close = 272.84m, Volume = 100801672 }, - new() { Date = DateTime.Parse("2018-01-22"), Open = 269.84m, High = 272.27m, Low = 269.78m, Close = 272.27m, Volume = 94818768 }, - new() { Date = DateTime.Parse("2018-01-19"), Open = 269.48m, High = 270.07m, Low = 268.85m, Close = 270.07m, Volume = 146315344 }, - new() { Date = DateTime.Parse("2018-01-18"), Open = 269.17m, High = 269.64m, Low = 268.31m, Close = 268.85m, Volume = 104584464 }, - new() { Date = DateTime.Parse("2018-01-17"), Open = 267.78m, High = 269.72m, Low = 266.76m, Close = 269.30m, Volume = 117595008 }, - new() { Date = DateTime.Parse("2018-01-16"), Open = 269.05m, High = 269.76m, Low = 266.00m, Close = 266.76m, Volume = 110634704 }, - new() { Date = DateTime.Parse("2018-01-12"), Open = 266.23m, High = 267.86m, Low = 265.90m, Close = 267.67m, Volume = 94293048 }, - new() { Date = DateTime.Parse("2018-01-11"), Open = 264.62m, High = 265.94m, Low = 264.44m, Close = 265.94m, Volume = 64749016 }, - new() { Date = DateTime.Parse("2018-01-10"), Open = 263.59m, High = 264.30m, Low = 262.86m, Close = 264.01m, Volume = 72238032 }, - new() { Date = DateTime.Parse("2018-01-09"), Open = 264.28m, High = 265.10m, Low = 263.97m, Close = 264.42m, Volume = 59445976 }, - new() { Date = DateTime.Parse("2018-01-08"), Open = 263.23m, High = 263.99m, Low = 262.91m, Close = 263.82m, Volume = 59513708 }, - new() { Date = DateTime.Parse("2018-01-05"), Open = 262.46m, High = 263.47m, Low = 261.92m, Close = 263.34m, Volume = 86721784 }, - new() { Date = DateTime.Parse("2018-01-04"), Open = 261.20m, High = 262.12m, Low = 260.57m, Close = 261.59m, Volume = 83723648 }, - new() { Date = DateTime.Parse("2018-01-03"), Open = 259.04m, High = 260.66m, Low = 259.04m, Close = 260.50m, Volume = 93518840 }, - new() { Date = DateTime.Parse("2018-01-02"), Open = 257.96m, High = 258.90m, Low = 257.54m, Close = 258.86m, Volume = 89973440 }, - new() { Date = DateTime.Parse("2017-12-29"), Open = 258.63m, High = 258.65m, Low = 256.81m, Close = 257.02m, Volume = 99683152 }, - new() { Date = DateTime.Parse("2017-12-28"), Open = 258.01m, High = 258.04m, Low = 257.59m, Close = 257.99m, Volume = 46843448 }, - new() { Date = DateTime.Parse("2017-12-27"), Open = 257.52m, High = 257.86m, Low = 257.16m, Close = 257.46m, Volume = 59962032 }, - new() { Date = DateTime.Parse("2017-12-26"), Open = 257.20m, High = 257.58m, Low = 257.04m, Close = 257.34m, Volume = 46976656 }, - new() { Date = DateTime.Parse("2017-12-22"), Open = 257.73m, High = 257.77m, Low = 257.06m, Close = 257.65m, Volume = 81734768 }, - new() { Date = DateTime.Parse("2017-12-21"), Open = 257.87m, High = 258.49m, Low = 257.44m, Close = 257.71m, Volume = 69598728 }, - new() { Date = DateTime.Parse("2017-12-20"), Open = 258.38m, High = 258.44m, Low = 256.86m, Close = 257.18m, Volume = 79690000 }, - new() { Date = DateTime.Parse("2017-12-19"), Open = 258.58m, High = 258.63m, Low = 257.24m, Close = 257.32m, Volume = 85536976 }, - new() { Date = DateTime.Parse("2017-12-18"), Open = 258.21m, High = 258.70m, Low = 258.10m, Close = 258.31m, Volume = 86856320 }, - new() { Date = DateTime.Parse("2017-12-15"), Open = 255.66m, High = 257.19m, Low = 255.60m, Close = 256.68m, Volume = 150146832 }, - new() { Date = DateTime.Parse("2017-12-14"), Open = 255.93m, High = 256.06m, Low = 254.51m, Close = 254.56m, Volume = 105055176 }, - new() { Date = DateTime.Parse("2017-12-13"), Open = 255.90m, High = 256.38m, Low = 255.51m, Close = 255.61m, Volume = 107391488 }, - new() { Date = DateTime.Parse("2017-12-12"), Open = 255.43m, High = 256.15m, Low = 255.22m, Close = 255.64m, Volume = 88909792 }, - new() { Date = DateTime.Parse("2017-12-11"), Open = 254.49m, High = 255.25m, Low = 254.39m, Close = 255.19m, Volume = 86699232 }, - new() { Date = DateTime.Parse("2017-12-08"), Open = 253.92m, High = 254.43m, Low = 253.00m, Close = 254.42m, Volume = 79901608 }, - new() { Date = DateTime.Parse("2017-12-07"), Open = 252.10m, High = 253.38m, Low = 251.96m, Close = 253.04m, Volume = 80584848 }, - new() { Date = DateTime.Parse("2017-12-06"), Open = 251.89m, High = 252.71m, Low = 251.74m, Close = 252.24m, Volume = 79207304 }, - new() { Date = DateTime.Parse("2017-12-05"), Open = 253.38m, High = 254.07m, Low = 252.05m, Close = 252.20m, Volume = 81394656 }, - new() { Date = DateTime.Parse("2017-12-04"), Open = 255.19m, High = 255.65m, Low = 253.05m, Close = 253.11m, Volume = 98140184 }, - new() { Date = DateTime.Parse("2017-12-01"), Open = 253.70m, High = 254.23m, Low = 249.87m, Close = 253.41m, Volume = 171557392 }, - new() { Date = DateTime.Parse("2017-11-30"), Open = 252.74m, High = 254.94m, Low = 252.66m, Close = 253.94m, Volume = 133469840 }, - new() { Date = DateTime.Parse("2017-11-29"), Open = 252.03m, High = 252.62m, Low = 251.25m, Close = 251.74m, Volume = 80891176 }, - new() { Date = DateTime.Parse("2017-11-28"), Open = 249.87m, High = 251.92m, Low = 249.77m, Close = 251.89m, Volume = 103286312 }, - new() { Date = DateTime.Parse("2017-11-27"), Open = 249.53m, High = 249.86m, Low = 249.14m, Close = 249.36m, Volume = 54553804 }, - new() { Date = DateTime.Parse("2017-11-24"), Open = 249.45m, High = 249.60m, Low = 249.29m, Close = 249.48m, Volume = 29070892 }, - new() { Date = DateTime.Parse("2017-11-22"), Open = 249.14m, High = 249.28m, Low = 248.73m, Close = 248.91m, Volume = 46996584 }, - new() { Date = DateTime.Parse("2017-11-21"), Open = 248.35m, High = 249.33m, Low = 247.47m, Close = 249.13m, Volume = 72192504 }, - new() { Date = DateTime.Parse("2017-11-20"), Open = 247.36m, High = 247.73m, Low = 247.09m, Close = 247.51m, Volume = 50171324 }, - new() { Date = DateTime.Parse("2017-11-17"), Open = 247.43m, High = 247.79m, Low = 247.00m, Close = 247.09m, Volume = 79059392 }, - new() { Date = DateTime.Parse("2017-11-16"), Open = 246.76m, High = 248.22m, Low = 246.72m, Close = 247.82m, Volume = 70731712 }, - new() { Date = DateTime.Parse("2017-11-15"), Open = 245.90m, High = 246.48m, Low = 244.95m, Close = 245.73m, Volume = 84334432 }, - new() { Date = DateTime.Parse("2017-11-14"), Open = 246.66m, High = 247.08m, Low = 245.80m, Close = 246.96m, Volume = 63988136 }, - new() { Date = DateTime.Parse("2017-11-13"), Open = 246.56m, High = 247.79m, Low = 246.52m, Close = 247.54m, Volume = 52418324 }, - new() { Date = DateTime.Parse("2017-11-10"), Open = 246.96m, High = 247.50m, Low = 246.62m, Close = 247.31m, Volume = 62599644 }, - new() { Date = DateTime.Parse("2017-11-09"), Open = 246.96m, High = 247.60m, Low = 245.65m, Close = 247.39m, Volume = 99230672 }, - new() { Date = DateTime.Parse("2017-11-08"), Open = 247.67m, High = 248.39m, Low = 247.37m, Close = 248.29m, Volume = 52669760 }, - new() { Date = DateTime.Parse("2017-11-07"), Open = 248.15m, High = 248.52m, Low = 247.31m, Close = 247.86m, Volume = 60008920 }, - new() { Date = DateTime.Parse("2017-11-06"), Open = 247.51m, High = 248.18m, Low = 247.43m, Close = 248.04m, Volume = 51817160 }, - new() { Date = DateTime.Parse("2017-11-03"), Open = 247.00m, High = 247.70m, Low = 246.55m, Close = 247.65m, Volume = 62187496 }, - new() { Date = DateTime.Parse("2017-11-02"), Open = 246.66m, High = 246.98m, Low = 245.49m, Close = 246.83m, Volume = 58910404 }, - new() { Date = DateTime.Parse("2017-11-01"), Open = 247.26m, High = 247.63m, Low = 246.33m, Close = 246.73m, Volume = 56565660 }, - new() { Date = DateTime.Parse("2017-10-31"), Open = 246.44m, High = 246.69m, Low = 246.08m, Close = 246.41m, Volume = 62933720 }, - new() { Date = DateTime.Parse("2017-10-30"), Open = 246.33m, High = 246.84m, Low = 245.70m, Close = 246.02m, Volume = 56652224 }, - new() { Date = DateTime.Parse("2017-10-27"), Open = 245.76m, High = 247.12m, Low = 244.95m, Close = 246.94m, Volume = 89292576 }, - new() { Date = DateTime.Parse("2017-10-26"), Open = 245.30m, High = 245.59m, Low = 244.81m, Close = 244.94m, Volume = 72840760 }, - new() { Date = DateTime.Parse("2017-10-25"), Open = 245.48m, High = 245.60m, Low = 243.39m, Close = 244.63m, Volume = 108236672 }, - new() { Date = DateTime.Parse("2017-10-24"), Open = 245.88m, High = 246.10m, Low = 245.45m, Close = 245.84m, Volume = 69853928 }, - new() { Date = DateTime.Parse("2017-10-23"), Open = 246.72m, High = 246.75m, Low = 245.33m, Close = 245.41m, Volume = 66701640 }, - new() { Date = DateTime.Parse("2017-10-20"), Open = 245.98m, High = 246.40m, Low = 245.09m, Close = 246.37m, Volume = 93063952 }, - new() { Date = DateTime.Parse("2017-10-19"), Open = 244.18m, High = 245.14m, Low = 243.72m, Close = 245.10m, Volume = 64602432 }, - new() { Date = DateTime.Parse("2017-10-18"), Open = 245.21m, High = 245.26m, Low = 244.83m, Close = 245.04m, Volume = 42670820 }, - new() { Date = DateTime.Parse("2017-10-17"), Open = 244.57m, High = 244.85m, Low = 244.33m, Close = 244.80m, Volume = 32936836 }, - new() { Date = DateTime.Parse("2017-10-16"), Open = 244.55m, High = 244.84m, Low = 244.18m, Close = 244.63m, Volume = 39887916 }, - new() { Date = DateTime.Parse("2017-10-13"), Open = 244.48m, High = 244.61m, Low = 244.00m, Close = 244.30m, Volume = 57189416 }, - new() { Date = DateTime.Parse("2017-10-12"), Open = 244.02m, High = 244.41m, Low = 243.74m, Close = 244.00m, Volume = 49116908 }, - new() { Date = DateTime.Parse("2017-10-11"), Open = 243.88m, High = 244.37m, Low = 243.70m, Close = 244.37m, Volume = 49752644 }, - new() { Date = DateTime.Parse("2017-10-10"), Open = 243.96m, High = 244.40m, Low = 243.37m, Close = 243.98m, Volume = 44934412 }, - new() { Date = DateTime.Parse("2017-10-09"), Open = 243.99m, High = 244.06m, Low = 243.05m, Close = 243.34m, Volume = 37363944 }, - new() { Date = DateTime.Parse("2017-10-06"), Open = 243.53m, High = 244.06m, Low = 243.25m, Close = 243.74m, Volume = 84161696 }, - new() { Date = DateTime.Parse("2017-10-05"), Open = 242.95m, High = 244.04m, Low = 242.62m, Close = 244.02m, Volume = 66291980 }, - new() { Date = DateTime.Parse("2017-10-04"), Open = 242.13m, High = 242.85m, Low = 242.01m, Close = 242.58m, Volume = 58392872 }, - new() { Date = DateTime.Parse("2017-10-03"), Open = 241.91m, High = 242.33m, Low = 241.69m, Close = 242.30m, Volume = 69722704 }, - new() { Date = DateTime.Parse("2017-10-02"), Open = 240.98m, High = 241.78m, Low = 240.80m, Close = 241.78m, Volume = 61596044 }, - new() { Date = DateTime.Parse("2017-09-29"), Open = 239.88m, High = 240.82m, Low = 239.68m, Close = 240.74m, Volume = 89308704 }, - new() { Date = DateTime.Parse("2017-09-28"), Open = 239.30m, High = 239.98m, Low = 239.20m, Close = 239.89m, Volume = 46730936 }, - new() { Date = DateTime.Parse("2017-09-27"), Open = 239.44m, High = 240.03m, Low = 238.47m, Close = 239.60m, Volume = 84532616 }, - new() { Date = DateTime.Parse("2017-09-26"), Open = 239.00m, High = 239.27m, Low = 238.41m, Close = 238.68m, Volume = 56439616 }, - new() { Date = DateTime.Parse("2017-09-25"), Open = 238.74m, High = 239.13m, Low = 237.72m, Close = 238.53m, Volume = 59552032 }, - new() { Date = DateTime.Parse("2017-09-22"), Open = 238.65m, High = 239.20m, Low = 238.62m, Close = 239.02m, Volume = 53446664 }, - new() { Date = DateTime.Parse("2017-09-21"), Open = 239.44m, High = 239.54m, Low = 238.78m, Close = 238.97m, Volume = 50313136 }, - new() { Date = DateTime.Parse("2017-09-20"), Open = 239.62m, High = 239.74m, Low = 238.52m, Close = 239.61m, Volume = 62171164 }, - new() { Date = DateTime.Parse("2017-09-19"), Open = 239.56m, High = 239.62m, Low = 239.17m, Close = 239.53m, Volume = 49161788 }, - new() { Date = DateTime.Parse("2017-09-18"), Open = 239.18m, High = 239.67m, Low = 238.87m, Close = 239.29m, Volume = 48250824 }, - new() { Date = DateTime.Parse("2017-09-15"), Open = 238.30m, High = 238.88m, Low = 238.19m, Close = 238.78m, Volume = 99592680 }, - new() { Date = DateTime.Parse("2017-09-14"), Open = 238.18m, High = 238.68m, Low = 237.99m, Close = 238.46m, Volume = 100101416 }, - new() { Date = DateTime.Parse("2017-09-13"), Open = 238.11m, High = 238.57m, Low = 237.98m, Close = 238.54m, Volume = 62116640 }, - new() { Date = DateTime.Parse("2017-09-12"), Open = 238.02m, High = 238.46m, Low = 237.82m, Close = 238.42m, Volume = 59670932 }, - new() { Date = DateTime.Parse("2017-09-11"), Open = 236.51m, High = 237.71m, Low = 236.49m, Close = 237.62m, Volume = 74845424 }, - new() { Date = DateTime.Parse("2017-09-08"), Open = 235.07m, High = 235.62m, Low = 234.85m, Close = 235.11m, Volume = 66946052 }, - new() { Date = DateTime.Parse("2017-09-07"), Open = 235.75m, High = 235.77m, Low = 234.94m, Close = 235.39m, Volume = 60865172 }, - new() { Date = DateTime.Parse("2017-09-06"), Open = 235.36m, High = 235.78m, Low = 234.78m, Close = 235.42m, Volume = 60741564 }, - new() { Date = DateTime.Parse("2017-09-05"), Open = 235.76m, High = 236.01m, Low = 233.56m, Close = 234.62m, Volume = 95856440 }, - new() { Date = DateTime.Parse("2017-09-01"), Open = 236.39m, High = 236.78m, Low = 236.15m, Close = 236.31m, Volume = 65031164 }, - new() { Date = DateTime.Parse("2017-08-31"), Open = 235.25m, High = 236.25m, Low = 234.61m, Close = 235.98m, Volume = 108866560 }, - new() { Date = DateTime.Parse("2017-08-30"), Open = 233.44m, High = 234.87m, Low = 233.24m, Close = 234.57m, Volume = 65056144 }, - new() { Date = DateTime.Parse("2017-08-29"), Open = 231.76m, High = 233.75m, Low = 231.63m, Close = 233.46m, Volume = 53629680 }, - new() { Date = DateTime.Parse("2017-08-28"), Open = 233.77m, High = 233.80m, Low = 232.74m, Close = 233.20m, Volume = 42544052 }, - new() { Date = DateTime.Parse("2017-08-25"), Open = 233.51m, High = 234.19m, Low = 233.02m, Close = 233.19m, Volume = 67589040 }, - new() { Date = DateTime.Parse("2017-08-24"), Open = 233.61m, High = 233.78m, Low = 232.41m, Close = 232.64m, Volume = 53216420 }, - new() { Date = DateTime.Parse("2017-08-23"), Open = 232.97m, High = 233.65m, Low = 232.81m, Close = 233.19m, Volume = 52652352 }, - new() { Date = DateTime.Parse("2017-08-22"), Open = 232.24m, High = 234.20m, Low = 232.22m, Close = 234.03m, Volume = 66219544 }, - new() { Date = DateTime.Parse("2017-08-21"), Open = 231.36m, High = 231.89m, Low = 230.58m, Close = 231.60m, Volume = 68662792 }, - new() { Date = DateTime.Parse("2017-08-18"), Open = 231.60m, High = 232.83m, Low = 230.94m, Close = 231.42m, Volume = 143417408 }, - new() { Date = DateTime.Parse("2017-08-17"), Open = 234.79m, High = 235.13m, Low = 231.79m, Close = 231.79m, Volume = 134757072 }, - new() { Date = DateTime.Parse("2017-08-16"), Open = 235.62m, High = 236.06m, Low = 234.99m, Close = 235.46m, Volume = 59481648 }, - new() { Date = DateTime.Parse("2017-08-15"), Open = 235.49m, High = 235.51m, Low = 234.71m, Close = 235.05m, Volume = 57937020 }, - new() { Date = DateTime.Parse("2017-08-14"), Open = 234.17m, High = 235.31m, Low = 234.13m, Close = 235.07m, Volume = 76866480 }, - new() { Date = DateTime.Parse("2017-08-11"), Open = 232.67m, High = 233.42m, Low = 232.41m, Close = 232.77m, Volume = 78521472 }, - new() { Date = DateTime.Parse("2017-08-10"), Open = 234.84m, High = 234.98m, Low = 232.37m, Close = 232.42m, Volume = 126355448 }, - new() { Date = DateTime.Parse("2017-08-09"), Open = 235.01m, High = 235.81m, Low = 234.62m, Close = 235.75m, Volume = 65687312 }, - new() { Date = DateTime.Parse("2017-08-08"), Open = 236.00m, High = 237.33m, Low = 235.35m, Close = 235.76m, Volume = 64729500 }, - new() { Date = DateTime.Parse("2017-08-07"), Open = 235.98m, High = 236.34m, Low = 235.87m, Close = 236.34m, Volume = 33555464 }, - new() { Date = DateTime.Parse("2017-08-04"), Open = 236.01m, High = 236.27m, Low = 235.49m, Close = 235.90m, Volume = 63127488 }, - new() { Date = DateTime.Parse("2017-08-03"), Open = 235.81m, High = 235.84m, Low = 235.17m, Close = 235.48m, Volume = 42848608 }, - new() { Date = DateTime.Parse("2017-08-02"), Open = 235.96m, High = 236.09m, Low = 234.91m, Close = 235.93m, Volume = 49513776 }, - new() { Date = DateTime.Parse("2017-08-01"), Open = 235.95m, High = 235.99m, Low = 235.24m, Close = 235.82m, Volume = 57735292 }, - new() { Date = DateTime.Parse("2017-07-31"), Open = 235.87m, High = 235.97m, Low = 235.07m, Close = 235.29m, Volume = 69049712 }, - new() { Date = DateTime.Parse("2017-07-28"), Open = 235.18m, High = 235.57m, Low = 234.68m, Close = 235.43m, Volume = 52531244 }, - new() { Date = DateTime.Parse("2017-07-27"), Open = 236.43m, High = 236.47m, Low = 234.26m, Close = 235.70m, Volume = 74217968 }, - new() { Date = DateTime.Parse("2017-07-26"), Open = 236.23m, High = 236.27m, Low = 235.64m, Close = 235.92m, Volume = 49895744 }, - new() { Date = DateTime.Parse("2017-07-25"), Open = 236.16m, High = 236.28m, Low = 235.67m, Close = 235.91m, Volume = 57593908 }, - new() { Date = DateTime.Parse("2017-07-24"), Open = 235.31m, High = 235.49m, Low = 234.83m, Close = 235.34m, Volume = 48896096 }, - new() { Date = DateTime.Parse("2017-07-21"), Open = 234.98m, High = 235.43m, Low = 234.73m, Close = 235.40m, Volume = 93037592 }, - new() { Date = DateTime.Parse("2017-07-20"), Open = 235.78m, High = 235.91m, Low = 235.01m, Close = 235.61m, Volume = 49434036 }, - new() { Date = DateTime.Parse("2017-07-19"), Open = 234.58m, High = 235.51m, Low = 234.57m, Close = 235.50m, Volume = 53523280 }, - new() { Date = DateTime.Parse("2017-07-18"), Open = 233.66m, High = 234.29m, Low = 233.29m, Close = 234.24m, Volume = 44827112 }, - new() { Date = DateTime.Parse("2017-07-17"), Open = 234.05m, High = 234.47m, Low = 233.92m, Close = 234.11m, Volume = 35167316 }, - new() { Date = DateTime.Parse("2017-07-14"), Open = 233.06m, High = 234.53m, Low = 232.95m, Close = 234.14m, Volume = 63201796 }, - new() { Date = DateTime.Parse("2017-07-13"), Open = 232.67m, High = 233.18m, Low = 232.42m, Close = 233.05m, Volume = 41396728 }, - new() { Date = DateTime.Parse("2017-07-12"), Open = 231.99m, High = 232.84m, Low = 231.99m, Close = 232.66m, Volume = 62517696 }, - new() { Date = DateTime.Parse("2017-07-11"), Open = 230.90m, High = 231.27m, Low = 229.65m, Close = 230.93m, Volume = 52810484 }, - new() { Date = DateTime.Parse("2017-07-10"), Open = 230.70m, High = 231.51m, Low = 230.52m, Close = 231.10m, Volume = 38451396 }, - new() { Date = DateTime.Parse("2017-07-07"), Open = 229.99m, High = 231.01m, Low = 229.38m, Close = 230.85m, Volume = 60799664 }, - new() { Date = DateTime.Parse("2017-07-06"), Open = 230.64m, High = 230.77m, Low = 229.16m, Close = 229.36m, Volume = 69339864 }, - new() { Date = DateTime.Parse("2017-07-05"), Open = 231.35m, High = 231.71m, Low = 230.46m, Close = 231.48m, Volume = 57082112 }, - new() { Date = DateTime.Parse("2017-07-03"), Open = 231.59m, High = 232.06m, Low = 230.95m, Close = 230.95m, Volume = 41063396 }, - new() { Date = DateTime.Parse("2017-06-30"), Open = 231.01m, High = 231.42m, Low = 230.34m, Close = 230.56m, Volume = 91055080 }, - new() { Date = DateTime.Parse("2017-06-29"), Open = 232.33m, High = 232.39m, Low = 228.80m, Close = 230.13m, Volume = 112165824 }, - new() { Date = DateTime.Parse("2017-06-28"), Open = 231.22m, High = 232.38m, Low = 230.97m, Close = 232.17m, Volume = 73458688 }, - new() { Date = DateTime.Parse("2017-06-27"), Open = 231.74m, High = 232.06m, Low = 230.09m, Close = 230.11m, Volume = 86259016 }, - new() { Date = DateTime.Parse("2017-06-26"), Open = 232.56m, High = 233.02m, Low = 231.74m, Close = 231.98m, Volume = 59465848 }, - new() { Date = DateTime.Parse("2017-06-23"), Open = 231.61m, High = 232.19m, Low = 231.19m, Close = 231.82m, Volume = 70253848 }, - new() { Date = DateTime.Parse("2017-06-22"), Open = 231.66m, High = 232.21m, Low = 231.36m, Close = 231.55m, Volume = 46301224 }, - new() { Date = DateTime.Parse("2017-06-21"), Open = 232.10m, High = 232.26m, Low = 231.14m, Close = 231.65m, Volume = 58707680 }, - new() { Date = DateTime.Parse("2017-06-20"), Open = 232.89m, High = 232.90m, Low = 231.69m, Close = 231.71m, Volume = 59681776 }, - new() { Date = DateTime.Parse("2017-06-19"), Open = 232.26m, High = 233.35m, Low = 232.16m, Close = 233.28m, Volume = 68299992 }, - new() { Date = DateTime.Parse("2017-06-16"), Open = 231.48m, High = 231.54m, Low = 230.40m, Close = 231.36m, Volume = 88676880 }, - new() { Date = DateTime.Parse("2017-06-15"), Open = 230.27m, High = 231.44m, Low = 229.97m, Close = 231.31m, Volume = 70046440 }, - new() { Date = DateTime.Parse("2017-06-14"), Open = 232.34m, High = 232.35m, Low = 230.85m, Close = 231.75m, Volume = 82837904 }, - new() { Date = DateTime.Parse("2017-06-13"), Open = 231.51m, High = 232.10m, Low = 231.13m, Close = 232.05m, Volume = 63303744 }, - new() { Date = DateTime.Parse("2017-06-12"), Open = 230.70m, High = 230.97m, Low = 229.99m, Close = 230.92m, Volume = 90748160 }, - new() { Date = DateTime.Parse("2017-06-09"), Open = 231.61m, High = 232.48m, Low = 229.58m, Close = 230.96m, Volume = 139383184 }, - new() { Date = DateTime.Parse("2017-06-08"), Open = 231.31m, High = 231.84m, Low = 230.74m, Close = 231.32m, Volume = 69504536 }, - new() { Date = DateTime.Parse("2017-06-07"), Open = 231.14m, High = 231.45m, Low = 230.41m, Close = 231.20m, Volume = 57061952 }, - new() { Date = DateTime.Parse("2017-06-06"), Open = 230.90m, High = 231.51m, Low = 230.69m, Close = 230.77m, Volume = 53089976 }, - new() { Date = DateTime.Parse("2017-06-05"), Open = 231.50m, High = 231.81m, Low = 231.30m, Close = 231.51m, Volume = 47107480 }, - new() { Date = DateTime.Parse("2017-06-02"), Open = 230.97m, High = 231.86m, Low = 230.65m, Close = 231.69m, Volume = 93444032 }, - new() { Date = DateTime.Parse("2017-06-01"), Open = 229.60m, High = 230.94m, Low = 229.28m, Close = 230.92m, Volume = 72678144 }, - new() { Date = DateTime.Parse("2017-05-31"), Open = 229.47m, High = 229.51m, Low = 228.34m, Close = 229.09m, Volume = 96742576 }, - new() { Date = DateTime.Parse("2017-05-30"), Open = 229.00m, High = 229.43m, Low = 228.83m, Close = 229.15m, Volume = 37098796 }, - new() { Date = DateTime.Parse("2017-05-26"), Open = 229.19m, High = 229.53m, Low = 229.10m, Close = 229.35m, Volume = 49142620 }, - new() { Date = DateTime.Parse("2017-05-25"), Open = 228.87m, High = 229.70m, Low = 228.64m, Close = 229.40m, Volume = 67524256 }, - new() { Date = DateTime.Parse("2017-05-24"), Open = 228.03m, High = 228.42m, Low = 227.66m, Close = 228.31m, Volume = 51831288 }, - new() { Date = DateTime.Parse("2017-05-23"), Open = 227.68m, High = 227.96m, Low = 227.26m, Close = 227.78m, Volume = 50946640 }, - new() { Date = DateTime.Parse("2017-05-22"), Open = 226.68m, High = 227.45m, Low = 226.61m, Close = 227.27m, Volume = 64298244 }, - new() { Date = DateTime.Parse("2017-05-19"), Open = 225.20m, High = 226.86m, Low = 225.14m, Close = 226.12m, Volume = 121208928 }, - new() { Date = DateTime.Parse("2017-05-18"), Open = 223.68m, High = 225.59m, Low = 223.39m, Close = 224.66m, Volume = 112816072 }, - new() { Date = DateTime.Parse("2017-05-17"), Open = 225.93m, High = 226.44m, Low = 223.70m, Close = 223.76m, Volume = 181451968 }, - new() { Date = DateTime.Parse("2017-05-16"), Open = 228.34m, High = 228.36m, Low = 227.38m, Close = 227.80m, Volume = 54003024 }, - new() { Date = DateTime.Parse("2017-05-15"), Open = 227.23m, High = 228.15m, Low = 227.21m, Close = 228.01m, Volume = 65255528 }, - new() { Date = DateTime.Parse("2017-05-12"), Open = 226.87m, High = 227.19m, Low = 226.47m, Close = 226.76m, Volume = 56817892 }, - new() { Date = DateTime.Parse("2017-05-11"), Open = 227.11m, High = 227.32m, Low = 225.95m, Close = 227.14m, Volume = 65718612 }, - new() { Date = DateTime.Parse("2017-05-10"), Open = 227.15m, High = 227.61m, Low = 226.92m, Close = 227.61m, Volume = 57219496 }, - new() { Date = DateTime.Parse("2017-05-09"), Open = 227.69m, High = 227.91m, Low = 226.82m, Close = 227.20m, Volume = 54130976 }, - new() { Date = DateTime.Parse("2017-05-08"), Open = 227.49m, High = 227.65m, Low = 226.94m, Close = 227.41m, Volume = 50993060 }, - new() { Date = DateTime.Parse("2017-05-05"), Open = 226.96m, High = 227.46m, Low = 226.48m, Close = 227.44m, Volume = 65342296 }, - new() { Date = DateTime.Parse("2017-05-04"), Open = 226.62m, High = 226.71m, Low = 225.62m, Close = 226.55m, Volume = 64774736 }, - new() { Date = DateTime.Parse("2017-05-03"), Open = 226.11m, High = 226.66m, Low = 225.55m, Close = 226.29m, Volume = 77078864 }, - new() { Date = DateTime.Parse("2017-05-02"), Open = 226.63m, High = 226.76m, Low = 226.12m, Close = 226.56m, Volume = 60467504 }, - new() { Date = DateTime.Parse("2017-05-01"), Open = 226.48m, High = 226.94m, Low = 226.02m, Close = 226.48m, Volume = 70486576 }, - new() { Date = DateTime.Parse("2017-04-28"), Open = 226.68m, High = 226.71m, Low = 225.76m, Close = 225.91m, Volume = 66956400 }, - new() { Date = DateTime.Parse("2017-04-27"), Open = 226.56m, High = 226.73m, Low = 225.81m, Close = 226.40m, Volume = 60503960 }, - new() { Date = DateTime.Parse("2017-04-26"), Open = 226.31m, High = 227.28m, Low = 226.16m, Close = 226.21m, Volume = 89266768 }, - new() { Date = DateTime.Parse("2017-04-25"), Open = 225.75m, High = 226.73m, Low = 225.65m, Close = 226.35m, Volume = 80831256 }, - new() { Date = DateTime.Parse("2017-04-24"), Open = 225.05m, High = 225.27m, Low = 222.57m, Close = 225.04m, Volume = 125633672 }, - new() { Date = DateTime.Parse("2017-04-21"), Open = 223.22m, High = 223.28m, Low = 222.16m, Close = 222.60m, Volume = 116338368 }, - new() { Date = DateTime.Parse("2017-04-20"), Open = 222.18m, High = 223.79m, Low = 221.83m, Close = 223.31m, Volume = 97560568 }, - new() { Date = DateTime.Parse("2017-04-19"), Open = 222.53m, High = 222.94m, Low = 221.26m, Close = 221.50m, Volume = 72401856 }, - new() { Date = DateTime.Parse("2017-04-18"), Open = 221.77m, High = 222.50m, Low = 221.16m, Close = 221.91m, Volume = 87710560 }, - new() { Date = DateTime.Parse("2017-04-17"), Open = 221.19m, High = 222.58m, Low = 220.97m, Close = 222.58m, Volume = 72091488 }, - new() { Date = DateTime.Parse("2017-04-13"), Open = 221.69m, High = 222.50m, Low = 220.62m, Close = 220.62m, Volume = 97885392 }, - new() { Date = DateTime.Parse("2017-04-12"), Open = 222.74m, High = 222.95m, Low = 221.82m, Close = 222.06m, Volume = 86275816 }, - new() { Date = DateTime.Parse("2017-04-11"), Open = 222.89m, High = 223.15m, Low = 221.41m, Close = 223.04m, Volume = 92789720 }, - new() { Date = DateTime.Parse("2017-04-10"), Open = 223.33m, High = 224.18m, Low = 222.73m, Close = 223.31m, Volume = 71258848 }, - new() { Date = DateTime.Parse("2017-04-07"), Open = 223.13m, High = 223.93m, Low = 222.64m, Close = 223.17m, Volume = 78422128 }, - new() { Date = DateTime.Parse("2017-04-06"), Open = 222.93m, High = 223.97m, Low = 222.44m, Close = 223.40m, Volume = 72861232 }, - new() { Date = DateTime.Parse("2017-04-05"), Open = 224.18m, High = 225.25m, Low = 222.55m, Close = 222.78m, Volume = 114663488 }, - new() { Date = DateTime.Parse("2017-04-04"), Open = 222.98m, High = 223.53m, Low = 222.56m, Close = 223.44m, Volume = 59508952 }, - new() { Date = DateTime.Parse("2017-04-03"), Open = 223.74m, High = 223.96m, Low = 221.95m, Close = 223.30m, Volume = 90156280 }, - new() { Date = DateTime.Parse("2017-03-31"), Open = 223.84m, High = 224.42m, Low = 223.63m, Close = 223.69m, Volume = 77706304 }, - new() { Date = DateTime.Parse("2017-03-30"), Open = 223.43m, High = 224.43m, Low = 223.24m, Close = 224.21m, Volume = 59795288 }, - new() { Date = DateTime.Parse("2017-03-29"), Open = 222.97m, High = 223.75m, Low = 222.72m, Close = 223.50m, Volume = 65288636 }, - new() { Date = DateTime.Parse("2017-03-28"), Open = 221.34m, High = 223.75m, Low = 221.22m, Close = 223.29m, Volume = 98521432 }, - new() { Date = DateTime.Parse("2017-03-27"), Open = 220.07m, High = 221.96m, Low = 219.77m, Close = 221.67m, Volume = 92167056 }, - new() { Date = DateTime.Parse("2017-03-24"), Open = 222.40m, High = 223.02m, Low = 221.05m, Close = 221.90m, Volume = 118567344 }, - new() { Date = DateTime.Parse("2017-03-23"), Open = 222.04m, High = 223.31m, Low = 221.66m, Close = 222.06m, Volume = 105821032 }, - new() { Date = DateTime.Parse("2017-03-22"), Open = 221.82m, High = 222.61m, Low = 221.13m, Close = 222.30m, Volume = 102826864 }, - new() { Date = DateTime.Parse("2017-03-21"), Open = 225.33m, High = 225.46m, Low = 221.64m, Close = 221.78m, Volume = 138912016 }, - new() { Date = DateTime.Parse("2017-03-20"), Open = 224.91m, High = 225.22m, Low = 224.24m, Close = 224.66m, Volume = 55368008 }, - new() { Date = DateTime.Parse("2017-03-17"), Open = 225.59m, High = 225.80m, Low = 224.91m, Close = 224.91m, Volume = 93798120 }, - new() { Date = DateTime.Parse("2017-03-16"), Open = 225.90m, High = 225.99m, Low = 224.95m, Close = 225.31m, Volume = 82924856 }, - new() { Date = DateTime.Parse("2017-03-15"), Open = 224.44m, High = 226.21m, Low = 224.18m, Close = 225.75m, Volume = 101699816 }, - new() { Date = DateTime.Parse("2017-03-14"), Open = 224.08m, High = 224.13m, Low = 223.14m, Close = 223.81m, Volume = 63382108 }, - new() { Date = DateTime.Parse("2017-03-13"), Open = 224.49m, High = 224.72m, Low = 224.13m, Close = 224.67m, Volume = 60604724 }, - new() { Date = DateTime.Parse("2017-03-10"), Open = 224.82m, High = 224.87m, Low = 223.52m, Close = 224.56m, Volume = 86785840 }, - new() { Date = DateTime.Parse("2017-03-09"), Open = 223.62m, High = 224.13m, Low = 222.72m, Close = 223.78m, Volume = 95986360 }, - new() { Date = DateTime.Parse("2017-03-08"), Open = 224.23m, High = 224.51m, Low = 223.34m, Close = 223.49m, Volume = 82739456 }, - new() { Date = DateTime.Parse("2017-03-07"), Open = 224.25m, High = 224.64m, Low = 223.68m, Close = 223.91m, Volume = 68910464 }, - new() { Date = DateTime.Parse("2017-03-06"), Open = 224.38m, High = 224.97m, Low = 223.92m, Close = 224.58m, Volume = 58630368 }, - new() { Date = DateTime.Parse("2017-03-03"), Open = 225.01m, High = 225.43m, Low = 224.60m, Close = 225.25m, Volume = 86767480 }, - new() { Date = DateTime.Parse("2017-03-02"), Open = 226.33m, High = 226.34m, Low = 225.05m, Close = 225.11m, Volume = 74353376 }, - new() { Date = DateTime.Parse("2017-03-01"), Open = 225.22m, High = 227.04m, Low = 225.20m, Close = 226.53m, Volume = 157879712 }, - new() { Date = DateTime.Parse("2017-02-28"), Open = 223.60m, High = 223.86m, Low = 222.98m, Close = 223.41m, Volume = 102631472 }, - new() { Date = DateTime.Parse("2017-02-27"), Open = 223.57m, High = 224.20m, Low = 223.29m, Close = 224.01m, Volume = 59819992 }, - new() { Date = DateTime.Parse("2017-02-24"), Open = 222.45m, High = 223.71m, Low = 222.41m, Close = 223.66m, Volume = 87198608 }, - new() { Date = DateTime.Parse("2017-02-23"), Open = 223.79m, High = 223.81m, Low = 222.55m, Close = 223.38m, Volume = 78978816 }, - new() { Date = DateTime.Parse("2017-02-22"), Open = 222.98m, High = 223.47m, Low = 222.80m, Close = 223.23m, Volume = 65747160 }, - new() { Date = DateTime.Parse("2017-02-21"), Open = 222.51m, High = 223.62m, Low = 222.50m, Close = 223.43m, Volume = 94146880 }, - new() { Date = DateTime.Parse("2017-02-17"), Open = 221.03m, High = 222.10m, Low = 221.01m, Close = 222.10m, Volume = 81718352 }, - new() { Date = DateTime.Parse("2017-02-16"), Open = 221.98m, High = 222.16m, Low = 220.93m, Close = 221.75m, Volume = 89676304 }, - new() { Date = DateTime.Parse("2017-02-15"), Open = 220.55m, High = 222.15m, Low = 220.50m, Close = 221.94m, Volume = 91860344 }, - new() { Date = DateTime.Parse("2017-02-14"), Open = 219.71m, High = 220.80m, Low = 219.33m, Close = 220.79m, Volume = 75266840 }, - new() { Date = DateTime.Parse("2017-02-13"), Open = 219.26m, High = 220.19m, Low = 219.23m, Close = 219.91m, Volume = 58408632 }, - new() { Date = DateTime.Parse("2017-02-10"), Open = 218.24m, High = 218.97m, Low = 217.88m, Close = 218.72m, Volume = 69875952 }, - new() { Date = DateTime.Parse("2017-02-09"), Open = 216.88m, High = 218.19m, Low = 216.84m, Close = 217.86m, Volume = 69811760 }, - new() { Date = DateTime.Parse("2017-02-08"), Open = 215.98m, High = 216.72m, Low = 215.70m, Close = 216.58m, Volume = 54581376 }, - new() { Date = DateTime.Parse("2017-02-07"), Open = 216.71m, High = 216.97m, Low = 216.09m, Close = 216.29m, Volume = 61318484 }, - new() { Date = DateTime.Parse("2017-02-06"), Open = 216.23m, High = 216.66m, Low = 215.92m, Close = 216.28m, Volume = 61169192 }, - new() { Date = DateTime.Parse("2017-02-03"), Open = 216.18m, High = 216.87m, Low = 215.84m, Close = 216.67m, Volume = 85273832 }, - new() { Date = DateTime.Parse("2017-02-02"), Open = 214.65m, High = 215.50m, Low = 214.29m, Close = 215.19m, Volume = 73730552 }, - new() { Date = DateTime.Parse("2017-02-01"), Open = 215.65m, High = 215.96m, Low = 214.40m, Close = 215.05m, Volume = 83743792 }, - new() { Date = DateTime.Parse("2017-01-31"), Open = 214.44m, High = 215.03m, Low = 213.82m, Close = 214.96m, Volume = 80317680 }, - new() { Date = DateTime.Parse("2017-01-30"), Open = 215.57m, High = 215.59m, Low = 213.90m, Close = 214.98m, Volume = 84399624 }, - new() { Date = DateTime.Parse("2017-01-27"), Open = 216.75m, High = 216.91m, Low = 216.12m, Close = 216.32m, Volume = 63202528 }, - new() { Date = DateTime.Parse("2017-01-26"), Open = 216.73m, High = 217.02m, Low = 216.36m, Close = 216.66m, Volume = 63477304 }, - new() { Date = DateTime.Parse("2017-01-25"), Open = 216.07m, High = 216.89m, Low = 215.89m, Close = 216.89m, Volume = 89374928 }, - new() { Date = DateTime.Parse("2017-01-24"), Open = 213.89m, High = 215.48m, Low = 213.77m, Close = 215.03m, Volume = 101142584 }, - new() { Date = DateTime.Parse("2017-01-23"), Open = 213.85m, High = 214.28m, Low = 212.83m, Close = 213.66m, Volume = 79450624 }, - new() { Date = DateTime.Parse("2017-01-20"), Open = 214.18m, High = 214.75m, Low = 213.49m, Close = 214.21m, Volume = 136721344 }, - new() { Date = DateTime.Parse("2017-01-19"), Open = 214.31m, High = 214.46m, Low = 212.96m, Close = 213.43m, Volume = 70503512 }, - new() { Date = DateTime.Parse("2017-01-18"), Open = 214.02m, High = 214.27m, Low = 213.42m, Close = 214.22m, Volume = 57997156 }, - new() { Date = DateTime.Parse("2017-01-17"), Open = 213.81m, High = 214.25m, Low = 213.33m, Close = 213.75m, Volume = 64821664 }, - new() { Date = DateTime.Parse("2017-01-13"), Open = 214.21m, High = 214.84m, Low = 214.17m, Close = 214.51m, Volume = 66385084 }, - new() { Date = DateTime.Parse("2017-01-12"), Open = 213.99m, High = 214.22m, Low = 212.53m, Close = 214.02m, Volume = 76329760 }, - new() { Date = DateTime.Parse("2017-01-11"), Open = 213.86m, High = 214.55m, Low = 213.13m, Close = 214.55m, Volume = 79014928 }, - new() { Date = DateTime.Parse("2017-01-10"), Open = 213.97m, High = 214.89m, Low = 213.52m, Close = 213.95m, Volume = 67500792 }, - new() { Date = DateTime.Parse("2017-01-09"), Open = 214.38m, High = 214.53m, Low = 213.91m, Close = 213.95m, Volume = 49684316 }, - new() { Date = DateTime.Parse("2017-01-06"), Open = 214.02m, High = 215.17m, Low = 213.42m, Close = 214.66m, Volume = 75744152 }, - new() { Date = DateTime.Parse("2017-01-05"), Open = 213.77m, High = 214.06m, Low = 213.02m, Close = 213.89m, Volume = 82961968 }, - new() { Date = DateTime.Parse("2017-01-04"), Open = 213.16m, High = 214.22m, Low = 213.15m, Close = 214.06m, Volume = 83348752 }, - new() { Date = DateTime.Parse("2017-01-03"), Open = 212.61m, High = 213.35m, Low = 211.52m, Close = 212.80m, Volume = 96708880 }, - new() { Date = DateTime.Parse("2017-01-02"), Open = 212.61m, High = 213.35m, Low = 211.52m, Close = 212.00m, Volume = 76708880 }, - new() { Date = DateTime.Parse("2017-01-01"), Open = 212.61m, High = 213.35m, Low = 211.52m, Close = 211.60m, Volume = 86708880 }, + new Quote(DateTime.Parse("2018-12-31"), 244.92m, 245.54m, 242.87m, 245.28m, 147031456), + new Quote(DateTime.Parse("2018-12-28"), 244.94m, 246.73m, 241.87m, 243.15m, 155998912), + new Quote(DateTime.Parse("2018-12-27"), 238.06m, 243.68m, 234.52m, 243.46m, 189794032), + new Quote(DateTime.Parse("2018-12-26"), 231.59m, 241.61m, 229.42m, 241.61m, 222622048), + new Quote(DateTime.Parse("2018-12-24"), 234.60m, 236.36m, 229.92m, 229.99m, 150100704), + new Quote(DateTime.Parse("2018-12-21"), 242.16m, 245.07m, 235.52m, 236.23m, 260180208), + new Quote(DateTime.Parse("2018-12-20"), 243.79m, 245.51m, 238.71m, 241.17m, 258325808), + new Quote(DateTime.Parse("2018-12-19"), 248.97m, 253.10m, 243.30m, 245.16m, 220342928), + new Quote(DateTime.Parse("2018-12-18"), 250.95m, 251.69m, 247.13m, 248.89m, 137862544), + new Quote(DateTime.Parse("2018-12-17"), 253.10m, 254.32m, 247.37m, 249.16m, 169610592), + new Quote(DateTime.Parse("2018-12-14"), 256.58m, 257.62m, 253.54m, 254.15m, 119871688), + new Quote(DateTime.Parse("2018-12-13"), 260.05m, 260.99m, 257.71m, 258.93m, 99068200), + new Quote(DateTime.Parse("2018-12-12"), 260.98m, 262.47m, 258.93m, 259.01m, 100414888), + new Quote(DateTime.Parse("2018-12-11"), 261.16m, 261.37m, 256.11m, 257.72m, 124528112), + new Quote(DateTime.Parse("2018-12-10"), 256.98m, 258.72m, 252.34m, 257.66m, 155214672), + new Quote(DateTime.Parse("2018-12-07"), 262.92m, 264.63m, 256.25m, 257.17m, 165025936), + new Quote(DateTime.Parse("2018-12-06"), 259.46m, 263.41m, 256.07m, 263.29m, 209266640), + new Quote(DateTime.Parse("2018-12-04"), 271.61m, 272.08m, 263.35m, 263.69m, 182415248), + new Quote(DateTime.Parse("2018-12-03"), 273.47m, 273.59m, 270.77m, 272.52m, 105581352), + new Quote(DateTime.Parse("2018-11-30"), 267.16m, 269.57m, 266.81m, 268.96m, 100648032), + new Quote(DateTime.Parse("2018-11-29"), 267.06m, 268.86m, 265.82m, 267.33m, 84395640), + new Quote(DateTime.Parse("2018-11-28"), 263.05m, 267.91m, 261.81m, 267.91m, 130805744), + new Quote(DateTime.Parse("2018-11-27"), 259.87m, 261.88m, 259.21m, 261.88m, 77381344), + new Quote(DateTime.Parse("2018-11-26"), 259.33m, 261.25m, 258.90m, 261.00m, 81971728), + new Quote(DateTime.Parse("2018-11-23"), 256.79m, 258.39m, 256.68m, 256.86m, 43873168), + new Quote(DateTime.Parse("2018-11-21"), 259.40m, 260.66m, 258.58m, 258.58m, 77444168), + new Quote(DateTime.Parse("2018-11-20"), 258.92m, 260.52m, 256.76m, 257.71m, 139406240), + new Quote(DateTime.Parse("2018-11-19"), 266.42m, 266.74m, 261.56m, 262.57m, 105626432), + new Quote(DateTime.Parse("2018-11-16"), 265.19m, 268.08m, 264.62m, 267.08m, 129820216), + new Quote(DateTime.Parse("2018-11-15"), 262.25m, 266.90m, 260.53m, 266.39m, 138463488), + new Quote(DateTime.Parse("2018-11-14"), 267.50m, 267.94m, 261.93m, 263.64m, 128454960), + new Quote(DateTime.Parse("2018-11-13"), 266.46m, 268.64m, 264.66m, 265.45m, 100619768), + new Quote(DateTime.Parse("2018-11-12"), 270.46m, 270.72m, 265.39m, 265.95m, 102153984), + new Quote(DateTime.Parse("2018-11-09"), 272.25m, 272.46m, 269.47m, 271.02m, 101271544), + new Quote(DateTime.Parse("2018-11-08"), 273.31m, 274.39m, 272.44m, 273.69m, 67216992), + new Quote(DateTime.Parse("2018-11-07"), 270.82m, 274.27m, 270.35m, 274.19m, 105309120), + new Quote(DateTime.Parse("2018-11-06"), 266.68m, 268.62m, 266.62m, 268.44m, 61581152), + new Quote(DateTime.Parse("2018-11-05"), 265.82m, 267.36m, 264.76m, 266.75m, 67255520), + new Quote(DateTime.Parse("2018-11-02"), 268.08m, 268.55m, 263.04m, 265.29m, 125685896), + new Quote(DateTime.Parse("2018-11-01"), 265.01m, 267.08m, 263.81m, 266.87m, 101971008), + new Quote(DateTime.Parse("2018-10-31"), 264.08m, 266.60m, 263.56m, 264.06m, 131489024), + new Quote(DateTime.Parse("2018-10-30"), 257.27m, 261.61m, 256.73m, 261.27m, 161025888), + new Quote(DateTime.Parse("2018-10-29"), 262.27m, 263.69m, 253.54m, 257.45m, 164749392), + new Quote(DateTime.Parse("2018-10-26"), 259.46m, 264.42m, 255.92m, 258.89m, 206590848), + new Quote(DateTime.Parse("2018-10-25"), 260.89m, 265.21m, 259.77m, 263.52m, 141497248), + new Quote(DateTime.Parse("2018-10-24"), 266.69m, 267.11m, 258.27m, 258.88m, 182231472), + new Quote(DateTime.Parse("2018-10-23"), 264.37m, 268.20m, 262.09m, 266.97m, 149994752), + new Quote(DateTime.Parse("2018-10-22"), 270.27m, 270.63m, 267.75m, 268.33m, 84466760), + new Quote(DateTime.Parse("2018-10-19"), 270.40m, 272.52m, 268.78m, 269.54m, 143383136), + new Quote(DateTime.Parse("2018-10-18"), 272.62m, 273.27m, 268.29m, 269.69m, 137906032), + new Quote(DateTime.Parse("2018-10-17"), 273.63m, 274.32m, 270.82m, 273.64m, 113378952), + new Quote(DateTime.Parse("2018-10-16"), 269.88m, 274.00m, 269.37m, 273.59m, 121198672), + new Quote(DateTime.Parse("2018-10-15"), 268.86m, 270.31m, 267.64m, 267.74m, 104808584), + new Quote(DateTime.Parse("2018-10-12"), 270.05m, 270.36m, 265.76m, 269.25m, 187745152), + new Quote(DateTime.Parse("2018-10-11"), 270.35m, 272.13m, 263.80m, 265.56m, 281680000), + new Quote(DateTime.Parse("2018-10-10"), 279.87m, 279.94m, 271.13m, 271.54m, 220074688), + new Quote(DateTime.Parse("2018-10-09"), 280.41m, 281.85m, 279.81m, 280.42m, 76188928), + new Quote(DateTime.Parse("2018-10-08"), 280.08m, 281.22m, 278.57m, 280.83m, 89925664), + new Quote(DateTime.Parse("2018-10-05"), 282.66m, 283.22m, 279.27m, 280.83m, 108588344), + new Quote(DateTime.Parse("2018-10-04"), 284.11m, 284.17m, 280.68m, 282.41m, 114321768), + new Quote(DateTime.Parse("2018-10-03"), 285.63m, 286.09m, 284.25m, 284.64m, 66304540), + new Quote(DateTime.Parse("2018-10-02"), 284.48m, 285.26m, 284.07m, 284.48m, 48434264), + new Quote(DateTime.Parse("2018-10-01"), 285.02m, 285.82m, 283.91m, 284.65m, 63623792), + new Quote(DateTime.Parse("2018-09-28"), 282.95m, 284.21m, 282.91m, 283.66m, 71835632), + new Quote(DateTime.Parse("2018-09-27"), 283.36m, 284.82m, 283.06m, 283.63m, 60723896), + new Quote(DateTime.Parse("2018-09-26"), 283.85m, 285.14m, 282.38m, 282.84m, 81724024), + new Quote(DateTime.Parse("2018-09-25"), 284.45m, 284.57m, 283.43m, 283.69m, 45474200), + new Quote(DateTime.Parse("2018-09-24"), 284.27m, 284.42m, 283.32m, 283.95m, 54738760), + new Quote(DateTime.Parse("2018-09-21"), 285.97m, 286.10m, 284.72m, 284.90m, 108104552), + new Quote(DateTime.Parse("2018-09-20"), 284.25m, 285.51m, 282.88m, 285.16m, 103323632), + new Quote(DateTime.Parse("2018-09-19"), 282.63m, 283.33m, 282.48m, 282.87m, 50529584), + new Quote(DateTime.Parse("2018-09-18"), 281.28m, 283.22m, 281.25m, 282.57m, 63758804), + new Quote(DateTime.Parse("2018-09-17"), 282.48m, 282.52m, 280.74m, 281.04m, 70258840), + new Quote(DateTime.Parse("2018-09-14"), 282.71m, 282.92m, 281.68m, 282.54m, 56706020), + new Quote(DateTime.Parse("2018-09-13"), 281.99m, 282.69m, 281.68m, 282.49m, 52540928), + new Quote(DateTime.Parse("2018-09-12"), 280.77m, 281.49m, 279.96m, 280.83m, 61576576), + new Quote(DateTime.Parse("2018-09-11"), 279.13m, 281.25m, 278.75m, 280.76m, 52022324), + new Quote(DateTime.Parse("2018-09-10"), 280.46m, 280.75m, 279.62m, 279.84m, 51693300), + new Quote(DateTime.Parse("2018-09-07"), 278.75m, 280.42m, 278.49m, 279.35m, 75695528), + new Quote(DateTime.Parse("2018-09-06"), 280.86m, 281.19m, 278.77m, 279.90m, 67855744), + new Quote(DateTime.Parse("2018-09-05"), 281.11m, 281.33m, 279.63m, 280.74m, 74591480), + new Quote(DateTime.Parse("2018-09-04"), 281.53m, 281.89m, 280.40m, 281.50m, 59294748), + new Quote(DateTime.Parse("2018-08-31"), 281.53m, 282.47m, 280.99m, 281.98m, 68093544), + new Quote(DateTime.Parse("2018-08-30"), 282.60m, 283.00m, 281.32m, 281.98m, 63037208), + new Quote(DateTime.Parse("2018-08-29"), 281.84m, 283.37m, 281.57m, 283.12m, 63300776), + new Quote(DateTime.Parse("2018-08-28"), 281.98m, 282.09m, 281.10m, 281.61m, 48329404), + new Quote(DateTime.Parse("2018-08-27"), 280.58m, 281.59m, 280.40m, 281.47m, 58757348), + new Quote(DateTime.Parse("2018-08-24"), 278.23m, 279.42m, 278.17m, 279.27m, 59184624), + new Quote(DateTime.Parse("2018-08-23"), 277.77m, 278.71m, 277.24m, 277.59m, 50657548), + new Quote(DateTime.Parse("2018-08-22"), 277.68m, 278.54m, 277.39m, 277.96m, 46321688), + new Quote(DateTime.Parse("2018-08-21"), 278.04m, 279.07m, 277.52m, 278.13m, 69258080), + new Quote(DateTime.Parse("2018-08-20"), 277.38m, 277.77m, 276.89m, 277.48m, 40982744), + new Quote(DateTime.Parse("2018-08-17"), 275.69m, 277.37m, 275.24m, 276.89m, 67555760), + new Quote(DateTime.Parse("2018-08-16"), 275.27m, 276.87m, 275.23m, 275.91m, 72033608), + new Quote(DateTime.Parse("2018-08-15"), 274.28m, 274.44m, 272.13m, 273.70m, 105964064), + new Quote(DateTime.Parse("2018-08-14"), 274.81m, 276.02m, 274.38m, 275.76m, 45136396), + new Quote(DateTime.Parse("2018-08-13"), 275.34m, 276.01m, 273.69m, 274.01m, 67673568), + new Quote(DateTime.Parse("2018-08-10"), 275.32m, 275.91m, 274.26m, 275.04m, 79351592), + new Quote(DateTime.Parse("2018-08-09"), 277.34m, 277.77m, 276.74m, 276.90m, 36771464), + new Quote(DateTime.Parse("2018-08-08"), 277.21m, 277.71m, 276.77m, 277.27m, 43357916), + new Quote(DateTime.Parse("2018-08-07"), 277.21m, 277.81m, 277.06m, 277.39m, 44471960), + new Quote(DateTime.Parse("2018-08-06"), 275.51m, 276.82m, 275.08m, 276.48m, 40564136), + new Quote(DateTime.Parse("2018-08-03"), 274.43m, 275.52m, 274.23m, 275.47m, 55527740), + new Quote(DateTime.Parse("2018-08-02"), 271.38m, 274.48m, 271.15m, 274.29m, 65298924), + new Quote(DateTime.Parse("2018-08-01"), 273.49m, 274.04m, 272.10m, 272.81m, 55443260), + new Quote(DateTime.Parse("2018-07-31"), 272.76m, 273.93m, 272.34m, 273.26m, 70594928), + new Quote(DateTime.Parse("2018-07-30"), 273.44m, 273.61m, 271.35m, 271.92m, 65624404), + new Quote(DateTime.Parse("2018-07-27"), 275.57m, 275.68m, 272.34m, 273.35m, 79050080), + new Quote(DateTime.Parse("2018-07-26"), 275.08m, 275.96m, 274.97m, 275.21m, 59629476), + new Quote(DateTime.Parse("2018-07-25"), 273.26m, 276.22m, 273.21m, 275.87m, 81211824), + new Quote(DateTime.Parse("2018-07-24"), 273.71m, 274.46m, 272.58m, 273.53m, 70035320), + new Quote(DateTime.Parse("2018-07-23"), 271.44m, 272.39m, 271.06m, 272.16m, 48436568), + new Quote(DateTime.Parse("2018-07-20"), 271.75m, 272.44m, 271.48m, 271.66m, 84804656), + new Quote(DateTime.Parse("2018-07-19"), 272.27m, 272.69m, 271.45m, 271.97m, 63225212), + new Quote(DateTime.Parse("2018-07-18"), 272.51m, 273.12m, 272.03m, 273.00m, 45910016), + new Quote(DateTime.Parse("2018-07-17"), 270.48m, 272.85m, 270.43m, 272.43m, 53860032), + new Quote(DateTime.Parse("2018-07-16"), 271.62m, 271.78m, 270.84m, 271.33m, 49624096), + new Quote(DateTime.Parse("2018-07-13"), 271.16m, 271.90m, 270.67m, 271.57m, 49659024), + new Quote(DateTime.Parse("2018-07-12"), 270.30m, 271.42m, 269.64m, 271.36m, 61899772), + new Quote(DateTime.Parse("2018-07-11"), 269.20m, 270.07m, 268.59m, 268.92m, 79329656), + new Quote(DateTime.Parse("2018-07-10"), 270.43m, 271.01m, 270.11m, 270.90m, 53501064), + new Quote(DateTime.Parse("2018-07-09"), 268.62m, 269.99m, 268.57m, 269.93m, 52042820), + new Quote(DateTime.Parse("2018-07-06"), 265.31m, 267.93m, 264.89m, 267.52m, 68456816), + new Quote(DateTime.Parse("2018-07-05"), 264.36m, 265.35m, 263.19m, 265.28m, 58606568), + new Quote(DateTime.Parse("2018-07-03"), 265.05m, 265.15m, 262.67m, 263.13m, 43432576), + new Quote(DateTime.Parse("2018-07-02"), 261.78m, 264.24m, 261.52m, 264.06m, 65431128), + new Quote(DateTime.Parse("2018-06-29"), 264.32m, 265.81m, 263.37m, 263.50m, 100473760), + new Quote(DateTime.Parse("2018-06-28"), 261.57m, 263.96m, 260.79m, 263.12m, 78913504), + new Quote(DateTime.Parse("2018-06-27"), 264.45m, 266.01m, 261.46m, 261.63m, 108213904), + new Quote(DateTime.Parse("2018-06-26"), 263.85m, 264.74m, 263.02m, 263.81m, 70710976), + new Quote(DateTime.Parse("2018-06-25"), 265.60m, 265.77m, 261.38m, 263.23m, 141924096), + new Quote(DateTime.Parse("2018-06-22"), 267.76m, 267.88m, 266.62m, 266.86m, 58283384), + new Quote(DateTime.Parse("2018-06-21"), 268.05m, 268.07m, 265.83m, 266.38m, 73159376), + new Quote(DateTime.Parse("2018-06-20"), 268.35m, 268.78m, 267.69m, 268.06m, 55373416), + new Quote(DateTime.Parse("2018-06-19"), 266.14m, 267.84m, 265.69m, 267.60m, 100410976), + new Quote(DateTime.Parse("2018-06-18"), 267.59m, 268.77m, 267.07m, 268.63m, 54479888), + new Quote(DateTime.Parse("2018-06-15"), 268.67m, 269.55m, 267.45m, 269.18m, 123585600), + new Quote(DateTime.Parse("2018-06-14"), 269.80m, 270.11m, 268.88m, 269.53m, 79730104), + new Quote(DateTime.Parse("2018-06-13"), 269.97m, 270.25m, 268.63m, 268.85m, 81770464), + new Quote(DateTime.Parse("2018-06-12"), 269.82m, 270.11m, 269.00m, 269.71m, 74798688), + new Quote(DateTime.Parse("2018-06-11"), 269.25m, 270.15m, 269.12m, 269.36m, 60903392), + new Quote(DateTime.Parse("2018-06-08"), 267.71m, 269.06m, 267.53m, 269.00m, 74602920), + new Quote(DateTime.Parse("2018-06-07"), 268.77m, 269.09m, 267.22m, 268.21m, 75460928), + new Quote(DateTime.Parse("2018-06-06"), 266.68m, 268.36m, 266.01m, 268.24m, 64874192), + new Quote(DateTime.Parse("2018-06-05"), 265.97m, 266.43m, 265.13m, 266.02m, 52881036), + new Quote(DateTime.Parse("2018-06-04"), 265.47m, 266.10m, 265.20m, 265.82m, 46934832), + new Quote(DateTime.Parse("2018-06-01"), 263.42m, 264.90m, 263.34m, 264.57m, 73691520), + new Quote(DateTime.Parse("2018-05-31"), 263.16m, 263.49m, 261.33m, 261.99m, 96713160), + new Quote(DateTime.Parse("2018-05-30"), 261.57m, 264.09m, 261.49m, 263.61m, 72057608), + new Quote(DateTime.Parse("2018-05-29"), 261.39m, 262.22m, 258.92m, 260.14m, 119866288), + new Quote(DateTime.Parse("2018-05-25"), 263.16m, 263.85m, 262.61m, 263.16m, 58299660), + new Quote(DateTime.Parse("2018-05-24"), 263.90m, 264.20m, 261.84m, 263.79m, 78640328), + new Quote(DateTime.Parse("2018-05-23"), 262.22m, 264.36m, 262.04m, 264.33m, 66903156), + new Quote(DateTime.Parse("2018-05-22"), 264.91m, 265.20m, 263.25m, 263.61m, 54774884), + new Quote(DateTime.Parse("2018-05-21"), 264.00m, 264.93m, 262.39m, 264.34m, 60007156), + new Quote(DateTime.Parse("2018-05-18"), 262.65m, 263.05m, 261.98m, 262.37m, 66565792), + new Quote(DateTime.Parse("2018-05-17"), 262.96m, 264.21m, 262.18m, 263.03m, 58466824), + new Quote(DateTime.Parse("2018-05-16"), 262.19m, 263.75m, 262.16m, 263.25m, 55784492), + new Quote(DateTime.Parse("2018-05-15"), 262.62m, 262.64m, 261.11m, 262.15m, 90007968), + new Quote(DateTime.Parse("2018-05-14"), 264.31m, 265.03m, 263.37m, 263.97m, 56661420), + new Quote(DateTime.Parse("2018-05-11"), 263.17m, 264.13m, 262.61m, 263.84m, 61915812), + new Quote(DateTime.Parse("2018-05-10"), 261.41m, 263.40m, 261.30m, 263.04m, 74524544), + new Quote(DateTime.Parse("2018-05-09"), 258.84m, 260.95m, 258.27m, 260.60m, 61703432), + new Quote(DateTime.Parse("2018-05-08"), 257.70m, 258.50m, 256.40m, 258.11m, 69804000), + new Quote(DateTime.Parse("2018-05-07"), 258.08m, 259.17m, 257.32m, 258.11m, 57193284), + new Quote(DateTime.Parse("2018-05-04"), 252.89m, 257.98m, 252.53m, 257.24m, 94336840), + new Quote(DateTime.Parse("2018-05-03"), 253.60m, 254.66m, 250.50m, 253.95m, 140965808), + new Quote(DateTime.Parse("2018-05-02"), 256.02m, 256.91m, 254.08m, 254.51m, 89317992), + new Quote(DateTime.Parse("2018-05-01"), 255.16m, 256.35m, 253.46m, 256.23m, 76737024), + new Quote(DateTime.Parse("2018-04-30"), 258.44m, 259.04m, 255.70m, 255.78m, 84988424), + new Quote(DateTime.Parse("2018-04-27"), 258.18m, 258.51m, 256.73m, 257.76m, 59001736), + new Quote(DateTime.Parse("2018-04-26"), 256.05m, 258.42m, 255.56m, 257.52m, 70044640), + new Quote(DateTime.Parse("2018-04-25"), 254.23m, 255.41m, 252.24m, 254.93m, 107386584), + new Quote(DateTime.Parse("2018-04-24"), 258.89m, 259.13m, 252.65m, 254.30m, 116739904), + new Quote(DateTime.Parse("2018-04-23"), 258.44m, 259.04m, 256.59m, 257.77m, 67796416), + new Quote(DateTime.Parse("2018-04-20"), 259.93m, 260.18m, 256.84m, 257.81m, 103366016), + new Quote(DateTime.Parse("2018-04-19"), 260.75m, 260.97m, 258.88m, 260.01m, 80307456), + new Quote(DateTime.Parse("2018-04-18"), 261.75m, 262.34m, 260.96m, 261.46m, 59260488), + new Quote(DateTime.Parse("2018-04-17"), 260.44m, 261.93m, 259.88m, 261.27m, 66890592), + new Quote(DateTime.Parse("2018-04-16"), 258.18m, 259.34m, 257.29m, 258.50m, 65570252), + new Quote(DateTime.Parse("2018-04-13"), 258.58m, 258.71m, 255.29m, 256.40m, 87984192), + new Quote(DateTime.Parse("2018-04-12"), 256.50m, 258.18m, 256.31m, 257.15m, 71242736), + new Quote(DateTime.Parse("2018-04-11"), 254.77m, 256.87m, 254.69m, 255.05m, 94252208), + new Quote(DateTime.Parse("2018-04-10"), 255.54m, 257.26m, 254.30m, 256.40m, 109178536), + new Quote(DateTime.Parse("2018-04-09"), 252.74m, 256.10m, 251.35m, 252.38m, 109043264), + new Quote(DateTime.Parse("2018-04-06"), 254.72m, 256.36m, 249.48m, 251.14m, 185650928), + new Quote(DateTime.Parse("2018-04-05"), 256.78m, 257.84m, 255.59m, 256.87m, 85474776), + new Quote(DateTime.Parse("2018-04-04"), 248.27m, 255.63m, 248.13m, 254.86m, 127939576), + new Quote(DateTime.Parse("2018-04-03"), 250.32m, 252.68m, 248.36m, 252.16m, 124052768), + new Quote(DateTime.Parse("2018-04-02"), 253.88m, 254.44m, 246.26m, 248.97m, 192647056), + new Quote(DateTime.Parse("2018-03-29"), 252.50m, 256.50m, 251.26m, 254.46m, 128487112), + new Quote(DateTime.Parse("2018-03-28"), 252.14m, 253.97m, 250.04m, 251.25m, 151452896), + new Quote(DateTime.Parse("2018-03-27"), 257.38m, 257.96m, 250.29m, 252.00m, 134378272), + new Quote(DateTime.Parse("2018-03-26"), 253.48m, 256.67m, 250.84m, 256.36m, 146803168), + new Quote(DateTime.Parse("2018-03-23"), 255.45m, 256.27m, 249.32m, 249.53m, 189801520), + new Quote(DateTime.Parse("2018-03-22"), 259.06m, 259.99m, 254.66m, 254.96m, 153866192), + new Quote(DateTime.Parse("2018-03-21"), 261.96m, 264.25m, 261.27m, 261.50m, 81397104), + new Quote(DateTime.Parse("2018-03-20"), 261.99m, 262.70m, 261.26m, 262.00m, 61797672), + new Quote(DateTime.Parse("2018-03-19"), 264.32m, 265.34m, 259.75m, 261.56m, 112937344), + new Quote(DateTime.Parse("2018-03-16"), 265.44m, 266.30m, 265.09m, 265.15m, 103769888), + new Quote(DateTime.Parse("2018-03-15"), 265.71m, 266.41m, 264.31m, 264.86m, 86627344), + new Quote(DateTime.Parse("2018-03-14"), 267.57m, 267.77m, 264.54m, 265.15m, 109949368), + new Quote(DateTime.Parse("2018-03-13"), 269.52m, 270.07m, 265.85m, 266.52m, 95490048), + new Quote(DateTime.Parse("2018-03-12"), 268.90m, 269.59m, 267.83m, 268.25m, 74678496), + new Quote(DateTime.Parse("2018-03-09"), 265.53m, 268.59m, 265.19m, 268.59m, 117975584), + new Quote(DateTime.Parse("2018-03-08"), 263.46m, 264.13m, 262.37m, 263.99m, 69462520), + new Quote(DateTime.Parse("2018-03-07"), 260.45m, 263.11m, 260.24m, 262.72m, 90396808), + new Quote(DateTime.Parse("2018-03-06"), 263.22m, 263.31m, 261.18m, 262.82m, 82245904), + new Quote(DateTime.Parse("2018-03-05"), 257.86m, 262.83m, 257.74m, 262.15m, 101032888), + new Quote(DateTime.Parse("2018-03-02"), 256.00m, 259.77m, 255.05m, 259.16m, 144408144), + new Quote(DateTime.Parse("2018-03-01"), 261.40m, 263.10m, 256.19m, 257.83m, 183626128), + new Quote(DateTime.Parse("2018-02-28"), 265.51m, 266.01m, 261.29m, 261.63m, 126575120), + new Quote(DateTime.Parse("2018-02-27"), 267.86m, 268.63m, 264.24m, 264.31m, 102893264), + new Quote(DateTime.Parse("2018-02-26"), 265.76m, 267.76m, 265.11m, 267.65m, 89802808), + new Quote(DateTime.Parse("2018-02-23"), 261.77m, 264.58m, 261.25m, 264.58m, 96318072), + new Quote(DateTime.Parse("2018-02-22"), 261.10m, 262.98m, 259.70m, 260.43m, 114742312), + new Quote(DateTime.Parse("2018-02-21"), 261.87m, 264.59m, 259.99m, 260.09m, 102669592), + new Quote(DateTime.Parse("2018-02-20"), 262.00m, 263.58m, 260.53m, 261.39m, 89676400), + new Quote(DateTime.Parse("2018-02-16"), 262.28m, 265.17m, 262.23m, 263.04m, 166561968), + new Quote(DateTime.Parse("2018-02-15"), 261.56m, 262.97m, 258.86m, 262.96m, 115457688), + new Quote(DateTime.Parse("2018-02-14"), 254.56m, 260.04m, 254.55m, 259.65m, 125358160), + new Quote(DateTime.Parse("2018-02-13"), 254.24m, 256.79m, 253.60m, 256.19m, 84333360), + new Quote(DateTime.Parse("2018-02-12"), 254.10m, 257.16m, 252.02m, 255.56m, 149239040), + new Quote(DateTime.Parse("2018-02-09"), 251.18m, 253.89m, 243.59m, 251.86m, 294421856), + new Quote(DateTime.Parse("2018-02-08"), 258.13m, 258.28m, 248.09m, 248.13m, 255885040), + new Quote(DateTime.Parse("2018-02-07"), 258.60m, 262.32m, 257.71m, 257.80m, 173784240), + new Quote(DateTime.Parse("2018-02-06"), 250.35m, 259.76m, 249.16m, 259.21m, 368619296), + new Quote(DateTime.Parse("2018-02-05"), 263.37m, 265.68m, 253.60m, 254.20m, 305963968), + new Quote(DateTime.Parse("2018-02-02"), 269.75m, 269.90m, 265.25m, 265.29m, 179804944), + new Quote(DateTime.Parse("2018-02-01"), 270.71m, 272.62m, 270.33m, 271.20m, 93552120), + new Quote(DateTime.Parse("2018-01-31"), 272.30m, 272.85m, 270.33m, 271.51m, 123502168), + new Quote(DateTime.Parse("2018-01-30"), 272.18m, 274.24m, 270.85m, 271.37m, 136842368), + new Quote(DateTime.Parse("2018-01-29"), 275.39m, 275.87m, 274.01m, 274.18m, 93568600), + new Quote(DateTime.Parse("2018-01-26"), 273.77m, 276.06m, 273.49m, 276.01m, 111868160), + new Quote(DateTime.Parse("2018-01-25"), 273.68m, 273.79m, 271.99m, 272.85m, 87825816), + new Quote(DateTime.Parse("2018-01-24"), 273.55m, 274.20m, 271.45m, 272.74m, 139977680), + new Quote(DateTime.Parse("2018-01-23"), 272.31m, 273.16m, 271.96m, 272.84m, 100801672), + new Quote(DateTime.Parse("2018-01-22"), 269.84m, 272.27m, 269.78m, 272.27m, 94818768), + new Quote(DateTime.Parse("2018-01-19"), 269.48m, 270.07m, 268.85m, 270.07m, 146315344), + new Quote(DateTime.Parse("2018-01-18"), 269.17m, 269.64m, 268.31m, 268.85m, 104584464), + new Quote(DateTime.Parse("2018-01-17"), 267.78m, 269.72m, 266.76m, 269.30m, 117595008), + new Quote(DateTime.Parse("2018-01-16"), 269.05m, 269.76m, 266.00m, 266.76m, 110634704), + new Quote(DateTime.Parse("2018-01-12"), 266.23m, 267.86m, 265.90m, 267.67m, 94293048), + new Quote(DateTime.Parse("2018-01-11"), 264.62m, 265.94m, 264.44m, 265.94m, 64749016), + new Quote(DateTime.Parse("2018-01-10"), 263.59m, 264.30m, 262.86m, 264.01m, 72238032), + new Quote(DateTime.Parse("2018-01-09"), 264.28m, 265.10m, 263.97m, 264.42m, 59445976), + new Quote(DateTime.Parse("2018-01-08"), 263.23m, 263.99m, 262.91m, 263.82m, 59513708), + new Quote(DateTime.Parse("2018-01-05"), 262.46m, 263.47m, 261.92m, 263.34m, 86721784), + new Quote(DateTime.Parse("2018-01-04"), 261.20m, 262.12m, 260.57m, 261.59m, 83723648), + new Quote(DateTime.Parse("2018-01-03"), 259.04m, 260.66m, 259.04m, 260.50m, 93518840), + new Quote(DateTime.Parse("2018-01-02"), 257.96m, 258.90m, 257.54m, 258.86m, 89973440), + new Quote(DateTime.Parse("2017-12-29"), 258.63m, 258.65m, 256.81m, 257.02m, 99683152), + new Quote(DateTime.Parse("2017-12-28"), 258.01m, 258.04m, 257.59m, 257.99m, 46843448), + new Quote(DateTime.Parse("2017-12-27"), 257.52m, 257.86m, 257.16m, 257.46m, 59962032), + new Quote(DateTime.Parse("2017-12-26"), 257.20m, 257.58m, 257.04m, 257.34m, 46976656), + new Quote(DateTime.Parse("2017-12-22"), 257.73m, 257.77m, 257.06m, 257.65m, 81734768), + new Quote(DateTime.Parse("2017-12-21"), 257.87m, 258.49m, 257.44m, 257.71m, 69598728), + new Quote(DateTime.Parse("2017-12-20"), 258.38m, 258.44m, 256.86m, 257.18m, 79690000), + new Quote(DateTime.Parse("2017-12-19"), 258.58m, 258.63m, 257.24m, 257.32m, 85536976), + new Quote(DateTime.Parse("2017-12-18"), 258.21m, 258.70m, 258.10m, 258.31m, 86856320), + new Quote(DateTime.Parse("2017-12-15"), 255.66m, 257.19m, 255.60m, 256.68m, 150146832), + new Quote(DateTime.Parse("2017-12-14"), 255.93m, 256.06m, 254.51m, 254.56m, 105055176), + new Quote(DateTime.Parse("2017-12-13"), 255.90m, 256.38m, 255.51m, 255.61m, 107391488), + new Quote(DateTime.Parse("2017-12-12"), 255.43m, 256.15m, 255.22m, 255.64m, 88909792), + new Quote(DateTime.Parse("2017-12-11"), 254.49m, 255.25m, 254.39m, 255.19m, 86699232), + new Quote(DateTime.Parse("2017-12-08"), 253.92m, 254.43m, 253.00m, 254.42m, 79901608), + new Quote(DateTime.Parse("2017-12-07"), 252.10m, 253.38m, 251.96m, 253.04m, 80584848), + new Quote(DateTime.Parse("2017-12-06"), 251.89m, 252.71m, 251.74m, 252.24m, 79207304), + new Quote(DateTime.Parse("2017-12-05"), 253.38m, 254.07m, 252.05m, 252.20m, 81394656), + new Quote(DateTime.Parse("2017-12-04"), 255.19m, 255.65m, 253.05m, 253.11m, 98140184), + new Quote(DateTime.Parse("2017-12-01"), 253.70m, 254.23m, 249.87m, 253.41m, 171557392), + new Quote(DateTime.Parse("2017-11-30"), 252.74m, 254.94m, 252.66m, 253.94m, 133469840), + new Quote(DateTime.Parse("2017-11-29"), 252.03m, 252.62m, 251.25m, 251.74m, 80891176), + new Quote(DateTime.Parse("2017-11-28"), 249.87m, 251.92m, 249.77m, 251.89m, 103286312), + new Quote(DateTime.Parse("2017-11-27"), 249.53m, 249.86m, 249.14m, 249.36m, 54553804), + new Quote(DateTime.Parse("2017-11-24"), 249.45m, 249.60m, 249.29m, 249.48m, 29070892), + new Quote(DateTime.Parse("2017-11-22"), 249.14m, 249.28m, 248.73m, 248.91m, 46996584), + new Quote(DateTime.Parse("2017-11-21"), 248.35m, 249.33m, 247.47m, 249.13m, 72192504), + new Quote(DateTime.Parse("2017-11-20"), 247.36m, 247.73m, 247.09m, 247.51m, 50171324), + new Quote(DateTime.Parse("2017-11-17"), 247.43m, 247.79m, 247.00m, 247.09m, 79059392), + new Quote(DateTime.Parse("2017-11-16"), 246.76m, 248.22m, 246.72m, 247.82m, 70731712), + new Quote(DateTime.Parse("2017-11-15"), 245.90m, 246.48m, 244.95m, 245.73m, 84334432), + new Quote(DateTime.Parse("2017-11-14"), 246.66m, 247.08m, 245.80m, 246.96m, 63988136), + new Quote(DateTime.Parse("2017-11-13"), 246.56m, 247.79m, 246.52m, 247.54m, 52418324), + new Quote(DateTime.Parse("2017-11-10"), 246.96m, 247.50m, 246.62m, 247.31m, 62599644), + new Quote(DateTime.Parse("2017-11-09"), 246.96m, 247.60m, 245.65m, 247.39m, 99230672), + new Quote(DateTime.Parse("2017-11-08"), 247.67m, 248.39m, 247.37m, 248.29m, 52669760), + new Quote(DateTime.Parse("2017-11-07"), 248.15m, 248.52m, 247.31m, 247.86m, 60008920), + new Quote(DateTime.Parse("2017-11-06"), 247.51m, 248.18m, 247.43m, 248.04m, 51817160), + new Quote(DateTime.Parse("2017-11-03"), 247.00m, 247.70m, 246.55m, 247.65m, 62187496), + new Quote(DateTime.Parse("2017-11-02"), 246.66m, 246.98m, 245.49m, 246.83m, 58910404), + new Quote(DateTime.Parse("2017-11-01"), 247.26m, 247.63m, 246.33m, 246.73m, 56565660), + new Quote(DateTime.Parse("2017-10-31"), 246.44m, 246.69m, 246.08m, 246.41m, 62933720), + new Quote(DateTime.Parse("2017-10-30"), 246.33m, 246.84m, 245.70m, 246.02m, 56652224), + new Quote(DateTime.Parse("2017-10-27"), 245.76m, 247.12m, 244.95m, 246.94m, 89292576), + new Quote(DateTime.Parse("2017-10-26"), 245.30m, 245.59m, 244.81m, 244.94m, 72840760), + new Quote(DateTime.Parse("2017-10-25"), 245.48m, 245.60m, 243.39m, 244.63m, 108236672), + new Quote(DateTime.Parse("2017-10-24"), 245.88m, 246.10m, 245.45m, 245.84m, 69853928), + new Quote(DateTime.Parse("2017-10-23"), 246.72m, 246.75m, 245.33m, 245.41m, 66701640), + new Quote(DateTime.Parse("2017-10-20"), 245.98m, 246.40m, 245.09m, 246.37m, 93063952), + new Quote(DateTime.Parse("2017-10-19"), 244.18m, 245.14m, 243.72m, 245.10m, 64602432), + new Quote(DateTime.Parse("2017-10-18"), 245.21m, 245.26m, 244.83m, 245.04m, 42670820), + new Quote(DateTime.Parse("2017-10-17"), 244.57m, 244.85m, 244.33m, 244.80m, 32936836), + new Quote(DateTime.Parse("2017-10-16"), 244.55m, 244.84m, 244.18m, 244.63m, 39887916), + new Quote(DateTime.Parse("2017-10-13"), 244.48m, 244.61m, 244.00m, 244.30m, 57189416), + new Quote(DateTime.Parse("2017-10-12"), 244.02m, 244.41m, 243.74m, 244.00m, 49116908), + new Quote(DateTime.Parse("2017-10-11"), 243.88m, 244.37m, 243.70m, 244.37m, 49752644), + new Quote(DateTime.Parse("2017-10-10"), 243.96m, 244.40m, 243.37m, 243.98m, 44934412), + new Quote(DateTime.Parse("2017-10-09"), 243.99m, 244.06m, 243.05m, 243.34m, 37363944), + new Quote(DateTime.Parse("2017-10-06"), 243.53m, 244.06m, 243.25m, 243.74m, 84161696), + new Quote(DateTime.Parse("2017-10-05"), 242.95m, 244.04m, 242.62m, 244.02m, 66291980), + new Quote(DateTime.Parse("2017-10-04"), 242.13m, 242.85m, 242.01m, 242.58m, 58392872), + new Quote(DateTime.Parse("2017-10-03"), 241.91m, 242.33m, 241.69m, 242.30m, 69722704), + new Quote(DateTime.Parse("2017-10-02"), 240.98m, 241.78m, 240.80m, 241.78m, 61596044), + new Quote(DateTime.Parse("2017-09-29"), 239.88m, 240.82m, 239.68m, 240.74m, 89308704), + new Quote(DateTime.Parse("2017-09-28"), 239.30m, 239.98m, 239.20m, 239.89m, 46730936), + new Quote(DateTime.Parse("2017-09-27"), 239.44m, 240.03m, 238.47m, 239.60m, 84532616), + new Quote(DateTime.Parse("2017-09-26"), 239.00m, 239.27m, 238.41m, 238.68m, 56439616), + new Quote(DateTime.Parse("2017-09-25"), 238.74m, 239.13m, 237.72m, 238.53m, 59552032), + new Quote(DateTime.Parse("2017-09-22"), 238.65m, 239.20m, 238.62m, 239.02m, 53446664), + new Quote(DateTime.Parse("2017-09-21"), 239.44m, 239.54m, 238.78m, 238.97m, 50313136), + new Quote(DateTime.Parse("2017-09-20"), 239.62m, 239.74m, 238.52m, 239.61m, 62171164), + new Quote(DateTime.Parse("2017-09-19"), 239.56m, 239.62m, 239.17m, 239.53m, 49161788), + new Quote(DateTime.Parse("2017-09-18"), 239.18m, 239.67m, 238.87m, 239.29m, 48250824), + new Quote(DateTime.Parse("2017-09-15"), 238.30m, 238.88m, 238.19m, 238.78m, 99592680), + new Quote(DateTime.Parse("2017-09-14"), 238.18m, 238.68m, 237.99m, 238.46m, 100101416), + new Quote(DateTime.Parse("2017-09-13"), 238.11m, 238.57m, 237.98m, 238.54m, 62116640), + new Quote(DateTime.Parse("2017-09-12"), 238.02m, 238.46m, 237.82m, 238.42m, 59670932), + new Quote(DateTime.Parse("2017-09-11"), 236.51m, 237.71m, 236.49m, 237.62m, 74845424), + new Quote(DateTime.Parse("2017-09-08"), 235.07m, 235.62m, 234.85m, 235.11m, 66946052), + new Quote(DateTime.Parse("2017-09-07"), 235.75m, 235.77m, 234.94m, 235.39m, 60865172), + new Quote(DateTime.Parse("2017-09-06"), 235.36m, 235.78m, 234.78m, 235.42m, 60741564), + new Quote(DateTime.Parse("2017-09-05"), 235.76m, 236.01m, 233.56m, 234.62m, 95856440), + new Quote(DateTime.Parse("2017-09-01"), 236.39m, 236.78m, 236.15m, 236.31m, 65031164), + new Quote(DateTime.Parse("2017-08-31"), 235.25m, 236.25m, 234.61m, 235.98m, 108866560), + new Quote(DateTime.Parse("2017-08-30"), 233.44m, 234.87m, 233.24m, 234.57m, 65056144), + new Quote(DateTime.Parse("2017-08-29"), 231.76m, 233.75m, 231.63m, 233.46m, 53629680), + new Quote(DateTime.Parse("2017-08-28"), 233.77m, 233.80m, 232.74m, 233.20m, 42544052), + new Quote(DateTime.Parse("2017-08-25"), 233.51m, 234.19m, 233.02m, 233.19m, 67589040), + new Quote(DateTime.Parse("2017-08-24"), 233.61m, 233.78m, 232.41m, 232.64m, 53216420), + new Quote(DateTime.Parse("2017-08-23"), 232.97m, 233.65m, 232.81m, 233.19m, 52652352), + new Quote(DateTime.Parse("2017-08-22"), 232.24m, 234.20m, 232.22m, 234.03m, 66219544), + new Quote(DateTime.Parse("2017-08-21"), 231.36m, 231.89m, 230.58m, 231.60m, 68662792), + new Quote(DateTime.Parse("2017-08-18"), 231.60m, 232.83m, 230.94m, 231.42m, 143417408), + new Quote(DateTime.Parse("2017-08-17"), 234.79m, 235.13m, 231.79m, 231.79m, 134757072), + new Quote(DateTime.Parse("2017-08-16"), 235.62m, 236.06m, 234.99m, 235.46m, 59481648), + new Quote(DateTime.Parse("2017-08-15"), 235.49m, 235.51m, 234.71m, 235.05m, 57937020), + new Quote(DateTime.Parse("2017-08-14"), 234.17m, 235.31m, 234.13m, 235.07m, 76866480), + new Quote(DateTime.Parse("2017-08-11"), 232.67m, 233.42m, 232.41m, 232.77m, 78521472), + new Quote(DateTime.Parse("2017-08-10"), 234.84m, 234.98m, 232.37m, 232.42m, 126355448), + new Quote(DateTime.Parse("2017-08-09"), 235.01m, 235.81m, 234.62m, 235.75m, 65687312), + new Quote(DateTime.Parse("2017-08-08"), 236.00m, 237.33m, 235.35m, 235.76m, 64729500), + new Quote(DateTime.Parse("2017-08-07"), 235.98m, 236.34m, 235.87m, 236.34m, 33555464), + new Quote(DateTime.Parse("2017-08-04"), 236.01m, 236.27m, 235.49m, 235.90m, 63127488), + new Quote(DateTime.Parse("2017-08-03"), 235.81m, 235.84m, 235.17m, 235.48m, 42848608), + new Quote(DateTime.Parse("2017-08-02"), 235.96m, 236.09m, 234.91m, 235.93m, 49513776), + new Quote(DateTime.Parse("2017-08-01"), 235.95m, 235.99m, 235.24m, 235.82m, 57735292), + new Quote(DateTime.Parse("2017-07-31"), 235.87m, 235.97m, 235.07m, 235.29m, 69049712), + new Quote(DateTime.Parse("2017-07-28"), 235.18m, 235.57m, 234.68m, 235.43m, 52531244), + new Quote(DateTime.Parse("2017-07-27"), 236.43m, 236.47m, 234.26m, 235.70m, 74217968), + new Quote(DateTime.Parse("2017-07-26"), 236.23m, 236.27m, 235.64m, 235.92m, 49895744), + new Quote(DateTime.Parse("2017-07-25"), 236.16m, 236.28m, 235.67m, 235.91m, 57593908), + new Quote(DateTime.Parse("2017-07-24"), 235.31m, 235.49m, 234.83m, 235.34m, 48896096), + new Quote(DateTime.Parse("2017-07-21"), 234.98m, 235.43m, 234.73m, 235.40m, 93037592), + new Quote(DateTime.Parse("2017-07-20"), 235.78m, 235.91m, 235.01m, 235.61m, 49434036), + new Quote(DateTime.Parse("2017-07-19"), 234.58m, 235.51m, 234.57m, 235.50m, 53523280), + new Quote(DateTime.Parse("2017-07-18"), 233.66m, 234.29m, 233.29m, 234.24m, 44827112), + new Quote(DateTime.Parse("2017-07-17"), 234.05m, 234.47m, 233.92m, 234.11m, 35167316), + new Quote(DateTime.Parse("2017-07-14"), 233.06m, 234.53m, 232.95m, 234.14m, 63201796), + new Quote(DateTime.Parse("2017-07-13"), 232.67m, 233.18m, 232.42m, 233.05m, 41396728), + new Quote(DateTime.Parse("2017-07-12"), 231.99m, 232.84m, 231.99m, 232.66m, 62517696), + new Quote(DateTime.Parse("2017-07-11"), 230.90m, 231.27m, 229.65m, 230.93m, 52810484), + new Quote(DateTime.Parse("2017-07-10"), 230.70m, 231.51m, 230.52m, 231.10m, 38451396), + new Quote(DateTime.Parse("2017-07-07"), 229.99m, 231.01m, 229.38m, 230.85m, 60799664), + new Quote(DateTime.Parse("2017-07-06"), 230.64m, 230.77m, 229.16m, 229.36m, 69339864), + new Quote(DateTime.Parse("2017-07-05"), 231.35m, 231.71m, 230.46m, 231.48m, 57082112), + new Quote(DateTime.Parse("2017-07-03"), 231.59m, 232.06m, 230.95m, 230.95m, 41063396), + new Quote(DateTime.Parse("2017-06-30"), 231.01m, 231.42m, 230.34m, 230.56m, 91055080), + new Quote(DateTime.Parse("2017-06-29"), 232.33m, 232.39m, 228.80m, 230.13m, 112165824), + new Quote(DateTime.Parse("2017-06-28"), 231.22m, 232.38m, 230.97m, 232.17m, 73458688), + new Quote(DateTime.Parse("2017-06-27"), 231.74m, 232.06m, 230.09m, 230.11m, 86259016), + new Quote(DateTime.Parse("2017-06-26"), 232.56m, 233.02m, 231.74m, 231.98m, 59465848), + new Quote(DateTime.Parse("2017-06-23"), 231.61m, 232.19m, 231.19m, 231.82m, 70253848), + new Quote(DateTime.Parse("2017-06-22"), 231.66m, 232.21m, 231.36m, 231.55m, 46301224), + new Quote(DateTime.Parse("2017-06-21"), 232.10m, 232.26m, 231.14m, 231.65m, 58707680), + new Quote(DateTime.Parse("2017-06-20"), 232.89m, 232.90m, 231.69m, 231.71m, 59681776), + new Quote(DateTime.Parse("2017-06-19"), 232.26m, 233.35m, 232.16m, 233.28m, 68299992), + new Quote(DateTime.Parse("2017-06-16"), 231.48m, 231.54m, 230.40m, 231.36m, 88676880), + new Quote(DateTime.Parse("2017-06-15"), 230.27m, 231.44m, 229.97m, 231.31m, 70046440), + new Quote(DateTime.Parse("2017-06-14"), 232.34m, 232.35m, 230.85m, 231.75m, 82837904), + new Quote(DateTime.Parse("2017-06-13"), 231.51m, 232.10m, 231.13m, 232.05m, 63303744), + new Quote(DateTime.Parse("2017-06-12"), 230.70m, 230.97m, 229.99m, 230.92m, 90748160), + new Quote(DateTime.Parse("2017-06-09"), 231.61m, 232.48m, 229.58m, 230.96m, 139383184), + new Quote(DateTime.Parse("2017-06-08"), 231.31m, 231.84m, 230.74m, 231.32m, 69504536), + new Quote(DateTime.Parse("2017-06-07"), 231.14m, 231.45m, 230.41m, 231.20m, 57061952), + new Quote(DateTime.Parse("2017-06-06"), 230.90m, 231.51m, 230.69m, 230.77m, 53089976), + new Quote(DateTime.Parse("2017-06-05"), 231.50m, 231.81m, 231.30m, 231.51m, 47107480), + new Quote(DateTime.Parse("2017-06-02"), 230.97m, 231.86m, 230.65m, 231.69m, 93444032), + new Quote(DateTime.Parse("2017-06-01"), 229.60m, 230.94m, 229.28m, 230.92m, 72678144), + new Quote(DateTime.Parse("2017-05-31"), 229.47m, 229.51m, 228.34m, 229.09m, 96742576), + new Quote(DateTime.Parse("2017-05-30"), 229.00m, 229.43m, 228.83m, 229.15m, 37098796), + new Quote(DateTime.Parse("2017-05-26"), 229.19m, 229.53m, 229.10m, 229.35m, 49142620), + new Quote(DateTime.Parse("2017-05-25"), 228.87m, 229.70m, 228.64m, 229.40m, 67524256), + new Quote(DateTime.Parse("2017-05-24"), 228.03m, 228.42m, 227.66m, 228.31m, 51831288), + new Quote(DateTime.Parse("2017-05-23"), 227.68m, 227.96m, 227.26m, 227.78m, 50946640), + new Quote(DateTime.Parse("2017-05-22"), 226.68m, 227.45m, 226.61m, 227.27m, 64298244), + new Quote(DateTime.Parse("2017-05-19"), 225.20m, 226.86m, 225.14m, 226.12m, 121208928), + new Quote(DateTime.Parse("2017-05-18"), 223.68m, 225.59m, 223.39m, 224.66m, 112816072), + new Quote(DateTime.Parse("2017-05-17"), 225.93m, 226.44m, 223.70m, 223.76m, 181451968), + new Quote(DateTime.Parse("2017-05-16"), 228.34m, 228.36m, 227.38m, 227.80m, 54003024), + new Quote(DateTime.Parse("2017-05-15"), 227.23m, 228.15m, 227.21m, 228.01m, 65255528), + new Quote(DateTime.Parse("2017-05-12"), 226.87m, 227.19m, 226.47m, 226.76m, 56817892), + new Quote(DateTime.Parse("2017-05-11"), 227.11m, 227.32m, 225.95m, 227.14m, 65718612), + new Quote(DateTime.Parse("2017-05-10"), 227.15m, 227.61m, 226.92m, 227.61m, 57219496), + new Quote(DateTime.Parse("2017-05-09"), 227.69m, 227.91m, 226.82m, 227.20m, 54130976), + new Quote(DateTime.Parse("2017-05-08"), 227.49m, 227.65m, 226.94m, 227.41m, 50993060), + new Quote(DateTime.Parse("2017-05-05"), 226.96m, 227.46m, 226.48m, 227.44m, 65342296), + new Quote(DateTime.Parse("2017-05-04"), 226.62m, 226.71m, 225.62m, 226.55m, 64774736), + new Quote(DateTime.Parse("2017-05-03"), 226.11m, 226.66m, 225.55m, 226.29m, 77078864), + new Quote(DateTime.Parse("2017-05-02"), 226.63m, 226.76m, 226.12m, 226.56m, 60467504), + new Quote(DateTime.Parse("2017-05-01"), 226.48m, 226.94m, 226.02m, 226.48m, 70486576), + new Quote(DateTime.Parse("2017-04-28"), 226.68m, 226.71m, 225.76m, 225.91m, 66956400), + new Quote(DateTime.Parse("2017-04-27"), 226.56m, 226.73m, 225.81m, 226.40m, 60503960), + new Quote(DateTime.Parse("2017-04-26"), 226.31m, 227.28m, 226.16m, 226.21m, 89266768), + new Quote(DateTime.Parse("2017-04-25"), 225.75m, 226.73m, 225.65m, 226.35m, 80831256), + new Quote(DateTime.Parse("2017-04-24"), 225.05m, 225.27m, 222.57m, 225.04m, 125633672), + new Quote(DateTime.Parse("2017-04-21"), 223.22m, 223.28m, 222.16m, 222.60m, 116338368), + new Quote(DateTime.Parse("2017-04-20"), 222.18m, 223.79m, 221.83m, 223.31m, 97560568), + new Quote(DateTime.Parse("2017-04-19"), 222.53m, 222.94m, 221.26m, 221.50m, 72401856), + new Quote(DateTime.Parse("2017-04-18"), 221.77m, 222.50m, 221.16m, 221.91m, 87710560), + new Quote(DateTime.Parse("2017-04-17"), 221.19m, 222.58m, 220.97m, 222.58m, 72091488), + new Quote(DateTime.Parse("2017-04-13"), 221.69m, 222.50m, 220.62m, 220.62m, 97885392), + new Quote(DateTime.Parse("2017-04-12"), 222.74m, 222.95m, 221.82m, 222.06m, 86275816), + new Quote(DateTime.Parse("2017-04-11"), 222.89m, 223.15m, 221.41m, 223.04m, 92789720), + new Quote(DateTime.Parse("2017-04-10"), 223.33m, 224.18m, 222.73m, 223.31m, 71258848), + new Quote(DateTime.Parse("2017-04-07"), 223.13m, 223.93m, 222.64m, 223.17m, 78422128), + new Quote(DateTime.Parse("2017-04-06"), 222.93m, 223.97m, 222.44m, 223.40m, 72861232), + new Quote(DateTime.Parse("2017-04-05"), 224.18m, 225.25m, 222.55m, 222.78m, 114663488), + new Quote(DateTime.Parse("2017-04-04"), 222.98m, 223.53m, 222.56m, 223.44m, 59508952), + new Quote(DateTime.Parse("2017-04-03"), 223.74m, 223.96m, 221.95m, 223.30m, 90156280), + new Quote(DateTime.Parse("2017-03-31"), 223.84m, 224.42m, 223.63m, 223.69m, 77706304), + new Quote(DateTime.Parse("2017-03-30"), 223.43m, 224.43m, 223.24m, 224.21m, 59795288), + new Quote(DateTime.Parse("2017-03-29"), 222.97m, 223.75m, 222.72m, 223.50m, 65288636), + new Quote(DateTime.Parse("2017-03-28"), 221.34m, 223.75m, 221.22m, 223.29m, 98521432), + new Quote(DateTime.Parse("2017-03-27"), 220.07m, 221.96m, 219.77m, 221.67m, 92167056), + new Quote(DateTime.Parse("2017-03-24"), 222.40m, 223.02m, 221.05m, 221.90m, 118567344), + new Quote(DateTime.Parse("2017-03-23"), 222.04m, 223.31m, 221.66m, 222.06m, 105821032), + new Quote(DateTime.Parse("2017-03-22"), 221.82m, 222.61m, 221.13m, 222.30m, 102826864), + new Quote(DateTime.Parse("2017-03-21"), 225.33m, 225.46m, 221.64m, 221.78m, 138912016), + new Quote(DateTime.Parse("2017-03-20"), 224.91m, 225.22m, 224.24m, 224.66m, 55368008), + new Quote(DateTime.Parse("2017-03-17"), 225.59m, 225.80m, 224.91m, 224.91m, 93798120), + new Quote(DateTime.Parse("2017-03-16"), 225.90m, 225.99m, 224.95m, 225.31m, 82924856), + new Quote(DateTime.Parse("2017-03-15"), 224.44m, 226.21m, 224.18m, 225.75m, 101699816), + new Quote(DateTime.Parse("2017-03-14"), 224.08m, 224.13m, 223.14m, 223.81m, 63382108), + new Quote(DateTime.Parse("2017-03-13"), 224.49m, 224.72m, 224.13m, 224.67m, 60604724), + new Quote(DateTime.Parse("2017-03-10"), 224.82m, 224.87m, 223.52m, 224.56m, 86785840), + new Quote(DateTime.Parse("2017-03-09"), 223.62m, 224.13m, 222.72m, 223.78m, 95986360), + new Quote(DateTime.Parse("2017-03-08"), 224.23m, 224.51m, 223.34m, 223.49m, 82739456), + new Quote(DateTime.Parse("2017-03-07"), 224.25m, 224.64m, 223.68m, 223.91m, 68910464), + new Quote(DateTime.Parse("2017-03-06"), 224.38m, 224.97m, 223.92m, 224.58m, 58630368), + new Quote(DateTime.Parse("2017-03-03"), 225.01m, 225.43m, 224.60m, 225.25m, 86767480), + new Quote(DateTime.Parse("2017-03-02"), 226.33m, 226.34m, 225.05m, 225.11m, 74353376), + new Quote(DateTime.Parse("2017-03-01"), 225.22m, 227.04m, 225.20m, 226.53m, 157879712), + new Quote(DateTime.Parse("2017-02-28"), 223.60m, 223.86m, 222.98m, 223.41m, 102631472), + new Quote(DateTime.Parse("2017-02-27"), 223.57m, 224.20m, 223.29m, 224.01m, 59819992), + new Quote(DateTime.Parse("2017-02-24"), 222.45m, 223.71m, 222.41m, 223.66m, 87198608), + new Quote(DateTime.Parse("2017-02-23"), 223.79m, 223.81m, 222.55m, 223.38m, 78978816), + new Quote(DateTime.Parse("2017-02-22"), 222.98m, 223.47m, 222.80m, 223.23m, 65747160), + new Quote(DateTime.Parse("2017-02-21"), 222.51m, 223.62m, 222.50m, 223.43m, 94146880), + new Quote(DateTime.Parse("2017-02-17"), 221.03m, 222.10m, 221.01m, 222.10m, 81718352), + new Quote(DateTime.Parse("2017-02-16"), 221.98m, 222.16m, 220.93m, 221.75m, 89676304), + new Quote(DateTime.Parse("2017-02-15"), 220.55m, 222.15m, 220.50m, 221.94m, 91860344), + new Quote(DateTime.Parse("2017-02-14"), 219.71m, 220.80m, 219.33m, 220.79m, 75266840), + new Quote(DateTime.Parse("2017-02-13"), 219.26m, 220.19m, 219.23m, 219.91m, 58408632), + new Quote(DateTime.Parse("2017-02-10"), 218.24m, 218.97m, 217.88m, 218.72m, 69875952), + new Quote(DateTime.Parse("2017-02-09"), 216.88m, 218.19m, 216.84m, 217.86m, 69811760), + new Quote(DateTime.Parse("2017-02-08"), 215.98m, 216.72m, 215.70m, 216.58m, 54581376), + new Quote(DateTime.Parse("2017-02-07"), 216.71m, 216.97m, 216.09m, 216.29m, 61318484), + new Quote(DateTime.Parse("2017-02-06"), 216.23m, 216.66m, 215.92m, 216.28m, 61169192), + new Quote(DateTime.Parse("2017-02-03"), 216.18m, 216.87m, 215.84m, 216.67m, 85273832), + new Quote(DateTime.Parse("2017-02-02"), 214.65m, 215.50m, 214.29m, 215.19m, 73730552), + new Quote(DateTime.Parse("2017-02-01"), 215.65m, 215.96m, 214.40m, 215.05m, 83743792), + new Quote(DateTime.Parse("2017-01-31"), 214.44m, 215.03m, 213.82m, 214.96m, 80317680), + new Quote(DateTime.Parse("2017-01-30"), 215.57m, 215.59m, 213.90m, 214.98m, 84399624), + new Quote(DateTime.Parse("2017-01-27"), 216.75m, 216.91m, 216.12m, 216.32m, 63202528), + new Quote(DateTime.Parse("2017-01-26"), 216.73m, 217.02m, 216.36m, 216.66m, 63477304), + new Quote(DateTime.Parse("2017-01-25"), 216.07m, 216.89m, 215.89m, 216.89m, 89374928), + new Quote(DateTime.Parse("2017-01-24"), 213.89m, 215.48m, 213.77m, 215.03m, 101142584), + new Quote(DateTime.Parse("2017-01-23"), 213.85m, 214.28m, 212.83m, 213.66m, 79450624), + new Quote(DateTime.Parse("2017-01-20"), 214.18m, 214.75m, 213.49m, 214.21m, 136721344), + new Quote(DateTime.Parse("2017-01-19"), 214.31m, 214.46m, 212.96m, 213.43m, 70503512), + new Quote(DateTime.Parse("2017-01-18"), 214.02m, 214.27m, 213.42m, 214.22m, 57997156), + new Quote(DateTime.Parse("2017-01-17"), 213.81m, 214.25m, 213.33m, 213.75m, 64821664), + new Quote(DateTime.Parse("2017-01-13"), 214.21m, 214.84m, 214.17m, 214.51m, 66385084), + new Quote(DateTime.Parse("2017-01-12"), 213.99m, 214.22m, 212.53m, 214.02m, 76329760), + new Quote(DateTime.Parse("2017-01-11"), 213.86m, 214.55m, 213.13m, 214.55m, 79014928), + new Quote(DateTime.Parse("2017-01-10"), 213.97m, 214.89m, 213.52m, 213.95m, 67500792), + new Quote(DateTime.Parse("2017-01-09"), 214.38m, 214.53m, 213.91m, 213.95m, 49684316), + new Quote(DateTime.Parse("2017-01-06"), 214.02m, 215.17m, 213.42m, 214.66m, 75744152), + new Quote(DateTime.Parse("2017-01-05"), 213.77m, 214.06m, 213.02m, 213.89m, 82961968), + new Quote(DateTime.Parse("2017-01-04"), 213.16m, 214.22m, 213.15m, 214.06m, 83348752), + new Quote(DateTime.Parse("2017-01-03"), 212.61m, 213.35m, 211.52m, 212.80m, 96708880), + new Quote(DateTime.Parse("2017-01-02"), 212.61m, 213.35m, 211.52m, 212.00m, 76708880), + new Quote(DateTime.Parse("2017-01-01"), 212.61m, 213.35m, 211.52m, 211.60m, 86708880), ]; } diff --git a/server/WebApi/Services/Service.Quotes.Random.cs b/server/WebApi/Services/Service.Quotes.Random.cs index 70e1bf8e..e95551ab 100644 --- a/server/WebApi/Services/Service.Quotes.Random.cs +++ b/server/WebApi/Services/Service.Quotes.Random.cs @@ -29,35 +29,15 @@ public class RandomQuotes : List/// Whether to include weekends in the generated data. ///Thrown when an invalid argument is provided. public RandomQuotes( - int bars = 250, - double volatility = 1.0, - double drift = 0.01, - double seed = 1000.0, - PeriodSize periodSize = PeriodSize.OneMinute, - bool includeWeekends = true) + int bars = 250, // NOSONAR S2360: constructor with many configurable options is intentional + double volatility = 1.0, // NOSONAR + double drift = 0.01, // NOSONAR + double seed = 1000.0, // NOSONAR + PeriodSize periodSize = PeriodSize.OneMinute, // NOSONAR + bool includeWeekends = true) // NOSONAR { - // validation - if (bars <= 0) - { - throw new ArgumentException("Number of bars must be greater than zero.", nameof(bars)); - } - - if (volatility <= 0) - { - throw new ArgumentException("Volatility must be greater than zero.", nameof(volatility)); - } - - if (seed <= 0) - { - throw new ArgumentException("Seed must be greater than zero.", nameof(seed)); - } - TimeSpan frequency = periodSize.ToTimeSpan(); - - if (!includeWeekends && (frequency < TimeSpan.FromHours(1) || frequency >= TimeSpan.FromDays(7))) - { - throw new ArgumentException("Weekends can only be excluded for period sizes between OneHour and less than OneWeek.", nameof(includeWeekends)); - } + ValidateArgs(bars, volatility, seed, frequency, includeWeekends); _seed = seed; _volatility = volatility * 0.01; @@ -78,6 +58,21 @@ public RandomQuotes( } } + private static void ValidateArgs(int bars, double volatility, double seed, TimeSpan frequency, bool includeWeekends) + { + if (bars <= 0) + throw new ArgumentException("Number of bars must be greater than zero.", nameof(bars)); + + if (volatility <= 0) + throw new ArgumentException("Volatility must be greater than zero.", nameof(volatility)); + + if (seed <= 0) + throw new ArgumentException("Seed must be greater than zero.", nameof(seed)); + + if (!includeWeekends && (frequency < TimeSpan.FromHours(1) || frequency >= TimeSpan.FromDays(7))) + throw new ArgumentException("Weekends can only be excluded for period sizes between OneHour and less than OneWeek.", nameof(includeWeekends)); + } + ////// Adds a new quote to the list. /// @@ -98,14 +93,7 @@ public void Add(DateTime timestamp) double volume = Price(_seed * 1000, _volatility * 2, drift: 0); - Quote quote = new() { - Date = timestamp, - Open = (decimal)open, - High = (decimal)high, - Low = (decimal)low, - Close = (decimal)close, - Volume = (decimal)volume - }; + Quote quote = new(timestamp, (decimal)open, (decimal)high, (decimal)low, (decimal)close, (decimal)volume); Add(quote); _seed = close; @@ -120,8 +108,8 @@ public void Add(DateTime timestamp) ///A random price. private static double Price(double seed, double volatility, double drift) { - double u1 = 1.0 - _random.NextDouble(); - double u2 = 1.0 - _random.NextDouble(); + double u1 = 1.0 - _random.NextDouble(); // nosemgrep: csharp.crypto.rule-WeakRNG - intentional: market simulator, not cryptographic + double u2 = 1.0 - _random.NextDouble(); // nosemgrep double z = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2); return seed * Math.Exp(drift - (volatility * volatility * 0.5) + (volatility * z)); } diff --git a/server/WebApi/Services/Service.Quotes.cs b/server/WebApi/Services/Service.Quotes.cs index 7ce5d3ea..5270187a 100644 --- a/server/WebApi/Services/Service.Quotes.cs +++ b/server/WebApi/Services/Service.Quotes.cs @@ -4,8 +4,8 @@ namespace WebApi.Services; public interface IQuoteService { - Task> Get(); - Task > Get(string symbol); + Task > Get(CancellationToken ct); + Task > Get(string symbol, CancellationToken ct); } public partial class QuoteService( @@ -19,53 +19,71 @@ public partial class QuoteService( /// Get default quotes /// /// List of default quotes - public async Task> Get() - => await Get("QQQ"); + public async Task > Get(CancellationToken ct) + => await Get("QQQ", ct); /// /// Get quotes for a specific symbol. /// /// "SPY" or "QQQ" only, for now - public async Task> Get(string symbol) + /// Cancellation token + public async Task > Get(string symbol, CancellationToken ct) { - string blobName = $"{symbol}-DAILY.json"; + ArgumentNullException.ThrowIfNull(symbol); + + symbol = symbol.Trim().ToUpperInvariant(); + if (symbol is not "SPY" and not "QQQ") + { + throw new ArgumentException("symbol must be \"SPY\" or \"QQQ\".", nameof(symbol)); + } + string blobName = $"{symbol}-DAILY.json"; try { - BlobClient blob = _storage.GetBlobClient(blobName); + return await TryGetBlobQuotesAsync(blobName, ct) ?? QuoteBackup.BackupQuotes; + } - if (!await blob.ExistsAsync()) - { - LogBlobNotFound(blobName); - return QuoteBackup.BackupQuotes; - } + catch (OperationCanceledException) when (ct.IsCancellationRequested) + { + throw; + } - Response response = await blob.DownloadAsync(); - await using Stream? stream = response?.Value.Content; + // failover to backup quotes for local development and testing + catch (Exception ex) + { + LogRetrieveQuotesFailed(ex, symbol); + return QuoteBackup.BackupQuotes; + } + } - if (stream == null) - { - LogDownloadStreamNull(blobName); - return QuoteBackup.BackupQuotes; - } + private async Task ?> TryGetBlobQuotesAsync(string blobName, CancellationToken ct) + { + BlobClient blob = _storage.GetBlobClient(blobName); - List ? quotes = await JsonSerializer.DeserializeAsync>(stream); + if (!await blob.ExistsAsync(ct)) + { + LogBlobNotFound(blobName); + return null; + } - if (quotes == null || quotes.Count == 0) - { - LogNoQuotesFound(blobName); - return QuoteBackup.BackupQuotes; - } + Response
response = await blob.DownloadAsync(ct); + await using Stream? stream = response?.Value.Content; - return quotes.OrderBy(x => x.Date); + if (stream == null) + { + LogDownloadStreamNull(blobName); + return null; } - // failover to backup quotes for local development and testing - catch (Exception ex) + List ? quotes = await JsonSerializer.DeserializeAsync>(stream, cancellationToken: ct); + + if (quotes == null || quotes.Count == 0) { - LogRetrieveQuotesFailed(ex, symbol); - return QuoteBackup.BackupQuotes; + LogNoQuotesFound(blobName); + return null; } + + return quotes.OrderBy(x => x.Timestamp); } [LoggerMessage(Level = LogLevel.Warning, Message = "Blob {BlobName} not found, using backup data")] diff --git a/server/WebApi/Services/Service.Storage.cs b/server/WebApi/Services/Service.Storage.cs index 83fcac41..ae463f4d 100644 --- a/server/WebApi/Services/Service.Storage.cs +++ b/server/WebApi/Services/Service.Storage.cs @@ -4,7 +4,7 @@ public interface IStorage { Task InitializeAsync(); Task InitializeAsync(CancellationToken cancellationToken); - Task PutBlobAsync(string blobName, string content); + Task PutBlobAsync(string blobName, string content, CancellationToken ct); BlobClient GetBlobClient(string blobName); } @@ -41,10 +41,17 @@ public async Task InitializeAsync(CancellationToken cancellationToken) /// Name of the blob /// Content to upload ///
Task representing the async operation - public async Task PutBlobAsync(string blobName, string content) + public async Task PutBlobAsync(string blobName, string content, CancellationToken ct) { + if (string.IsNullOrWhiteSpace(blobName)) + { + throw new ArgumentException("Blob name cannot be null or whitespace.", nameof(blobName)); + } + + ArgumentNullException.ThrowIfNull(content); + await using MemoryStream stream = new(Encoding.UTF8.GetBytes(content)); - await _blobClient.GetBlobClient(blobName).UploadAsync(stream, overwrite: true); + await _blobClient.GetBlobClient(blobName).UploadAsync(stream, overwrite: true, ct); } ///diff --git a/server/WebApi/appsettings.json b/server/WebApi/appsettings.json index dbbe61da..e8a954cd 100644 --- a/server/WebApi/appsettings.json +++ b/server/WebApi/appsettings.json @@ -8,6 +8,7 @@ }, "AllowedHosts": "*", "CorsOrigins": { - "Website": "http://localhost:4200;http://localhost:4300;http://localhost:4301" + "Website": "http://localhost:4200;http://localhost:4300;http://localhost:4301;http://localhost:4302", + "Demo": "https://stock-charts-vitepress.pages.dev" } } diff --git a/server/WebApi/packages.lock.json b/server/WebApi/packages.lock.json index fd7799a8..7dbc3ee2 100644 --- a/server/WebApi/packages.lock.json +++ b/server/WebApi/packages.lock.json @@ -13,21 +13,21 @@ }, "Azure.Security.KeyVault.Secrets": { "type": "Direct", - "requested": "[4.10.0, )", - "resolved": "4.10.0", - "contentHash": "lcJtcgTkk1gGy59RQhGLJLMyad+zgASMn975PVjMft69q+jjFTo6Nyq5SCtOhPY1WvA0gNI1qYIVN2oikVXDjw==", + "requested": "[4.11.0, )", + "resolved": "4.11.0", + "contentHash": "tjpVczILiXTR9bEynSL1JBU80169hGnTECtGsFjnRz9E1xoIhfUsaUTnB79k995zDkOG61hOI+YBtf5bNqgRIQ==", "dependencies": { - "Azure.Core": "1.53.0" + "Azure.Core": "1.54.0" } }, "Azure.Storage.Blobs": { "type": "Direct", - "requested": "[12.27.0, )", - "resolved": "12.27.0", - "contentHash": "zI5rg1tTtnA8T2g2/21l+1iIUdDjpEQQ0FI1BabJVEQJ1JUyTQKrc41eNabAHs0SBHprl6pu/6OqIMK9Ve+4tQ==", + "requested": "[12.28.0, )", + "resolved": "12.28.0", + "contentHash": "OK6slT3Hq3Yp2HWA0e23YHheHzKNbYjBZOwdT4fQ1iMH6I/8e6X8kAJLuKqVUeFBy160QSwhsynA3HxhVSHEcg==", "dependencies": { - "Azure.Core": "1.50.0", - "Azure.Storage.Common": "12.26.0" + "Azure.Core": "1.51.1", + "Azure.Storage.Common": "12.27.0" } }, "Microsoft.Extensions.Azure": { @@ -47,17 +47,17 @@ }, "Skender.Stock.Indicators": { "type": "Direct", - "requested": "[2.7.1, )", - "resolved": "2.7.1", - "contentHash": "HsHVlg9Tcb1gUV50dpazlUh2Qy1F9NtG7Fe4pYcxgnnloW4Fdh8TQTA7IB5M7rWubEvtFgzx+1U1vI2LzJPWXg==" + "requested": "[3.0.0-preview.3.1, )", + "resolved": "3.0.0-preview.3.1", + "contentHash": "oBzrKgtwRRGfJyotPufP1tpNUnNeUgyiv58aY9E/Z4qaKfLL0pOqPUtcS9/5z/mnmhtyRCe/BKPkRKTD4kHUKw==" }, "Azure.Storage.Common": { "type": "Transitive", - "resolved": "12.26.0", - "contentHash": "XaT6CDcSshZb7KaCTwc6m4EouZbLBg7ciOEpsJSdJCvkNsZJQCvPKw7V5TtXno19AA1NpwtsZriYque8mzbQVg==", + "resolved": "12.27.0", + "contentHash": "PBucMNzot6cYyN0isdte50iPCefJ4Ylg0B+KP4kxmqsc3ciOiDYh1MwVV6fPZPjoPnPvNRLN9TI6J5hgNf4huA==", "dependencies": { - "Azure.Core": "1.50.0", - "System.IO.Hashing": "10.0.1" + "Azure.Core": "1.51.1", + "System.IO.Hashing": "10.0.3" } }, "Microsoft.Bcl.AsyncInterfaces": { @@ -97,8 +97,8 @@ }, "System.IO.Hashing": { "type": "Transitive", - "resolved": "10.0.1", - "contentHash": "Dy6ULPb2S0GmNndjKrEIpfibNsc8+FTOoZnqygtFDuyun8vWboQbfMpQtKUXpgTxokR5E4zFHETpNnGfeWY6NA==" + "resolved": "10.0.3", + "contentHash": "La6ICwsdTKhVX+LKN+pvFjQRR3LhLwq3uKdi2knjLzRyPYBSydF4cjXidYxIiTcDD6XVYdsBWQEI8ZxiZ/OdIg==" }, "System.Memory.Data": { "type": "Transitive", @@ -113,8 +113,8 @@ "Azure.Core": { "type": "CentralTransitive", "requested": "[1.50.0, )", - "resolved": "1.53.0", - "contentHash": "x9c/toFMOtRrlTdFuE7rlGCVAduQzWVfKmLz5juj41zJAXEhYD5hluiUyyAEzJ6OxpBnKtiaBztzwpZITAVjtg==", + "resolved": "1.54.0", + "contentHash": "m6hHbx1q9+GCBZ5A9ykzFylPdTwscX2APH7PlnqV+yu+DH3RRtuIDJMRqdU17cMyinv0hCPofpegoyQ6qWPW7g==", "dependencies": { "Microsoft.Bcl.AsyncInterfaces": "10.0.3", "Microsoft.Identity.Client": "4.83.1", diff --git a/tests/playwright/package.json b/tests/playwright/package.json index b28a1217..19fc4109 100644 --- a/tests/playwright/package.json +++ b/tests/playwright/package.json @@ -6,6 +6,6 @@ "test": "playwright test" }, "devDependencies": { - "@playwright/test": "1.59.1" + "@playwright/test": "1.60.0" } } diff --git a/tests/playwright/playwright.config.ts b/tests/playwright/playwright.config.ts index 00972531..bde9237d 100644 --- a/tests/playwright/playwright.config.ts +++ b/tests/playwright/playwright.config.ts @@ -33,8 +33,8 @@ export default defineConfig({ }, { command: - "pnpm --filter @stock-charts/vitepress-example run build && pnpm --filter @stock-charts/vitepress-example run preview", - url: "http://localhost:4301", + "pnpm --filter @stock-charts/vitepress-example run build && pnpm --filter @stock-charts/vitepress-example run preview:test", + url: "http://localhost:4302", cwd: workspaceRoot, reuseExistingServer: !process.env["CI"], timeout: 180_000 @@ -49,7 +49,7 @@ export default defineConfig({ { name: "vitepress", testMatch: ["vitepress.spec.ts"], - use: { ...devices["Desktop Chrome"], baseURL: "http://localhost:4301" } + use: { ...devices["Desktop Chrome"], baseURL: "http://localhost:4302" } } ] }); diff --git a/tests/playwright/vitepress.spec.ts b/tests/playwright/vitepress.spec.ts index 3263778a..1475dac1 100644 --- a/tests/playwright/vitepress.spec.ts +++ b/tests/playwright/vitepress.spec.ts @@ -1,7 +1,7 @@ import { test, expect, type Locator, type Page } from "@playwright/test"; interface MockQuote { - date: string; + timestamp: string; open: number; high: number; low: number; @@ -16,7 +16,7 @@ function createQuotes(count: number): MockQuote[] { date.setUTCDate(date.getUTCDate() + index); const base = 100 + index * 0.35; return { - date: date.toISOString(), + timestamp: date.toISOString(), open: base, high: base + 2, low: base - 2, @@ -105,32 +105,34 @@ const mockListings = [ ]; async function mockChartApi(page: Page): Promise { - await page.route("https://localhost:5001/quotes", route => - route.fulfill({ json: mockQuotes, headers: { "access-control-allow-origin": "*" } }) - ); - await page.route("https://localhost:5001/indicators", route => - route.fulfill({ json: mockListings, headers: { "access-control-allow-origin": "*" } }) - ); - await page.route("https://localhost:5001/ema**", route => - route.fulfill({ - json: mockQuotes.map((quote, index) => ({ - date: quote.date, - candle: quote, - ema: quote.close - 1 + index / 200 - })), - headers: { "access-control-allow-origin": "*" } - }) - ); - await page.route("https://localhost:5001/rsi**", route => - route.fulfill({ - json: mockQuotes.map((quote, index) => ({ - date: quote.date, - candle: quote, - rsi: 45 + Math.sin(index / 5) * 20 - })), - headers: { "access-control-allow-origin": "*" } - }) - ); + // Pre-compute response payloads once; reused for every intercepted origin. + const emaData = mockQuotes.map((quote, index) => ({ + timestamp: quote.timestamp, + candle: quote, + ema: quote.close - 1 + index / 200 + })); + const rsiData = mockQuotes.map((quote, index) => ({ + timestamp: quote.timestamp, + candle: quote, + rsi: 45 + Math.sin(index / 5) * 20 + })); + + // Intercept both the local dev server and the production API origin so the + // mocks work whether the VitePress site was built in DEV or PROD mode. + for (const base of ["https://localhost:5001", "https://stock-charts-api.azurewebsites.net"]) { + await page.route(`${base}/quotes`, route => + route.fulfill({ json: mockQuotes, headers: { "access-control-allow-origin": "*" } }) + ); + await page.route(`${base}/indicators`, route => + route.fulfill({ json: mockListings, headers: { "access-control-allow-origin": "*" } }) + ); + await page.route(`${base}/ema**`, route => + route.fulfill({ json: emaData, headers: { "access-control-allow-origin": "*" } }) + ); + await page.route(`${base}/rsi**`, route => + route.fulfill({ json: rsiData, headers: { "access-control-allow-origin": "*" } }) + ); + } } async function expectCanvasToBeNonBlank(canvas: Locator): Promise { @@ -160,7 +162,7 @@ async function expectCanvasToBeNonBlank(canvas: Locator): Promise { test.describe("VitePress Documentation Site", () => { test("home page loads with correct title and heading", async ({ page }) => { await page.goto("/"); - await expect(page).toHaveTitle("Indy Charts Demo"); + await expect(page).toHaveTitle("Indy Charts"); await expect(page.getByRole("heading", { name: "Indy Charts", level: 1 })).toBeVisible(); }); diff --git a/tests/vitepress/.env.example b/tests/vitepress/.env.example new file mode 100644 index 00000000..4d3f307f --- /dev/null +++ b/tests/vitepress/.env.example @@ -0,0 +1,4 @@ +# Local development API URL override. +# Copy this file to .env and adjust for your local setup. +# When not set, the chart demos connect to the live production API. +VITE_API_URL=https://localhost:5001 diff --git a/tests/vitepress/.gitignore b/tests/vitepress/.gitignore index 01a48824..8d72039c 100644 --- a/tests/vitepress/.gitignore +++ b/tests/vitepress/.gitignore @@ -3,3 +3,4 @@ node_modules .vitepress/cache .DS_Store *.log +.env diff --git a/tests/vitepress/.vitepress/config.ts b/tests/vitepress/.vitepress/config.ts index 7975d0ed..70496d1d 100644 --- a/tests/vitepress/.vitepress/config.ts +++ b/tests/vitepress/.vitepress/config.ts @@ -1,7 +1,7 @@ import { defineConfig } from "vitepress"; export default defineConfig({ - title: "Indy Charts Demo", + title: "Indy Charts", description: "Financial charting with @facioquo/indy-charts", appearance: "dark", @@ -20,19 +20,21 @@ export default defineConfig({ sidebar: [ { - text: "Getting Started", + text: "Getting started", items: [ { text: "Introduction", link: "/guide/" }, { text: "Installation", link: "/guide/installation" }, - { text: "Quick Start", link: "/guide/quick-start" } + { text: "Quick start", link: "/guide/quick-start" }, + { text: "Theme customization", link: "/guide/themes" } ] }, { text: "Examples", items: [ - { text: "Basic Chart", link: "/examples/" }, - { text: "With Indicators", link: "/examples/indicators" }, - { text: "Multiple Charts", link: "/examples/multiple" } + { text: "Basic chart", link: "/examples/" }, + { text: "With indicators", link: "/examples/indicators" }, + { text: "Multiple charts", link: "/examples/multiple" }, + { text: "Custom data", link: "/examples/custom-data" } ] } ], diff --git a/tests/vitepress/.vitepress/theme/custom.css b/tests/vitepress/.vitepress/theme/custom.css index e5f1f0e1..640136b2 100644 --- a/tests/vitepress/.vitepress/theme/custom.css +++ b/tests/vitepress/.vitepress/theme/custom.css @@ -1,53 +1,16 @@ -:root { - --indy-demo-border: color-mix(in srgb, var(--vp-c-divider) 72%, transparent); - --indy-demo-bg: color-mix(in srgb, var(--vp-c-bg-soft) 85%, white 15%); - --indy-demo-bg-alt: color-mix(in srgb, var(--vp-c-bg) 90%, var(--vp-c-bg-soft) 10%); - --indy-demo-shadow: 0 18px 42px rgb(15 23 42 / 8%); - --indy-demo-radius: 16px; -} - -.dark { - --indy-demo-bg: color-mix(in srgb, var(--vp-c-bg-soft) 82%, black 18%); - --indy-demo-bg-alt: color-mix(in srgb, var(--vp-c-bg) 88%, black 12%); - --indy-demo-shadow: 0 16px 36px rgb(0 0 0 / 28%); -} - .indy-demo { - border: 1px solid var(--indy-demo-border); - border-radius: var(--indy-demo-radius); - background: linear-gradient(180deg, var(--indy-demo-bg), var(--indy-demo-bg-alt)); - box-shadow: var(--indy-demo-shadow); - padding: 14px; - margin: 18px 0 24px; + margin: 8px 0 24px; overflow: hidden; max-width: 100%; box-sizing: border-box; } .indy-demo__header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; - margin-bottom: 10px; -} - -.indy-demo__title { - margin: 0; - font-size: 14px; - letter-spacing: 0.02em; - text-transform: uppercase; - color: var(--vp-c-text-2); -} - -.indy-demo__hint { - margin: 0; - font-size: 12px; - color: var(--vp-c-text-3); + display: none; } .indy-demo__status { - border-radius: 12px; + border-radius: 8px; padding: 10px 12px; font-size: 13px; line-height: 1.4; @@ -85,20 +48,12 @@ } .indy-demo__panel { - border: 1px solid var(--indy-demo-border); - border-radius: 12px; - background: color-mix(in srgb, var(--vp-c-bg) 94%, transparent); - padding: 10px; overflow: hidden; min-width: 0; } .indy-demo__panel-title { - margin: 0 0 8px; - font-size: 12px; - color: var(--vp-c-text-2); - letter-spacing: 0.03em; - text-transform: uppercase; + display: none; } .indy-demo__canvas-wrap { @@ -108,22 +63,22 @@ } .indy-demo__canvas-wrap--overlay { - aspect-ratio: 2.5; + aspect-ratio: 2; } @media (width <= 880px) { .indy-demo__canvas-wrap--overlay { - aspect-ratio: 2; + aspect-ratio: 1.6; } } .indy-demo__canvas-wrap--oscillator { - aspect-ratio: 10; + aspect-ratio: 6; } @media (width <= 880px) { .indy-demo__canvas-wrap--oscillator { - aspect-ratio: 8; + aspect-ratio: 5; } } diff --git a/tests/vitepress/.vitepress/theme/index.ts b/tests/vitepress/.vitepress/theme/index.ts index 4bbf81a0..05f1f59b 100644 --- a/tests/vitepress/.vitepress/theme/index.ts +++ b/tests/vitepress/.vitepress/theme/index.ts @@ -1,15 +1,22 @@ import DefaultTheme from "vitepress/theme"; -import { setupIndyChartsForVitePress } from "@facioquo/indy-charts/vitepress"; +import { setupIndyChartsForVue } from "@facioquo/indy-charts/vue"; import "./custom.css"; +const PROD_API_URL = "https://stock-charts-api.azurewebsites.net"; +// VITE_API_URL is for local development only; production always uses the live API +// (guards against CF Pages dashboard env var misconfiguration) +const apiUrl = import.meta.env.DEV + ? ((import.meta.env.VITE_API_URL as string | undefined) ?? PROD_API_URL) + : PROD_API_URL; + export default { extends: DefaultTheme, enhanceApp({ app }) { - setupIndyChartsForVitePress(app, { + setupIndyChartsForVue(app, { api: { - baseUrl: "https://localhost:5001" + baseUrl: apiUrl }, defaults: { barCount: 250, diff --git a/tests/vitepress/AGENTS.md b/tests/vitepress/AGENTS.md index 03403961..a05ce144 100644 --- a/tests/vitepress/AGENTS.md +++ b/tests/vitepress/AGENTS.md @@ -1,9 +1,18 @@ -# Integration test host for indy-charts +# VitePress demo and integration test host for indy-charts -This VitePress website is solely for the purpose of testing an actual implementation of the `@facioquo/indy-charts` library package to depict per-use charts in a realistic scenario. +This VitePress website serves two purposes: -It solely depends on the [`@facioquo/indy-charts`](https://github.com/facioquo/stock-charts/tree/main/libs/indy-charts) package and indirectly on the [REST API](https://github.com/facioquo/stock-charts/tree/main/server). It must not directly depend on `@facioquo/chartjs-chart-financial` or any aspects of our primary client website. +1. **Consumer documentation**: demonstrates `@facioquo/indy-charts` in a realistic deployment scenario β the kind of site a library adopter would build +2. **Integration test host**: Playwright tests run against it to verify the public API works correctly end-to-end -## Dependencies note +It is deployed publicly on Cloudflare Pages (`stock-charts-vitepress`). + +## Rules + +- **Dependencies**: depends only on `@facioquo/indy-charts` (and indirectly on the REST API). Must not directly depend on `@facioquo/chartjs-chart-financial` or any aspects of the primary client website. +- **Heading style**: use sentence case for all headings. +- **No internal repo references**: documentation pages must not include VS Code task names, local port numbers, or other details specific to this repository's development environment. + +## VitePress version `vitepress` is pinned to `2.0.0-alpha.16` (a pre-release) intentionally: we are tracking VitePress 2.x to evaluate its updated plugin and theme APIs before the stable release. Downgrade to `1.x` only if the alpha blocks CI or produces breaking changes. Review when a stable `2.x` is published. diff --git a/tests/vitepress/README.md b/tests/vitepress/README.md index 73d58a08..70391e77 100644 --- a/tests/vitepress/README.md +++ b/tests/vitepress/README.md @@ -1,4 +1,4 @@ -# VitePress Integration Example +# VitePress integration example Minimal VitePress site demonstrating `@facioquo/indy-charts` integration. @@ -11,14 +11,14 @@ This example shows how to use the indy-charts VitePress adapter in a documentati - Technical indicators - Multiple chart layouts -## Getting Started +## Getting started ### Prerequisites - Node.js 24+ - pnpm (recommended) -### Install Dependencies +### Install dependencies From the repository root: @@ -26,28 +26,28 @@ From the repository root: pnpm install ``` -### Run Development Server +### Run development server ```bash cd tests/vitepress pnpm run dev ``` -The site will be available at `http://localhost:4300`. +The site will be available locally at the address shown in your dev server output. -### Build for Production +### Build for production ```bash pnpm run build ``` -### Preview Production Build +### Preview production build ```bash pnpm run preview ``` -## Project Structure +## Project structure ```text tests/vitepress/ @@ -68,18 +68,18 @@ tests/vitepress/ βββ package.json ``` -## Key Features +## Key features ### VitePress adapter (recommended pattern) The theme registers `StockIndicatorChart` once with site-level API and indicator defaults: ```typescript -import { setupIndyChartsForVitePress } from "@facioquo/indy-charts/vitepress"; +import { setupIndyChartsForVue } from "@facioquo/indy-charts/vue"; export default { enhanceApp({ app }) { - setupIndyChartsForVitePress(app, { + setupIndyChartsForVue(app, { api: { baseUrl: "https://localhost:5001" }, indicators: { rsi: { uiid: "RSI", params: { lookbackPeriods: 14 }, results: ["rsi"] } @@ -97,13 +97,13 @@ Markdown pages use the global component directly: ``` -### Live Examples +### Live examples - `/examples/` renders a live overlay indicator chart through `StockIndicatorChart` - `/examples/indicators` renders a live oscillator chart through `StockIndicatorChart` - `/examples/multiple` is currently a recipe page (truthful code, no live embed) -### TypeScript Support +### TypeScript support Full TypeScript support with type checking enabled in VitePress config. @@ -135,10 +135,10 @@ If you encounter module resolution issues, ensure: Check: -- `setupIndyChartsForVitePress()` is called from `.vitepress/theme/index.ts` -- The adapter API `baseUrl` matches the running Web API (`https://localhost:5001` by default) +- `setupIndyChartsForVue()` is called from `.vitepress/theme/index.ts` +- The adapter API `baseUrl` matches the running Web API address - The requested indicator is registered in the adapter `indicators` config -- Local Web API CORS includes VitePress dev/preview ports (`4300` / `4301`) +- Local Web API CORS includes the VitePress dev and preview origins ## Resources diff --git a/tests/vitepress/env.d.ts b/tests/vitepress/env.d.ts new file mode 100644 index 00000000..47cde6a6 --- /dev/null +++ b/tests/vitepress/env.d.ts @@ -0,0 +1,6 @@ +// Extends ImportMeta with Vite's env property for type-safe environment variable access. +// VitePress uses Vite under the hood; this declaration makes `import.meta.env` available +// to the TypeScript language server without requiring vite as a direct dependency. +interface ImportMeta { + readonly env: Record ; +} diff --git a/tests/vitepress/examples/StaticChart.vue b/tests/vitepress/examples/StaticChart.vue new file mode 100644 index 00000000..22f863bc --- /dev/null +++ b/tests/vitepress/examples/StaticChart.vue @@ -0,0 +1,50 @@ + + + + + ++ diff --git a/tests/vitepress/examples/custom-data.md b/tests/vitepress/examples/custom-data.md new file mode 100644 index 00000000..018c3842 --- /dev/null +++ b/tests/vitepress/examples/custom-data.md @@ -0,0 +1,103 @@ + + +# Custom data (bring your own) + +Render a chart directly from your own quote data β no API required. + +## Live demo + ++ + +## How it works + +`OverlayChart` is a lower-level building block exported from `@facioquo/indy-charts`. Unlike +`StockIndicatorChart`, it does not fetch data from an API β you supply the quotes directly. + +```typescript +import { OverlayChart, loadStaticQuotes } from "@facioquo/indy-charts"; +import type { RawQuote } from "@facioquo/indy-charts"; + +const raw: RawQuote[] = [ + { timestamp: "2025-01-02", open: 180.00, high: 182.50, low: 179.20, close: 181.80, volume: 38500000 }, + // ... more bars +]; + +const canvas = document.getElementById("my-canvas") as HTMLCanvasElement; +const chart = new OverlayChart(canvas, { isDarkTheme: false, showTooltips: true }); +chart.render(loadStaticQuotes(raw)); +``` + +## Source code + +The Vue component driving the demo above: + +```vue + + + + + +``` + +## Key points + +- **`RawQuote`**: input shape with ISO string `timestamp` and numeric OHLCV fields +- **`loadStaticQuotes`**: converts `timestamp` strings to `Date` objects, returning `Quote[]` +- **`OverlayChart`**: renders candlestick and volume directly onto a `+