Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use quote cache #190

Merged
merged 1 commit into from
Feb 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Server/Backend.sln
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Functions", "Functions\Functions.csproj", "{E9B5CE4B-BFAA-4E3A-B365-BEB69338932F}"
ProjectSection(ProjectDependencies) = postProject
{8C23ABF9-340A-4D21-BACD-A515A3C072EF} = {8C23ABF9-340A-4D21-BACD-A515A3C072EF}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
4 changes: 3 additions & 1 deletion Server/Functions/Functions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Alpaca.Markets" Version="5.2.8" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.10.0" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WebApi\WebApi.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand Down
10 changes: 2 additions & 8 deletions Server/Functions/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using Azure.Storage.Blobs;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using WebApi.Services;

[assembly: FunctionsStartup(typeof(Functions.Startup))]

Expand All @@ -10,11 +9,6 @@ public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
// initialize Azure services (setup storage)
string awjsConnection = Environment.GetEnvironmentVariable("AzureWebJobsStorage");

// main blob container
BlobContainerClient blobContainer = new(awjsConnection, "chart-demo");
blobContainer.CreateIfNotExists();
Storage.Startup();
}
}
64 changes: 22 additions & 42 deletions Server/Functions/UpdateQuotes.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Alpaca.Markets;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Skender.Stock.Indicators;
using WebApi.Services;

namespace Functions;

