Skip to content

Commit

Permalink
Encapsulate fetching ApiKey into EnvironmentVariablesLoader class
Browse files Browse the repository at this point in the history
  • Loading branch information
bleunguts committed Feb 13, 2024
1 parent 07e6098 commit 75d0f1f
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 25 deletions.
25 changes: 25 additions & 0 deletions ProjectX.Core/EnvironmentVariableLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Microsoft.Extensions.Configuration.EnvironmentVariables;

namespace ProjectX.Core
{
public class EnvironmentVariableLoader
{
private readonly EnvironmentVariablesConfigurationProvider _provider;
public EnvironmentVariableLoader()
{
_provider = new EnvironmentVariablesConfigurationProvider();
_provider.Load();
}
public string FromEnvironmentVariable(string envVariable)
{
string? value = null;
if (!_provider.TryGet(envVariable, out value) || string.IsNullOrEmpty(value))
{
throw new Exception($"Blow up: cannot get compulsory market data api key from environment variable '${envVariable}'");
}

return value;
}
}

}
1 change: 1 addition & 0 deletions ProjectX.Core/ProjectX.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0-rc.1.23419.4" />
<PackageReference Include="Skender.Stock.Indicators" Version="3.0.0-preview1014-0012" />
<PackageReference Include="System.ComponentModel.Composition" Version="7.0.0" />
Expand Down
9 changes: 6 additions & 3 deletions ProjectX.GatewayAPI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,12 @@ public void ConfigureServices(IServiceCollection services)
services.AddSingleton<PricingTasksChannel>();
services.AddSingleton<FXTasksChannel>();
services.TryAddScoped<IPricingTasksProcessor, PricingTasksProcessor>();
services.AddSingleton<IStockMarketSource>(new FileBackedStockMarketDataSource(
new FMPStockMarketSource(Options.Create(new FMPStockMarketSourceOptions() { ApiKey = FMPStockMarketSourceOptions.GetFromEnvironment() })),
Options.Create(new FileBackedStoreMarketDataSourceOptions() { Filename = Configuration.GetSection("MarketData")["CacheFilename"] }))
var environmentVariablesLoader = new EnvironmentVariableLoader();
services.AddSingleton<IStockMarketSource>(
new FileBackedStockMarketDataSource(
new FMPStockMarketSource(Options.Create(new FMPStockMarketSourceOptions { ApiKey = environmentVariablesLoader.FromEnvironmentVariable("fmpapikey") })),
Options.Create(new FileBackedStoreMarketDataSourceOptions() { Filename = Configuration.GetSection("MarketData")["CacheFilename"] })
)
);
services.AddSingleton<IStockSignalService, StockSignalService>();
services.AddSingleton<IBacktestService, BacktestService>();
Expand Down
5 changes: 4 additions & 1 deletion ProjectX.MarketData.Cache.Tests/BacktestExternalTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using ProjectX.Core;
using ProjectX.Core.Services;
using ProjectX.Core.Strategy;
using System;
Expand All @@ -14,9 +15,11 @@ public class BacktestExternalTest
{
const string ticker = "IBM";

private static readonly EnvironmentVariableLoader _environmentVariableLoader = new();
private static readonly string _apiKey = _environmentVariableLoader.FromEnvironmentVariable("fmpapikey");
private readonly BacktestService _backtestService = new();
private readonly FileBackedStockMarketDataSource _marketSource = new FileBackedStockMarketDataSource(
new FMPStockMarketSource(Options.Create<FMPStockMarketSourceOptions>(new FMPStockMarketSourceOptions() { ApiKey = FMPStockMarketSourceOptions.GetFromEnvironment()})),
new FMPStockMarketSource(Options.Create<FMPStockMarketSourceOptions>(new FMPStockMarketSourceOptions { ApiKey = _apiKey })),
Options.Create<FileBackedStoreMarketDataSourceOptions>(new FileBackedStoreMarketDataSourceOptions { Filename = "externalTests.json" }));
public record ChartData(string time, double amount, double amountHold);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.Options;
using ProjectX.Core;
using ProjectX.Core.Services;
using ProjectX.Core.Strategy;
using ProjectX.MarketData.Cache;
Expand All @@ -14,7 +15,8 @@ namespace ProjectX.MarketData.Tests
{
public class StockSignalServiceExternalTest
{
private static readonly FileBackedStockMarketDataSource _marketSource = new FileBackedStockMarketDataSource(new FMPStockMarketSource(Options.Create<FMPStockMarketSourceOptions>(new FMPStockMarketSourceOptions() { ApiKey = FMPStockMarketSourceOptions.GetFromEnvironment() })), Options.Create<FileBackedStoreMarketDataSourceOptions>(new FileBackedStoreMarketDataSourceOptions { Filename = "externalTests.json" }));
private static readonly EnvironmentVariableLoader _environmentVariableLoader = new();
private static readonly FileBackedStockMarketDataSource _marketSource = new FileBackedStockMarketDataSource(new FMPStockMarketSource(Options.Create<FMPStockMarketSourceOptions>(new FMPStockMarketSourceOptions { ApiKey = _environmentVariableLoader.FromEnvironmentVariable("fmpapikey")})), Options.Create<FileBackedStoreMarketDataSourceOptions>(new FileBackedStoreMarketDataSourceOptions { Filename = "externalTests.json" }));
private readonly StockSignalService _signalService = new StockSignalService(_marketSource);

[Test]
Expand Down
14 changes: 9 additions & 5 deletions ProjectX.MarketData.Tests/FMPStockMarketSourceExternalTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
namespace ProjectX.MarketData.Tests
{
public class FMPStockMarketSourceExternalTest
{
{
private static readonly EnvironmentVariableLoader _environmentVariableLoader = new();
private static readonly string _apiKey = _environmentVariableLoader.FromEnvironmentVariable("fmpapikey");

[Test]
[Ignore("Tool")]
public async Task ExternalFoo()
{
var api = FinancialModelingPrepApiClientFactory.CreateClient(new FinancialModelingPrepOptions()
{
ApiKey = "35fdfe7c1a0d49e6ca2283bb073fea3a"
ApiKey = _apiKey
});

var result = await api.StockTimeSeries.GetHistoricalDailyPricesAsync("GOOGL", "2020-01-01", "2020-02-01");
Expand All @@ -38,7 +41,7 @@ public async Task ExternalFoo()
[Ignore("Tool")]
public async Task WhenGettingHistoricalPricesFromFMP()
{
var marketDataService = new FMPStockMarketSource(Options.Create<FMPStockMarketSourceOptions>(new FMPStockMarketSourceOptions() { ApiKey = FMPStockMarketSourceOptions.GetFromEnvironment() }));
var marketDataService = new FMPStockMarketSource(Options.Create<FMPStockMarketSourceOptions>(new FMPStockMarketSourceOptions { ApiKey = _apiKey }));
var marketPrices = await marketDataService.GetPrices("ACAQ", new DateTime(2023, 1, 1), new DateTime(2023, 10, 1));
Assert.That(marketPrices.Count(), Is.GreaterThan(0));
foreach (var data in marketPrices)
Expand All @@ -53,7 +56,7 @@ public async Task WhenGettingHistoricalPricesFromFMP()
[Ignore("External Tool for testing only")]
public async Task WhenGettingStockMarketMostActiveFromFMP()
{
var marketDataService = new FMPStockMarketSource(Options.Create<FMPStockMarketSourceOptions>(new FMPStockMarketSourceOptions() { ApiKey = FMPStockMarketSourceOptions.GetFromEnvironment() }));
var marketDataService = new FMPStockMarketSource(Options.Create<FMPStockMarketSourceOptions>(new FMPStockMarketSourceOptions { ApiKey = _apiKey }));
var mostActiveStocks = await marketDataService.GetMostActiveStocks();
Assert.That(mostActiveStocks.Count(), Is.GreaterThan(0));
foreach(var data in mostActiveStocks)
Expand All @@ -66,7 +69,8 @@ public async Task WhenGettingStockMarketMostActiveFromFMP()
[Ignore("Use to try out StockIndicator Api features")]
public async Task WhenGettingBollingerBandsFromFMQ()
{
var marketDataService = new FMPStockMarketSource(Options.Create<FMPStockMarketSourceOptions>(new FMPStockMarketSourceOptions() { ApiKey = FMPStockMarketSourceOptions.GetFromEnvironment() }));
var config = Options.Create<FMPStockMarketSourceOptions>(new FMPStockMarketSourceOptions { ApiKey = _apiKey });
var marketDataService = new FMPStockMarketSource(config);
var quotes = await marketDataService.GetQuote("ACAQ", new DateTime(2023, 1, 1), new DateTime(2023, 10, 1));
Assert.That(quotes.Count(), Is.GreaterThan(0));

Expand Down
4 changes: 4 additions & 0 deletions ProjectX.MarketData/EnvironmentVariableLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using Microsoft.Extensions.Configuration.EnvironmentVariables;

namespace ProjectX.MarketData;

15 changes: 0 additions & 15 deletions ProjectX.MarketData/FMPStockMarketSourceOptions.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,5 @@
namespace ProjectX.MarketData;

public class FMPStockMarketSourceOptions
{
public string ApiKey { get; set; }

public static string GetFromEnvironment()
{
var provider = new Microsoft.Extensions.Configuration.EnvironmentVariables.EnvironmentVariablesConfigurationProvider();
provider.Load();

string? apiKey = null;
if (!provider.TryGet("fmpapikey", out apiKey))
{
throw new Exception($"Blow up: cannot get compulsory market data api key from environment variable 'fmpapikey'");
}

return apiKey;
}
}

0 comments on commit 75d0f1f

Please sign in to comment.