Expand All @@ -17,7 +18,6 @@ public static async Task Run([TimerTrigger("0 */1 08-18 * * 1-5")] TimerInfo myT
{
// ~ extended market hours, every minute "0 */1 08-18 * * 1-5"
// for dev: minutely "0 */1 * * * *"
await StoreQuoteDaily("DIA", log);
await StoreQuoteDaily("SPY", log);
await StoreQuoteDaily("QQQ", log);

Expand All @@ -40,49 +40,29 @@ private static async Task StoreQuoteDaily(string symbol, ILogger log)
IPage<IBar> barSet = await alpacaDataClient.ListHistoricalBarsAsync(
new HistoricalBarsRequest(symbol, from, into, BarTimeFrame.Day));

// compose CSV
string csv = string.Empty;
List<Quote> quotes = new(barSet.Items.Count);

// compose
foreach (IBar bar in barSet.Items)
{
csv += $"{bar.TimeUtc:d},{bar.Open},{bar.High},{bar.Low},{bar.Close},{bar.Volume}\r\n";
Quote q = new()
{
Date = bar.TimeUtc,
Open = bar.Open,
High = bar.High,
Low = bar.Low,
Close = bar.Close,
Volume = bar.Volume
};
quotes.Add(q);
}

string json = JsonSerializer.Serialize(quotes.OrderBy(x => x.Date));

// store in Azure Blog
string blobName = $"{symbol}-DAILY.csv";
await PutBlob(blobName, csv);
string blobName = $"{symbol}-DAILY.json";
await Storage.PutBlob(blobName, json);

log.LogInformation($"Updated {blobName}");
}

// SAVE BLOB
private static async Task<bool> PutBlob(string blobName, string csv)
{
BlobClient blob = GetBlobReference(blobName);
BlobHttpHeaders httpHeader = new()
{
ContentType = "application/text"
};

using (MemoryStream ms = new(Encoding.UTF8.GetBytes(csv)))
{
ms.Position = 0;
await blob.UploadAsync(ms, httpHeader);
};
return true;
}

// HELPERS
private static BlobClient GetBlobReference(string blobName)
{
BlobContainerClient blobContainer = GetContainerReference("chart-demo");
BlobClient blob = blobContainer.GetBlobClient(blobName);

return blob;
}

private static BlobContainerClient GetContainerReference(string containerName)
{
string awjsConnection = Environment.GetEnvironmentVariable("AzureWebJobsStorage");
return new BlobContainerClient(awjsConnection, containerName);
}
}
18 changes: 9 additions & 9 deletions Server/WebApi/Controllers/MainController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace WebApi.Controllers;
public class MainController : ControllerBase
{
internal static readonly IEnumerable<Quote> quotes = FetchQuotes.Get();
internal static readonly DateTime dateStart = DateTime.Parse("6/1/2018");
internal static readonly int limitLast = 130;

[HttpGet]
public string Get()
Expand All @@ -20,7 +20,7 @@ public string Get()
[HttpGet("quotes")]
public IActionResult GetQuotes()
{
return Ok(quotes.Where(x => x.Date >= dateStart));
return Ok(quotes.TakeLast(limitLast));
}

[HttpGet("indicators")]
Expand All @@ -41,7 +41,7 @@ public IActionResult GetBollingerBands(
{
IEnumerable<BollingerBandsResult> results =
quotes.GetBollingerBands(lookbackPeriods, standardDeviations)
.Where(x => x.Date >= dateStart);
.TakeLast(limitLast);

return Ok(results);
}
Expand All @@ -58,7 +58,7 @@ public IActionResult GetEMA(int lookbackPeriods)
{
IEnumerable<EmaResult> results =
quotes.GetEma(lookbackPeriods)
.Where(x => x.Date >= dateStart);
.TakeLast(limitLast);

return Ok(results);
}
Expand All @@ -77,7 +77,7 @@ public IActionResult GetParabolicSar(
{
IEnumerable<ParabolicSarResult> results =
quotes.GetParabolicSar(accelerationStep, maxAccelerationFactor)
.Where(x => x.Date >= dateStart);
.TakeLast(limitLast);

return Ok(results);
}
Expand All @@ -95,7 +95,7 @@ public IActionResult GetRsi(
{
IEnumerable<RsiResult> results =
quotes.GetRsi(lookbackPeriods)
.Where(x => x.Date >= dateStart);
.TakeLast(limitLast);

return Ok(results);
}
Expand All @@ -114,7 +114,7 @@ public IActionResult GetStoch(
{
IEnumerable<StochResult> results =
quotes.GetStoch(lookbackPeriods, signalPeriods)
.Where(x => x.Date >= dateStart);
.TakeLast(limitLast);

return Ok(results);
}
Expand All @@ -132,7 +132,7 @@ public IActionResult GetZigZagClose(
{
IEnumerable<ZigZagResult> results =
quotes.GetZigZag(EndType.Close, percentChange)
.Where(x => x.Date >= dateStart);
.TakeLast(limitLast);

return Ok(results);
}
Expand All @@ -150,7 +150,7 @@ public IActionResult GetZigZagHighLow(
{
IEnumerable<ZigZagResult> results =
quotes.GetZigZag(EndType.HighLow, percentChange)
.Where(x => x.Date >= dateStart);
.TakeLast(limitLast);

return Ok(results);
}
Expand Down
8 changes: 8 additions & 0 deletions Server/WebApi/Properties/serviceDependencies.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"dependencies": {
"storage1": {
"type": "storage",
"connectionId": "AzureWebJobsStorage"
}
}
}
9 changes: 9 additions & 0 deletions Server/WebApi/Properties/serviceDependencies.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"dependencies": {
"storage1": {
"secretStore": null,
"type": "storage.emulator",
"connectionId": "AzureWebJobsStorage"
}
}
}
35 changes: 33 additions & 2 deletions Server/WebApi/Services/Service.Quotes.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,41 @@
using Skender.Stock.Indicators;
using System.Text.Json;
using Azure;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Skender.Stock.Indicators;

namespace WebApi.Services;

internal static class FetchQuotes
{
internal static IEnumerable<Quote> Get()
internal static IEnumerable<Quote> Get(string symbol = "QQQ")
{
string blobName = $"{symbol}-DAILY.json";

try
{
BlobClient blob = Storage.GetBlobReference(blobName);
Response<BlobDownloadInfo> response = blob.Download();

List<Quote> quotes = JsonSerializer
.Deserialize<List<Quote>>(response.Value.Content);

if (quotes == null || quotes.Count == 0)
{
return GetBackup();
}

return quotes
.OrderBy(x => x.Date)
.ToList();
}
catch
{
return GetBackup();
}
}

internal static IEnumerable<Quote> GetBackup()
{
List<Quote> h = new()
{
Expand Down
51 changes: 51 additions & 0 deletions Server/WebApi/Services/Service.Storage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System.Text;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;

namespace WebApi.Services;

public class Storage
{
// STARTUP
public static void Startup()
{
// initialize Azure services (setup storage)
string awjsConnection = Environment.GetEnvironmentVariable("AzureWebJobsStorage");

// main blob container
BlobContainerClient blobContainer = new(awjsConnection, "chart-demo");
blobContainer.CreateIfNotExists();
}

// SAVE BLOB
public static async Task<bool> PutBlob(string blobName, string csv)
{
BlobClient blob = GetBlobReference(blobName);
BlobHttpHeaders httpHeader = new()
{
ContentType = "application/json"
};

using (MemoryStream ms = new(Encoding.UTF8.GetBytes(csv)))
{
ms.Position = 0;
await blob.UploadAsync(ms, httpHeader);
};
return true;
}

// HELPERS
internal static BlobClient GetBlobReference(string blobName)
{
BlobContainerClient blobContainer = GetContainerReference("chart-demo");
BlobClient blob = blobContainer.GetBlobClient(blobName);

return blob;
}

private static BlobContainerClient GetContainerReference(string containerName)
{
string awjsConnection = Environment.GetEnvironmentVariable("AzureWebJobsStorage");
return new BlobContainerClient(awjsConnection, containerName);
}
}
4 changes: 4 additions & 0 deletions Server/WebApi/WebApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Azure.Storage.Blobs" Version="12.10.0" />
<PackageReference Include="Azure.Storage.Files.Shares" Version="12.1.0" />
<PackageReference Include="Azure.Storage.Queues" Version="12.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.2" />
<PackageReference Include="Microsoft.Extensions.Azure" Version="1.0.0" />
<PackageReference Include="Skender.Stock.Indicators" Version="1.21.0" />
</ItemGroup>

Expand Down