diff --git a/ConsoleHelper/Program.cs b/ConsoleHelper/Program.cs index 13e2d0bb..cab37d2e 100644 --- a/ConsoleHelper/Program.cs +++ b/ConsoleHelper/Program.cs @@ -3,6 +3,7 @@ using GhostfolioSidekick.FileImporter.Bunq; using GhostfolioSidekick.FileImporter.DeGiro; using GhostfolioSidekick.FileImporter.Generic; +using GhostfolioSidekick.FileImporter.Nexo; using GhostfolioSidekick.FileImporter.ScalableCaptial; using GhostfolioSidekick.FileImporter.Trading212; using GhostfolioSidekick.Ghostfolio.API; @@ -29,15 +30,15 @@ static void Main(string[] args) MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions { }); GhostfolioAPI api = new GhostfolioAPI(cs, memoryCache, logger); IScheduledWork t = new FileImporterTask(logger, api, cs, new IFileImporter[] { - new ScalableCapitalParser(api), - new DeGiroParser(api), - new Trading212Parser(api), - new GenericParser(api), new BunqParser(api), //new CoinbaseParser(api), - //new NexoParser(api), + new DeGiroParser(api), + new GenericParser(api), + new NexoParser(api), + new ScalableCapitalParser(api), + new Trading212Parser(api), }); - // t.DoWork().Wait(); + t.DoWork().Wait(); t = new MarketDataMaintainerTask(logger, api); t.DoWork().Wait(); } diff --git a/GhostfolioSidekick.UnitTests/FileImporter/Bunq/BunqParserTests.cs b/GhostfolioSidekick.UnitTests/FileImporter/Bunq/BunqParserTests.cs index 45ffa903..c6103cdc 100644 --- a/GhostfolioSidekick.UnitTests/FileImporter/Bunq/BunqParserTests.cs +++ b/GhostfolioSidekick.UnitTests/FileImporter/Bunq/BunqParserTests.cs @@ -36,7 +36,7 @@ public async Task ConvertActivitiesForAccount_TestFileLifecycle_Converted() var parser = new BunqParser(api.Object); var fixture = new Fixture(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); @@ -45,13 +45,13 @@ public async Task ConvertActivitiesForAccount_TestFileLifecycle_Converted() // Assert account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, 903.5M, new DateTime(2023, 08, 18, 0, 0, 0, DateTimeKind.Utc))); - account.Activities.Should().BeEquivalentTo(new[] { new Model.Activity { + account.Activities.Should().BeEquivalentTo(new[] { new Activity { Asset = null, Comment = "Transaction Reference: [Interest_2023-07-27]", Date = new DateTime(2023,07,27, 0,0,0, DateTimeKind.Utc), Fee = null, Quantity = 1m, - ActivityType = Model.ActivityType.Interest, + ActivityType = ActivityType.Interest, UnitPrice = new Money(DefaultCurrency.EUR, 3.5M, new DateTime(2023,7,27, 0,0,0, DateTimeKind.Utc)), ReferenceCode = "Interest_2023-07-27" } }); @@ -64,7 +64,7 @@ public async Task ConvertActivitiesForAccount_TestMultipleDepositsOn1Day_Convert var parser = new BunqParser(api.Object); var fixture = new Fixture(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); diff --git a/GhostfolioSidekick.UnitTests/FileImporter/DeGiro/DeGiroParserTests.cs b/GhostfolioSidekick.UnitTests/FileImporter/DeGiro/DeGiroParserTests.cs index 545389a5..9a501e73 100644 --- a/GhostfolioSidekick.UnitTests/FileImporter/DeGiro/DeGiroParserTests.cs +++ b/GhostfolioSidekick.UnitTests/FileImporter/DeGiro/DeGiroParserTests.cs @@ -49,8 +49,8 @@ public async Task ConvertActivitiesForAccount_TestFileSingleOrder_Converted() var parser = new DeGiroParser(api.Object); var fixture = new Fixture(); - var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("IE00B3XXRP09", null)).ReturnsAsync(asset); @@ -60,13 +60,13 @@ public async Task ConvertActivitiesForAccount_TestFileSingleOrder_Converted() // Assert account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, 21.70M, new DateTime(2023, 07, 10, 17, 34, 0, DateTimeKind.Utc))); - account.Activities.Should().BeEquivalentTo(new[] { new Model.Activity { + account.Activities.Should().BeEquivalentTo(new[] { new Activity { Asset = asset, Comment = "Transaction Reference: [b7ab0494-1b46-4e2f-9bd2-f79e6c87cb5b]", Date = new DateTime(2023,07,6, 9, 39,0, DateTimeKind.Utc), Fee = new Money(DefaultCurrency.EUR, 1, new DateTime(2023,07,6, 9, 39,0, DateTimeKind.Utc)), Quantity = 1, - ActivityType = Model.ActivityType.Buy, + ActivityType = ActivityType.Buy, UnitPrice = new Money(DefaultCurrency.EUR, 77.30M, new DateTime(2023,07,6, 9, 39,0, DateTimeKind.Utc)), ReferenceCode = "b7ab0494-1b46-4e2f-9bd2-f79e6c87cb5b" } }); @@ -79,10 +79,10 @@ public async Task ConvertActivitiesForAccount_TestFileMultipleOrders_Converted() var parser = new DeGiroParser(api.Object); var fixture = new Fixture(); - var asset1 = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); - var asset2 = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); + var asset1 = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); + var asset2 = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("IE00B3XXRP09", null)).ReturnsAsync(asset1); @@ -94,22 +94,22 @@ public async Task ConvertActivitiesForAccount_TestFileMultipleOrders_Converted() // Assert account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, 23.83M, new DateTime(2023, 07, 13, 11, 49, 0, DateTimeKind.Utc))); account.Activities.Should().BeEquivalentTo(new[] - { new Model.Activity { + { new Activity { Asset = asset1, Comment = "Transaction Reference: [b7ab0494-1b46-4e2f-9bd2-f79e6c87cb5b]", Date = new DateTime(2023,07,6,9,39,0, DateTimeKind.Utc), Fee = new Money(DefaultCurrency.EUR, 1, new DateTime(2023,07,6,9,39,0, DateTimeKind.Utc)), Quantity = 1, - ActivityType = Model.ActivityType.Buy, + ActivityType = ActivityType.Buy, UnitPrice = new Money(DefaultCurrency.EUR, 77.30M, new DateTime(2023,07,6,9,39,0, DateTimeKind.Utc)), ReferenceCode = "b7ab0494-1b46-4e2f-9bd2-f79e6c87cb5b" - }, new Model.Activity { + }, new Activity { Asset = asset2, Comment = "Transaction Reference: [67e39ca1-2f10-4f82-8365-1baad98c398f]", Date = new DateTime(2023,07,11, 9,33,0, DateTimeKind.Utc), Fee = new Money(DefaultCurrency.EUR, 1, new DateTime(2023,07,11, 9,33,0, DateTimeKind.Utc)), Quantity = 29, - ActivityType = Model.ActivityType.Buy, + ActivityType = ActivityType.Buy, UnitPrice = new Money(DefaultCurrency.EUR, 34.375M, new DateTime(2023,07,11, 9,33,0, DateTimeKind.Utc)), ReferenceCode = "67e39ca1-2f10-4f82-8365-1baad98c398f" } }); @@ -122,8 +122,8 @@ public async Task ConvertActivitiesForAccount_TestFileDividend_WithTax_Converted var parser = new DeGiroParser(api.Object); var fixture = new Fixture(); - var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("NL0009690239", null)).ReturnsAsync(asset); @@ -133,13 +133,13 @@ public async Task ConvertActivitiesForAccount_TestFileDividend_WithTax_Converted // Assert account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, 24.39M, new DateTime(2023, 09, 14, 6, 32, 0, DateTimeKind.Utc))); - account.Activities.Should().BeEquivalentTo(new[] { new Model.Activity { + account.Activities.Should().BeEquivalentTo(new[] { new Activity { Asset = asset, Comment = "Transaction Reference: [Dividend_14-09-2023_06:32_NL0009690239]", Date = new DateTime(2023,09,14,6, 32,0, DateTimeKind.Utc), Fee = null, Quantity = 1, - ActivityType = Model.ActivityType.Dividend, + ActivityType = ActivityType.Dividend, UnitPrice = new Money(DefaultCurrency.EUR, 8.13M, new DateTime(2023,09,14,6, 32,0, DateTimeKind.Utc)), ReferenceCode = "Dividend_14-09-2023_06:32_NL0009690239" } }); @@ -152,8 +152,8 @@ public async Task ConvertActivitiesForAccount_TestFileDividend_NoTax_Converted() var parser = new DeGiroParser(api.Object); var fixture = new Fixture(); - var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("NL0009690239", null)).ReturnsAsync(asset); @@ -163,13 +163,13 @@ public async Task ConvertActivitiesForAccount_TestFileDividend_NoTax_Converted() // Assert account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, 33.96M, new DateTime(2023, 09, 14, 6, 32, 0, DateTimeKind.Utc))); - account.Activities.Should().BeEquivalentTo(new[] { new Model.Activity { + account.Activities.Should().BeEquivalentTo(new[] { new Activity { Asset = asset, Comment = "Transaction Reference: [Dividend_14-09-2023_06:32_NL0009690239]", Date = new DateTime(2023,09,14,6, 32,0, DateTimeKind.Utc), Fee = null, Quantity = 1, - ActivityType = Model.ActivityType.Dividend, + ActivityType = ActivityType.Dividend, UnitPrice = new Money(DefaultCurrency.EUR, 9.57M, new DateTime(2023,09,14,6, 32,0, DateTimeKind.Utc)), ReferenceCode = "Dividend_14-09-2023_06:32_NL0009690239" } }); diff --git a/GhostfolioSidekick.UnitTests/FileImporter/Generic/GenericParserTests.cs b/GhostfolioSidekick.UnitTests/FileImporter/Generic/GenericParserTests.cs index 3db002db..25b0b1db 100644 --- a/GhostfolioSidekick.UnitTests/FileImporter/Generic/GenericParserTests.cs +++ b/GhostfolioSidekick.UnitTests/FileImporter/Generic/GenericParserTests.cs @@ -36,8 +36,8 @@ public async Task ConvertActivitiesForAccount_TestFileSingleOrder_Converted() var parser = new GenericParser(api.Object); var fixture = new Fixture(); - var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.USD)).Create(); + var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.USD)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("US67066G1040", null)).ReturnsAsync(asset); @@ -47,13 +47,13 @@ public async Task ConvertActivitiesForAccount_TestFileSingleOrder_Converted() // Assert account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.USD, -12.123956333000M, new DateTime(2023, 08, 7, 0, 0, 0, DateTimeKind.Utc))); - account.Activities.Should().BeEquivalentTo(new[] { new Model.Activity { + account.Activities.Should().BeEquivalentTo(new[] { new Activity { Asset = asset, Comment = "Transaction Reference: [Buy_US67066G1040_2023-08-07]", Date = new DateTime(2023,08,7, 0,0,0, DateTimeKind.Utc), Fee = new Money(DefaultCurrency.USD, 0.02M, new DateTime(2023,08,7, 0,0,0, DateTimeKind.Utc)), Quantity = 0.0267001M, - ActivityType = Model.ActivityType.Buy, + ActivityType = ActivityType.Buy, UnitPrice = new Money(DefaultCurrency.USD, 453.33M, new DateTime(2023,08,7, 0,0,0, DateTimeKind.Utc)), ReferenceCode = "Buy_US67066G1040_2023-08-07" } }); @@ -66,8 +66,8 @@ public async Task ConvertActivitiesForAccount_TestFileLifecycle_Converted() var parser = new GenericParser(api.Object); var fixture = new Fixture(); - var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.USD)).Create(); + var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.USD)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("US67066G1040", null)).ReturnsAsync(asset); @@ -77,13 +77,13 @@ public async Task ConvertActivitiesForAccount_TestFileLifecycle_Converted() // Assert account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.USD, 589.98M, new DateTime(2023, 08, 8, 0, 0, 0, DateTimeKind.Utc))); - account.Activities.Should().BeEquivalentTo(new[] { new Model.Activity { + account.Activities.Should().BeEquivalentTo(new[] { new Activity { Asset = asset, Comment = "Transaction Reference: [Buy_US67066G1040_2023-08-07]", Date = new DateTime(2023,08,7, 0,0,0, DateTimeKind.Utc), Fee = new Money(DefaultCurrency.USD, 0.02M, new DateTime(2023,08,7, 0,0,0, DateTimeKind.Utc)), Quantity = 4m, - ActivityType = Model.ActivityType.Buy, + ActivityType = ActivityType.Buy, UnitPrice = new Money(DefaultCurrency.USD, 100M, new DateTime(2023,08,7, 0,0,0, DateTimeKind.Utc)), ReferenceCode = "Buy_US67066G1040_2023-08-07" } }); diff --git a/GhostfolioSidekick.UnitTests/FileImporter/Nexo/NexoParserTests.cs b/GhostfolioSidekick.UnitTests/FileImporter/Nexo/NexoParserTests.cs index f5dafcfd..9d2f8dec 100644 --- a/GhostfolioSidekick.UnitTests/FileImporter/Nexo/NexoParserTests.cs +++ b/GhostfolioSidekick.UnitTests/FileImporter/Nexo/NexoParserTests.cs @@ -1,126 +1,126 @@ -//using AutoFixture; -//using FluentAssertions; -//using GhostfolioSidekick.FileImporter.Nexo; -//using GhostfolioSidekick.Ghostfolio.API; -//using GhostfolioSidekick.Model; -//using Moq; - -//namespace GhostfolioSidekick.UnitTests.FileImporter.Nexo -//{ -// public class NexoParserTests -// { -// readonly Mock api; - -// public NexoParserTests() -// { -// api = new Mock(); -// } - -// [Fact] -// public async Task CanParseActivities_TestFileSingleOrder_True() -// { -// // Arrange -// var parser = new NexoParser(api.Object); - -// // Act -// var canParse = await parser.CanParseActivities(new[] { "./FileImporter/TestFiles/Nexo/Example1/Example1.csv" }); - -// // Assert -// canParse.Should().BeTrue(); -// } - -// [Fact] -// public async Task ConvertActivitiesForAccount_TestFileMultipleOrders_ReferalPending_Converted() -// { -// // Arrange -// var parser = new NexoParser(api.Object); -// var fixture = new Fixture(); - -// var asset1 = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); -// var asset2 = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); - -// var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); - -// api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); -// api.Setup(x => x.FindSymbolByISIN("USDC", It.IsAny, Model.Asset>>())).ReturnsAsync(asset1); -// api.Setup(x => x.FindSymbolByISIN("BTC", It.IsAny, Model.Asset>>())).ReturnsAsync(asset2); - -// // Act -// account = await parser.ConvertActivitiesForAccount(account.Name, new[] { "./FileImporter/TestFiles/Nexo/Example1/Example1.csv" }); - -// // Assert -// account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, 0M, new DateTime(2023, 08, 25, 14, 44, 46, DateTimeKind.Utc))); -// account.Activities.Should().BeEquivalentTo(new[] -// { new Model.Activity { -// Asset = asset1, -// Comment = "Transaction Reference: [NXTyPxhiopNL3_2]", -// Date = new DateTime(2023,8,25,14,44,46, DateTimeKind.Utc), -// Fee = null, -// Quantity = 161.90485771M, -// ActivityType = Model.ActivityType.Buy, -// UnitPrice = new Model.Money(asset1.Currency, 0.999969996514813032906620872M, new DateTime(2023,8,25,14,44,46, DateTimeKind.Utc)), -// ReferenceCode = "NXTyPxhiopNL3_2" -// }, new Model.Activity { -// Asset = asset2, -// Comment = "Transaction Reference: [NXTyVJeCwg6Og]", -// Date = new DateTime(2023,8,26, 13,30,38, DateTimeKind.Utc), -// Quantity = 0.00445142M, -// ActivityType = Model.ActivityType.Receive, -// UnitPrice = new Model.Money(asset1.Currency, 26028.386478921332967906870167M, new DateTime(2023,8,26, 13,30,38, DateTimeKind.Utc)), -// ReferenceCode = "NXTyVJeCwg6Og" -// } }); -// } - -// [Fact] -// public async Task ConvertActivitiesForAccount_TestFileMultipleOrders_ReferalApproved_Converted() -// { -// // Arrange -// var parser = new NexoParser(api.Object); -// var fixture = new Fixture(); - -// var asset1 = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); -// var asset2 = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); - -// var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); - -// api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); -// api.Setup(x => x.FindSymbolByISIN("USDC", It.IsAny, Model.Asset>>())).ReturnsAsync(asset1); -// api.Setup(x => x.FindSymbolByISIN("BTC", It.IsAny, Model.Asset>>())).ReturnsAsync(asset2); - -// // Act -// account = await parser.ConvertActivitiesForAccount(account.Name, new[] { "./FileImporter/TestFiles/Nexo/Example2/Example2.csv" }); - -// // Assert -// account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, 0M, new DateTime(2023, 08, 25, 14, 44, 46, DateTimeKind.Utc))); -// account.Activities.Should().BeEquivalentTo(new[] -// { new Model.Activity { -// Asset = asset1, -// Comment = "Transaction Reference: [NXTyPxhiopNL3_2]", -// Date = new DateTime(2023,8,25,14,44,46, DateTimeKind.Utc), -// Fee = null, -// Quantity = 161.90485771M, -// ActivityType = Model.ActivityType.Buy, -// UnitPrice = new Model.Money(asset1.Currency, 0.999969996514813032906620872M, new DateTime(2023,8,25,14,44,46, DateTimeKind.Utc)), -// ReferenceCode = "NXTyPxhiopNL3_2" -// } , new Model.Activity { -// Asset = asset2, -// Comment = "Transaction Reference: [NXTk6FBYyxOqH]", -// Date = new DateTime(2023,08,25,16,43,55, DateTimeKind.Utc), -// Fee = null, -// Quantity = 0.00096332M, -// ActivityType = Model.ActivityType.Receive, -// UnitPrice = new Model.Money(asset1.Currency, 25951.855302495536270398206204M, new DateTime(2023,08,25,16,43,55, DateTimeKind.Utc)), -// ReferenceCode = "NXTk6FBYyxOqH" -// } , new Model.Activity { -// Asset = asset2, -// Comment = "Transaction Reference: [NXTyVJeCwg6Og]", -// Date = new DateTime(2023,8,26, 13,30,38, DateTimeKind.Utc), -// Fee = null, -// Quantity = 0.00445142M, -// ActivityType = Model.ActivityType.Receive, -// UnitPrice = new Model.Money(asset1.Currency, 26028.386478921332967906870167M, new DateTime(2023,8,26, 13,30,38, DateTimeKind.Utc)), -// ReferenceCode = "NXTyVJeCwg6Og" -// } }); -// } -// } -//} \ No newline at end of file +using AutoFixture; +using FluentAssertions; +using GhostfolioSidekick.FileImporter.Nexo; +using GhostfolioSidekick.Ghostfolio.API; +using GhostfolioSidekick.Model; +using Moq; + +namespace GhostfolioSidekick.UnitTests.FileImporter.Nexo +{ + public class NexoParserTests + { + readonly Mock api; + + public NexoParserTests() + { + api = new Mock(); + } + + [Fact] + public async Task CanParseActivities_TestFileSingleOrder_True() + { + // Arrange + var parser = new NexoParser(api.Object); + + // Act + var canParse = await parser.CanParseActivities(new[] { "./FileImporter/TestFiles/Nexo/Example1/Example1.csv" }); + + // Assert + canParse.Should().BeTrue(); + } + + [Fact] + public async Task ConvertActivitiesForAccount_TestFileMultipleOrders_ReferalPending_Converted() + { + // Arrange + var parser = new NexoParser(api.Object); + var fixture = new Fixture(); + + var asset1 = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); + var asset2 = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); + + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + + api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); + api.Setup(x => x.FindSymbolByISIN("USDC", It.IsAny, Asset>>())).ReturnsAsync(asset1); + api.Setup(x => x.FindSymbolByISIN("BTC", It.IsAny, Asset>>())).ReturnsAsync(asset2); + + // Act + account = await parser.ConvertActivitiesForAccount(account.Name, new[] { "./FileImporter/TestFiles/Nexo/Example1/Example1.csv" }); + + // Assert + account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, -11.9M, new DateTime(2023, 08, 25, 14, 44, 46, DateTimeKind.Utc))); + account.Activities.Should().BeEquivalentTo(new[] + { new Activity { + Asset = asset1, + Comment = "Transaction Reference: [NXTyPxhiopNL3]", + Date = new DateTime(2023,8,25,14,44,46, DateTimeKind.Utc), + Fee = null, + Quantity = 161.90485771M, + ActivityType = ActivityType.Buy, + UnitPrice = new Money(asset1.Currency, 0.999969996514813032906620872M, new DateTime(2023,8,25,14,44,46, DateTimeKind.Utc)), + ReferenceCode = "NXTyPxhiopNL3" + }, new Activity { + Asset = asset2, + Comment = "Transaction Reference: [NXTyVJeCwg6Og]", + Date = new DateTime(2023,8,26, 13,30,38, DateTimeKind.Utc), + Quantity = 0.00445142M, + ActivityType = ActivityType.Receive, + UnitPrice = new Money(asset1.Currency, 26028.386478921332967906870167M, new DateTime(2023,8,26, 13,30,38, DateTimeKind.Utc)), + ReferenceCode = "NXTyVJeCwg6Og" + } }); + } + + [Fact] + public async Task ConvertActivitiesForAccount_TestFileMultipleOrders_ReferalApproved_Converted() + { + // Arrange + var parser = new NexoParser(api.Object); + var fixture = new Fixture(); + + var asset1 = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); + var asset2 = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); + + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + + api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); + api.Setup(x => x.FindSymbolByISIN("USDC", It.IsAny, Asset>>())).ReturnsAsync(asset1); + api.Setup(x => x.FindSymbolByISIN("BTC", It.IsAny, Asset>>())).ReturnsAsync(asset2); + + // Act + account = await parser.ConvertActivitiesForAccount(account.Name, new[] { "./FileImporter/TestFiles/Nexo/Example2/Example2.csv" }); + + // Assert + account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, -11.90000000000000000000000000M, new DateTime(2023, 08, 25, 14, 44, 46, DateTimeKind.Utc))); + account.Activities.Should().BeEquivalentTo(new[] + { new Activity { + Asset = asset1, + Comment = "Transaction Reference: [NXTyPxhiopNL3]", + Date = new DateTime(2023,8,25,14,44,46, DateTimeKind.Utc), + Fee = null, + Quantity = 161.90485771M, + ActivityType = ActivityType.Buy, + UnitPrice = new Money(asset1.Currency, 0.999969996514813032906620872M, new DateTime(2023,8,25,14,44,46, DateTimeKind.Utc)), + ReferenceCode = "NXTyPxhiopNL3" + }, new Activity { + Asset = asset2, + Comment = "Transaction Reference: [NXTk6FBYyxOqH]", + Date = new DateTime(2023,08,25,16,43,55, DateTimeKind.Utc), + Fee = null, + Quantity = 0.00096332M, + ActivityType = ActivityType.Receive, + UnitPrice = new Money(asset1.Currency, 25951.855302495536270398206204M, new DateTime(2023,08,25,16,43,55, DateTimeKind.Utc)), + ReferenceCode = "NXTk6FBYyxOqH" + }, new Activity { + Asset = asset2, + Comment = "Transaction Reference: [NXTyVJeCwg6Og]", + Date = new DateTime(2023,8,26, 13,30,38, DateTimeKind.Utc), + Fee = null, + Quantity = 0.00445142M, + ActivityType = ActivityType.Receive, + UnitPrice = new Money(asset1.Currency, 26028.386478921332967906870167M, new DateTime(2023,8,26, 13,30,38, DateTimeKind.Utc)), + ReferenceCode = "NXTyVJeCwg6Og" + }}); + } + } +} \ No newline at end of file diff --git a/GhostfolioSidekick.UnitTests/FileImporter/ScalableCapital/ScalableCapitalParserTests.cs b/GhostfolioSidekick.UnitTests/FileImporter/ScalableCapital/ScalableCapitalParserTests.cs index 92b1283f..059dde86 100644 --- a/GhostfolioSidekick.UnitTests/FileImporter/ScalableCapital/ScalableCapitalParserTests.cs +++ b/GhostfolioSidekick.UnitTests/FileImporter/ScalableCapital/ScalableCapitalParserTests.cs @@ -49,8 +49,8 @@ public async Task ConvertActivitiesForAccount_Example1_OrderOnly() var parser = new ScalableCapitalParser(api.Object); var fixture = new Fixture(); - var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("IE00077FRP95", null)).ReturnsAsync(asset); @@ -59,13 +59,13 @@ public async Task ConvertActivitiesForAccount_Example1_OrderOnly() account = await parser.ConvertActivitiesForAccount(account.Name, new[] { "./FileImporter/TestFiles/ScalableCapital/Example1/WUMExample1.csv" }); // Assert - account.Activities.Should().BeEquivalentTo(new[] { new Model.Activity { + account.Activities.Should().BeEquivalentTo(new[] { new Activity { Asset = asset, Comment = "Transaction Reference: [SCALQbWiZnN9DtQ]", Date = new DateTime(2023,8,3, 14,43,17, 650, DateTimeKind.Utc), Fee = null, Quantity = 5, - ActivityType = Model.ActivityType.Buy, + ActivityType = ActivityType.Buy, UnitPrice = new Money(DefaultCurrency.EUR, 8.685M, new DateTime(2023,8,3, 14,43,17, 650, DateTimeKind.Utc)), ReferenceCode = "SCALQbWiZnN9DtQ" } }); @@ -78,8 +78,8 @@ public async Task ConvertActivitiesForAccount_Example1_DividendOnly() var parser = new ScalableCapitalParser(api.Object); var fixture = new Fixture(); - var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("US92343V1044", null)).ReturnsAsync(asset); @@ -89,13 +89,13 @@ public async Task ConvertActivitiesForAccount_Example1_DividendOnly() // Assert account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, 696.85M, new DateTime(2023, 08, 2, 0, 0, 0, DateTimeKind.Utc))); - account.Activities.Should().BeEquivalentTo(new[] { new Model.Activity { + account.Activities.Should().BeEquivalentTo(new[] { new Activity { Asset = asset, Comment = "Transaction Reference: [WWEK 16100100]", Date = new DateTime(2023,8,1, 0,0,0, DateTimeKind.Utc), Fee = null, Quantity = 14, - ActivityType = Model.ActivityType.Dividend, + ActivityType = ActivityType.Dividend, UnitPrice = new Money(DefaultCurrency.EUR, 0.5057142857142857142857142857M, new DateTime(2023,8,1, 0,0,0, DateTimeKind.Utc)), ReferenceCode = "WWEK 16100100" } }); @@ -108,9 +108,9 @@ public async Task ConvertActivitiesForAccount_Example1_Both() var parser = new ScalableCapitalParser(api.Object); var fixture = new Fixture(); - var asset1 = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); - var asset2 = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var asset1 = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); + var asset2 = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("IE00077FRP95", null)).ReturnsAsync(asset1); @@ -124,23 +124,23 @@ public async Task ConvertActivitiesForAccount_Example1_Both() // Assert account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, 696.85M, new DateTime(2023, 08, 2, 0, 0, 0, DateTimeKind.Utc))); account.Activities.Should().BeEquivalentTo(new[] { - new Model.Activity { + new Activity { Asset = asset1, Comment = "Transaction Reference: [SCALQbWiZnN9DtQ]", Date = new DateTime(2023,8,3, 14,43,17, 650, DateTimeKind.Utc), Fee = new Money(DefaultCurrency.EUR, 0.99M, new DateTime(2023,8,3, 14,43,17, 650, DateTimeKind.Utc)), Quantity = 5, - ActivityType = Model.ActivityType.Buy, + ActivityType = ActivityType.Buy, UnitPrice = new Money(DefaultCurrency.EUR, 8.685M, new DateTime(2023,8,3, 14,43,17, 650, DateTimeKind.Utc)), ReferenceCode = "SCALQbWiZnN9DtQ" }, - new Model.Activity { + new Activity { Asset = asset2, Comment = "Transaction Reference: [WWEK 16100100]", Date = new DateTime(2023,8,1, 0,0,0, DateTimeKind.Utc), Fee = null, Quantity = 14, - ActivityType = Model.ActivityType.Dividend, + ActivityType = ActivityType.Dividend, UnitPrice = new Money(DefaultCurrency.EUR, 0.5057142857142857142857142857M, new DateTime(2023,8,1, 0,0,0, DateTimeKind.Utc)), ReferenceCode = "WWEK 16100100" } }); @@ -153,9 +153,9 @@ public async Task ConvertActivitiesForAccount_Example2_NotDuplicateFeesAndDivide var parser = new ScalableCapitalParser(api.Object); var fixture = new Fixture(); - var asset1 = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); - var asset2 = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var asset1 = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); + var asset2 = fixture.Build().With(x => x.Currency, DefaultCurrency.EUR).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("IE00077FRP95", null)).ReturnsAsync(asset1); @@ -170,23 +170,23 @@ public async Task ConvertActivitiesForAccount_Example2_NotDuplicateFeesAndDivide // Assert account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, 696.85M, new DateTime(2023, 08, 2, 0, 0, 0, DateTimeKind.Utc))); account.Activities.Should().BeEquivalentTo(new[] { - new Model.Activity { + new Activity { Asset = asset1, Comment = "Transaction Reference: [SCALQbWiZnN9DtQ]", Date = new DateTime(2023,8,3, 14,43,17, 650, DateTimeKind.Utc), Fee = new Money(DefaultCurrency.EUR, 0.99M, new DateTime(2023,8,3, 14,43,17, 650, DateTimeKind.Utc)), Quantity = 5, - ActivityType = Model.ActivityType.Buy, + ActivityType = ActivityType.Buy, UnitPrice = new Money(DefaultCurrency.EUR, 8.685M, new DateTime(2023,8,3, 14,43,17, 650, DateTimeKind.Utc)), ReferenceCode = "SCALQbWiZnN9DtQ" }, - new Model.Activity { + new Activity { Asset = asset2, Comment = "Transaction Reference: [WWEK 16100100]", Date = new DateTime(2023,8,1, 0,0,0, DateTimeKind.Utc), Fee = null, Quantity = 14, - ActivityType = Model.ActivityType.Dividend, + ActivityType = ActivityType.Dividend, UnitPrice = new Money(DefaultCurrency.EUR, 0.5057142857142857142857142857M, new DateTime(2023,8,1, 0,0,0, DateTimeKind.Utc)), ReferenceCode = "WWEK 16100100" } }); diff --git a/GhostfolioSidekick.UnitTests/FileImporter/TestFiles/Nexo/Example2/Example2.csv b/GhostfolioSidekick.UnitTests/FileImporter/TestFiles/Nexo/Example2/Example2.csv index 97255859..93c0e445 100644 --- a/GhostfolioSidekick.UnitTests/FileImporter/TestFiles/Nexo/Example2/Example2.csv +++ b/GhostfolioSidekick.UnitTests/FileImporter/TestFiles/Nexo/Example2/Example2.csv @@ -1,7 +1,6 @@ Transaction,Type,Input Currency,Input Amount,Output Currency,Output Amount,USD Equivalent,Details,Date / Time NXT2nBRTjakWQn7hRAXE1evul,UnlockingTermDeposit,BTC,0.00445142,BTC,0.00445142,$117.03156265,"approved / Transfer from Term Wallet to Savings Wallet",2023-09-26 07:00:00 NXT6MIn1vd9eRGVUzGMClmRsR,Interest,USDC,0.00184300,USDC,0.00184300,$0.00184294,"approved / USDC Interest Earned",2023-09-21 07:00:00 -NXT5YK2DM1A8srzkLGiLaol31,Interest,USDC,0.00184300,USDC,0.00184300,$0.00184331,"approved / USDC Interest Earned",2023-09-20 07:00:00 NXTJXwdAl7oDx,LockingTermDeposit,BTC,-0.00445142,BTC,0.00445142,$115.89390996,"approved / Transfer from Savings Wallet to Term Wallet",2023-08-26 13:31:47 NXTyVJeCwg6Og,Deposit,BTC,0.00445142,BTC,0.00445142,$115.86328014,"approved / 6f287e436c5255d6227cc0627b58df45ed7a016c7d300f7cf2640476ab2bbf9c",2023-08-26 13:30:38 NXTk6FBYyxOqH,ReferralBonus,BTC,0.00096332,BTC,0.00096332,$24.99994125,"approved / Referral bonus",2023-08-25 16:43:55 diff --git a/GhostfolioSidekick.UnitTests/FileImporter/Trading212/Trading212Tests.cs b/GhostfolioSidekick.UnitTests/FileImporter/Trading212/Trading212Tests.cs index f45ec6bd..dea05e81 100644 --- a/GhostfolioSidekick.UnitTests/FileImporter/Trading212/Trading212Tests.cs +++ b/GhostfolioSidekick.UnitTests/FileImporter/Trading212/Trading212Tests.cs @@ -36,8 +36,8 @@ public async Task ConvertActivitiesForAccount_TestFileSingleOrder_Converted() var parser = new Trading212Parser(api.Object); var fixture = new Fixture(); - var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("US67066G1040", null)).ReturnsAsync(asset); @@ -47,23 +47,23 @@ public async Task ConvertActivitiesForAccount_TestFileSingleOrder_Converted() // Assert account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, 98.906043667000M, new DateTime(2023, 08, 11, 21, 8, 18, DateTimeKind.Utc))); - account.Activities.Should().BeEquivalentTo(new[] { new Model.Activity { + account.Activities.Should().BeEquivalentTo(new[] { new Activity { Asset = asset, Comment = "Transaction Reference: [EOF3219953148]", Date = new DateTime(2023,08,7, 19,56,2, DateTimeKind.Utc), Fee = new Money(DefaultCurrency.EUR, 0.02M, new DateTime(2023,08,7, 19,56,2, DateTimeKind.Utc)), Quantity = 0.0267001M, - ActivityType = Model. ActivityType.Buy, + ActivityType = ActivityType.Buy, UnitPrice = new Money(DefaultCurrency.USD,453.33M, new DateTime(2023,08,7, 19,56,2, DateTimeKind.Utc)), ReferenceCode = "EOF3219953148" }, - new Model.Activity { + new Activity { Asset = null, Comment = "Transaction Reference: [82f82014-23a3-4ddf-bc09-658419823f4c]", Date = new DateTime(2023,08,11, 21,08,18, DateTimeKind.Utc), Fee = null, Quantity = 1M, - ActivityType = Model. ActivityType.Interest, + ActivityType = ActivityType.Interest, UnitPrice = new Money(DefaultCurrency.EUR,0.01M, new DateTime(2023,08,11, 21,08,18, DateTimeKind.Utc)), ReferenceCode = "82f82014-23a3-4ddf-bc09-658419823f4c" }}); @@ -76,8 +76,8 @@ public async Task ConvertActivitiesForAccount_TestFileMultipleOrdersUS_Converted var parser = new Trading212Parser(api.Object); var fixture = new Fixture(); - var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("US67066G1040", null)).ReturnsAsync(asset); @@ -88,23 +88,23 @@ public async Task ConvertActivitiesForAccount_TestFileMultipleOrdersUS_Converted // Assert account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, -13.232829008000M, new DateTime(2023, 08, 9, 15, 25, 08, DateTimeKind.Utc))); account.Activities.Should().BeEquivalentTo(new[] { - new Model.Activity { + new Activity { Asset = asset, Comment = "Transaction Reference: [EOF3219953148]", Date = new DateTime(2023,08,7, 19,56,2, DateTimeKind.Utc), Fee = new Money(DefaultCurrency.EUR,0.02M, new DateTime(2023,08,7, 19,56,2, DateTimeKind.Utc)), Quantity = 0.0267001M, - ActivityType = Model.ActivityType.Buy, + ActivityType = ActivityType.Buy, UnitPrice = new Money(DefaultCurrency.USD,453.33M, new DateTime(2023,08,7, 19,56,2, DateTimeKind.Utc)), ReferenceCode = "EOF3219953148" }, - new Model.Activity { + new Activity { Asset = asset, Comment = "Transaction Reference: [EOF3224031567]", Date = new DateTime(2023,08,9, 15,25,8, DateTimeKind.Utc), Fee = null, Quantity = 0.0026199M, - ActivityType = Model.ActivityType.Buy, + ActivityType = ActivityType.Buy, UnitPrice = new Money(DefaultCurrency.USD,423.25M, new DateTime(2023,08,9, 15,25,8, DateTimeKind.Utc)), ReferenceCode = "EOF3224031567" }}); @@ -117,8 +117,8 @@ public async Task ConvertActivitiesForAccount_TestFileSingleOrderUK_Converted() var parser = new Trading212Parser(api.Object); var fixture = new Fixture(); - var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.GBX).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.GBX).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("GB0007188757", null)).ReturnsAsync(asset); @@ -127,13 +127,13 @@ public async Task ConvertActivitiesForAccount_TestFileSingleOrderUK_Converted() account = await parser.ConvertActivitiesForAccount(account.Name, new[] { "./FileImporter/TestFiles/Trading212/Example3/TestFileSingleOrderUK.csv" }); // Assert - account.Activities.Should().BeEquivalentTo(new[] { new Model.Activity { + account.Activities.Should().BeEquivalentTo(new[] { new Activity { Asset = asset, Comment = "Transaction Reference: [EOF3224031549]", Date = new DateTime(2023,08,9, 15,25,8, DateTimeKind.Utc), Fee = new Money(DefaultCurrency.EUR,0.07M, new DateTime(2023,08,9, 15,25,8, DateTimeKind.Utc)), Quantity = 0.18625698M, - ActivityType = Model.ActivityType.Buy, + ActivityType = ActivityType.Buy, UnitPrice = new Money(DefaultCurrency.GBX,4947.00M, new DateTime(2023,08,9, 15,25,8, DateTimeKind.Utc)), ReferenceCode = "EOF3224031549" } }); @@ -146,8 +146,8 @@ public async Task ConvertActivitiesForAccount_TestFileSingleDividend_Converted() var parser = new Trading212Parser(api.Object); var fixture = new Fixture(); - var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("US0378331005", null)).ReturnsAsync(asset); @@ -157,13 +157,13 @@ public async Task ConvertActivitiesForAccount_TestFileSingleDividend_Converted() // Assert account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, 0.025583540000M, new DateTime(2023, 08, 17, 10, 49, 49, DateTimeKind.Utc))); - account.Activities.Should().BeEquivalentTo(new[] { new Model.Activity { + account.Activities.Should().BeEquivalentTo(new[] { new Activity { Asset = asset, Comment = "Transaction Reference: [Dividend_US0378331005_2023-08-17]", Date = new DateTime(2023,08,17, 10,49,49, DateTimeKind.Utc), Fee = null, Quantity = 0.1279177000M, - ActivityType = Model.ActivityType.Dividend, + ActivityType = ActivityType.Dividend, UnitPrice = new Money(DefaultCurrency.USD, 0.20M, new DateTime(2023,08,17, 10,49,49, DateTimeKind.Utc)), ReferenceCode = "Dividend_US0378331005_2023-08-17" } }); @@ -176,8 +176,8 @@ public async Task ConvertActivitiesForAccount_TestFileSingleOrderUKNativeCurrenc var parser = new Trading212Parser(api.Object); var fixture = new Fixture(); - var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.GBX).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.GBX).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("GB0007188757", null)).ReturnsAsync(asset); @@ -186,13 +186,13 @@ public async Task ConvertActivitiesForAccount_TestFileSingleOrderUKNativeCurrenc account = await parser.ConvertActivitiesForAccount(account.Name, new[] { "./FileImporter/TestFiles/Trading212/Example5/TestFileSingleOrderUKNativeCurrency.csv" }); // Assert - account.Activities.Should().BeEquivalentTo(new[] { new Model.Activity { + account.Activities.Should().BeEquivalentTo(new[] { new Activity { Asset = asset, Comment = "Transaction Reference: [EOF3224031549]", Date = new DateTime(2023,08,9, 15,25,8, DateTimeKind.Utc), Fee = new Money(DefaultCurrency.GBP,0.05M, new DateTime(2023,08,9, 15,25,8, DateTimeKind.Utc)), Quantity = 0.18625698M, - ActivityType = Model.ActivityType.Buy, + ActivityType = ActivityType.Buy, UnitPrice = new Money(DefaultCurrency.GBX,4947.00M, new DateTime(2023,08,9, 15,25,8, DateTimeKind.Utc)), ReferenceCode = "EOF3224031549" } }); @@ -205,8 +205,8 @@ public async Task ConvertActivitiesForAccount_TestFileSingleOrderMultipleTimes_C var parser = new Trading212Parser(api.Object); var fixture = new Fixture(); - var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var asset = fixture.Build().With(x => x.Currency, DefaultCurrency.USD).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); api.Setup(x => x.FindSymbolByISIN("US67066G1040", null)).ReturnsAsync(asset); @@ -220,13 +220,13 @@ public async Task ConvertActivitiesForAccount_TestFileSingleOrderMultipleTimes_C // Assert account.Balance.Current(DummyPriceConverter.Instance).Should().BeEquivalentTo(new Money(DefaultCurrency.EUR, 98.896043667000M, new DateTime(2023, 08, 7, 19, 56, 02, DateTimeKind.Utc))); - account.Activities.Should().BeEquivalentTo(new[] { new Model. Activity { + account.Activities.Should().BeEquivalentTo(new[] { new Activity { Asset = asset, Comment = "Transaction Reference: [EOF3219953148]", Date = new DateTime(2023,08,7, 19,56,2, DateTimeKind.Utc), Fee = new Money(DefaultCurrency.EUR,0.02M, new DateTime(2023,08,7, 19,56,2, DateTimeKind.Utc)), Quantity = 0.0267001M, - ActivityType = Model.ActivityType.Buy, + ActivityType = ActivityType.Buy, UnitPrice = new Money(DefaultCurrency.USD,453.33M, new DateTime(2023,08,7, 19,56,2, DateTimeKind.Utc)), ReferenceCode = "EOF3219953148" }}); @@ -240,7 +240,7 @@ public async Task ConvertActivitiesForAccount_TestFileCurrencyConversion_Convert var parser = new Trading212Parser(api.Object); var fixture = new Fixture(); - var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); + var account = fixture.Build().With(x => x.Balance, Balance.Empty(DefaultCurrency.EUR)).Create(); api.Setup(x => x.GetAccountByName(account.Name)).ReturnsAsync(account); diff --git a/GhostfolioSidekick/FileImporter/CryptoRecordBaseImporter.cs b/GhostfolioSidekick/FileImporter/CryptoRecordBaseImporter.cs index 9fc4b98c..7e4072e1 100644 --- a/GhostfolioSidekick/FileImporter/CryptoRecordBaseImporter.cs +++ b/GhostfolioSidekick/FileImporter/CryptoRecordBaseImporter.cs @@ -9,7 +9,7 @@ protected CryptoRecordBaseImporter(IGhostfolioAPI api) : base(api) { } - protected async Task GetCorrectUnitPrice(Money originalUnitPrice, Model.Asset? symbol, DateTime date) + protected async Task GetCorrectUnitPrice(Money originalUnitPrice, Asset? symbol, DateTime date) { if (originalUnitPrice.Amount > 0) { @@ -21,7 +21,7 @@ protected async Task GetCorrectUnitPrice(Money originalUnitPrice, Model.A return price; } - protected Model.Asset? ParseFindSymbolByISINResult(string assetName, string symbol, IEnumerable assets) + protected Asset? ParseFindSymbolByISINResult(string assetName, string symbol, IEnumerable assets) { var cryptoOnly = assets.Where(x => x.AssetSubClass == "CRYPTOCURRENCY"); var asset = cryptoOnly.FirstOrDefault(x => assetName == x.Name); @@ -42,15 +42,5 @@ protected async Task GetCorrectUnitPrice(Money originalUnitPrice, Model.A return asset; } - - protected Model.ActivityType HandleConvertActivityType(Model.ActivityType value) - { - if (value == Model.ActivityType.Convert) - { - return Model.ActivityType.Sell; - } - - return value; - } } } diff --git a/GhostfolioSidekick/FileImporter/Nexo/NexoParser.cs b/GhostfolioSidekick/FileImporter/Nexo/NexoParser.cs index 572a5d86..3cd21103 100644 --- a/GhostfolioSidekick/FileImporter/Nexo/NexoParser.cs +++ b/GhostfolioSidekick/FileImporter/Nexo/NexoParser.cs @@ -1,194 +1,149 @@ -//using CsvHelper.Configuration; -//using GhostfolioSidekick.Ghostfolio.API; -//using GhostfolioSidekick.Model; -//using System.Globalization; - -//namespace GhostfolioSidekick.FileImporter.Nexo -//{ -// public class NexoParser : CryptoRecordBaseImporter -// { -// private Model.Asset[] fiat = new[] { -// new Model.Asset(new Model.Currency("EUR"), "EUR", "EUR", null, null, null), -// new Model.Asset(new Model.Currency("USD"), "USD", "USD", null, null, null) -// }; - -// private Model.Asset[] fiatCoin = new[] { -// new Model.Asset(new Model.Currency("EUR"), "EURX", "EURX", null, null, null), -// new Model.Asset(new Model.Currency("USD"), "USDX", "USDX", null, null, null) -// }; - -// public NexoParser(IGhostfolioAPI api) : base(api) -// { -// } - -// protected override async Task> ConvertOrders(NexoRecord record, Model.Account account, IEnumerable allRecords) -// { -// var activityType = GetOrderTypeCrypto(record); -// if (activityType == null || !record.Details.StartsWith("approved")) -// { -// return Array.Empty(); -// } - -// var activities = new List(); -// if (HandleDepositAndWithdrawel(record, activities)) -// { -// return activities; -// } - -// var assetName = record.InputCurrency; -// var sellAsset = await GetAsset(assetName); - -// var sellActivity = new Model.Activity -// { -// Asset = sellAsset, -// Date = record.DateTime, -// Comment = $"Transaction Reference: [{record.Transaction}]", -// Fee = null, -// Quantity = record.InputAmount, -// ActivityType = HandleConvertActivityType(activityType.Value), -// UnitPrice = GetUnitPrice(record, false), -// ReferenceCode = record.Transaction, -// }; -// activities.Add(sellActivity); - -// var buyAssetName = record.OutputCurrency; -// var buyAsset = await GetAsset(buyAssetName); - -// var refCode = record.Transaction + "_2"; -// var orderBuy = new Model.Activity -// { -// Asset = buyAsset, -// Date = record.DateTime, -// Comment = $"Transaction Reference: [{refCode}]", -// Fee = null, -// Quantity = record.OutputAmount, -// ActivityType = Model.ActivityType.Buy, -// UnitPrice = GetUnitPrice(record, true), -// ReferenceCode = refCode, -// }; - -// if (activityType != Model.ActivityType.Receive) -// { -// activities.Add(orderBuy); -// } - -// // Filter out fiat currency -// return activities.Where(FilterEmptyBuysAndSells); - -// async Task GetAsset(string assetName) -// { -// return await api.FindSymbolByISIN(assetName, x => -// ParseFindSymbolByISINResult(assetName, assetName, x)); -// } -// } - -// private bool FilterEmptyBuysAndSells(Model.Activity activity) -// { -// switch (activity.ActivityType) -// { -// case Model.ActivityType.Buy: -// case Model.ActivityType.Sell: -// return activity.Asset != null; -// case Model.ActivityType.Dividend: -// case Model.ActivityType.Send: -// case Model.ActivityType.Receive: -// case Model.ActivityType.Interest: -// case Model.ActivityType.Gift: -// case Model.ActivityType.LearningReward: -// case Model.ActivityType.StakingReward: -// case Model.ActivityType.Convert: -// case Model.ActivityType.CashDeposit: -// case Model.ActivityType.CashWithdrawal: -// return true; -// default: -// throw new NotSupportedException(); -// } -// } - -// protected override void SetActivitiesToAccount(Model.Account account, ICollection values) -// { -// base.SetActivitiesToAccount(account, values); - -// // Fix balance -// account.Balance.Empty(); -// account.Balance.Calculate(values.Where(x => x.Asset == null).ToList()); -// } - -// private Money GetUnitPrice(NexoRecord record, bool isOutput) -// { -// var currency = isOutput ? record.OutputCurrency : record.InputCurrency; -// var amount = isOutput ? record.OutputAmount : record.InputAmount; -// var fiatCoinCurrency = fiatCoin.Any(x => x.Symbol == currency); - -// if (fiatCoinCurrency == false) -// { -// return new Model.Money("USD", record.GetUSDEquivalent() / amount, record.DateTime); -// } - -// return new Model.Money(currency, 1, record.DateTime); -// } - -// protected override CsvConfiguration GetConfig() -// { -// return new CsvConfiguration(CultureInfo.InvariantCulture) -// { -// HasHeaderRecord = true, -// CacheFields = true, -// Delimiter = ",", -// }; -// } - -// private Model.ActivityType? GetOrderTypeCrypto(NexoRecord record) -// { -// switch (record.Type) -// { -// case "ReferralBonus": // TODO: Should be a 'reward' -// case "Deposit": -// return Model.ActivityType.Receive; -// case "Exchange": -// return Model.ActivityType.Convert; -// case "DepositToExchange": -// return Model.ActivityType.CashDeposit; -// case "LockingTermDeposit": -// case "UnlockingTermDeposit": -// case "ExchangeDepositedOn": -// case "FixedTermInterest": // TODO: Should be a 'reward' -// case "Interest": // TODO: Should be a 'reward' -// return null; -// default: throw new NotSupportedException($"{record.Type}"); -// } -// } - -// private bool HandleDepositAndWithdrawel(NexoRecord record, List activities) -// { -// var inFiat = fiat.Any(x => x.Symbol == record.InputCurrency); -// var outFiat = fiat.Any(x => x.Symbol == record.OutputCurrency); - -// var inFiatCoin = fiatCoin.Any(x => x.Symbol == record.InputCurrency); -// var outFiatCoin = fiatCoin.Any(x => x.Symbol == record.OutputCurrency); - -// var deposit = inFiat && outFiatCoin; -// var withdrawl = inFiatCoin && outFiat; - -// if (!deposit && !withdrawl) -// { -// return false; -// } - -// var refCode = $"Cash_Change_{record.DateTime}"; -// var activity = new Model.Activity -// { -// Asset = null, -// Date = record.DateTime, -// Comment = $"Transaction Reference: [{refCode}]", -// Fee = null, -// Quantity = record.OutputAmount, -// ActivityType = deposit ? Model.ActivityType.CashDeposit : Model.ActivityType.CashWithdrawal, -// UnitPrice = new Model.Money(CurrencyHelper.ParseCurrency(deposit ? record.InputCurrency : record.OutputCurrency), 1, record.DateTime), -// ReferenceCode = refCode, -// }; -// activities.Add(activity); -// return true; -// } -// } -//} +using CsvHelper.Configuration; +using GhostfolioSidekick.Ghostfolio.API; +using GhostfolioSidekick.Model; +using System.Globalization; + +namespace GhostfolioSidekick.FileImporter.Nexo +{ + public class NexoParser : CryptoRecordBaseImporter + { + private Asset[] fiatCoin = new[] { + new Asset(new Currency("EUR"), "EURX", "EURX", null, null, null), + new Asset(new Currency("USD"), "USDX", "USDX", null, null, null), + new Asset(new Currency("EUR"), "EUR", "EUR", null, null, null), + new Asset(new Currency("USD"), "USD", "USD", null, null, null) + }; + + public NexoParser(IGhostfolioAPI api) : base(api) + { + } + + protected override async Task> ConvertOrders(NexoRecord record, Account account, IEnumerable allRecords) + { + if (!record.Details.StartsWith("approved")) + { + return Array.Empty(); + } + + var activities = new List(); + + var inputAsset = await GetAsset(record.InputCurrency); + var inputActivity = new Activity + { + Asset = inputAsset, + Date = record.DateTime, + Comment = $"Transaction Reference: [{record.Transaction}]", + Fee = null, + Quantity = record.InputAmount, + ActivityType = ActivityType.Undefined, + UnitPrice = GetUnitPrice(record, false), + ReferenceCode = record.Transaction, + }; + + var outputAsset = await GetAsset(record.OutputCurrency); + var refCode = record.Transaction; + var outputActivity = new Activity + { + Asset = outputAsset, + Date = record.DateTime, + Comment = $"Transaction Reference: [{refCode}]", + Fee = null, + Quantity = record.OutputAmount, + ActivityType = ActivityType.Undefined, + UnitPrice = GetUnitPrice(record, true), + ReferenceCode = refCode, + }; + + activities.AddRange(HandleRecord(record, inputActivity, outputActivity)); + + return activities; + + async Task GetAsset(string assetName) + { + if (fiatCoin.Any(x => x.Symbol == assetName)) + { + return null; + } + + return await api.FindSymbolByISIN(assetName, x => + ParseFindSymbolByISINResult(assetName, assetName, x)); + } + } + + private IEnumerable HandleRecord(NexoRecord record, Activity inputActivity, Activity outputActivity) + { + switch (record.Type) + { + case "ReferralBonus": // TODO: Should be a 'reward' + case "Deposit": + return new[] { SetActivity(outputActivity, ActivityType.Receive) }; + case "ExchangeDepositedOn": + case "Exchange": + return HandleConversion(record, inputActivity, outputActivity); + case "Interest": + case "FixedTermInterest": + // return new[] { SetActivity(outputActivity, ActivityType.Interest) }; // Staking rewards are not yet supported + case "DepositToExchange": + case "LockingTermDeposit": + case "UnlockingTermDeposit": + return Enumerable.Empty(); + default: throw new NotSupportedException($"{record.Type}"); + } + } + + private Activity SetActivity(Activity outputActivity, ActivityType activityType) + { + outputActivity.ActivityType = activityType; + return outputActivity; + } + + private IEnumerable HandleConversion(NexoRecord record, Activity inputActivity, Activity outputActivity) + { + var inFiatCoin = inputActivity.Asset == null && fiatCoin.Any(x => x.Symbol == inputActivity.UnitPrice.Currency.Symbol); + var outFiatCoin = outputActivity.Asset == null && fiatCoin.Any(x => x.Symbol == outputActivity.UnitPrice.Currency.Symbol); + + if (inFiatCoin && !outFiatCoin) + { + outputActivity.ActivityType = ActivityType.Buy; + return new[] { outputActivity }; + } + if (!inFiatCoin && outFiatCoin) + { + inputActivity.ActivityType = ActivityType.Sell; + return new[] { inputActivity }; + } + + if (inFiatCoin && outFiatCoin) + { + inputActivity.ActivityType = ActivityType.CashDeposit; + return new[] { inputActivity }; + } + + throw new NotSupportedException(); + } + + private Money GetUnitPrice(NexoRecord record, bool isOutput) + { + var currency = isOutput ? record.OutputCurrency : record.InputCurrency; + var amount = isOutput ? record.OutputAmount : record.InputAmount; + var fiatCoinCurrency = fiatCoin.Any(x => x.Symbol == currency); + + if (fiatCoinCurrency == false) + { + return new Money("USD", record.GetUSDEquivalent() / amount, record.DateTime); + } + + return new Money(currency, 1, record.DateTime); + } + + protected override CsvConfiguration GetConfig() + { + return new CsvConfiguration(CultureInfo.InvariantCulture) + { + HasHeaderRecord = true, + CacheFields = true, + Delimiter = ",", + }; + } + } +} diff --git a/GhostfolioSidekick/FileImporter/Nexo/NexoRecord.cs b/GhostfolioSidekick/FileImporter/Nexo/NexoRecord.cs index 209babdf..92f1f99f 100644 --- a/GhostfolioSidekick/FileImporter/Nexo/NexoRecord.cs +++ b/GhostfolioSidekick/FileImporter/Nexo/NexoRecord.cs @@ -1,40 +1,40 @@ -//using CsvHelper.Configuration.Attributes; -//using System.Globalization; +using CsvHelper.Configuration.Attributes; +using System.Globalization; -//namespace GhostfolioSidekick.FileImporter.Nexo -//{ -// [Delimiter(",")] -// public class NexoRecord -// { -// public string Transaction { get; set; } +namespace GhostfolioSidekick.FileImporter.Nexo +{ + [Delimiter(",")] + public class NexoRecord + { + public string Transaction { get; set; } -// public string Type { get; set; } + public string Type { get; set; } -// [Name("Input Currency")] -// public string InputCurrency { get; set; } + [Name("Input Currency")] + public string InputCurrency { get; set; } -// [Name("Input Amount")] -// public decimal InputAmount { get; set; } + [Name("Input Amount")] + public decimal InputAmount { get; set; } -// [Name("Output Currency")] -// public string OutputCurrency { get; set; } + [Name("Output Currency")] + public string OutputCurrency { get; set; } -// [Name("Output Amount")] -// public decimal OutputAmount { get; set; } + [Name("Output Amount")] + public decimal OutputAmount { get; set; } -// [Name("USD Equivalent")] -// public string USDEquivalent { get; set; } + [Name("USD Equivalent")] + public string USDEquivalent { get; set; } -// [Name("Details")] -// public string Details { get; set; } + [Name("Details")] + public string Details { get; set; } -// [Name("Date / Time")] -// [Format("yyyy-MM-dd HH:mm:ss")] -// public DateTime DateTime { get; set; } + [Name("Date / Time")] + [Format("yyyy-MM-dd HH:mm:ss")] + public DateTime DateTime { get; set; } -// public decimal GetUSDEquivalent() -// { -// return decimal.Parse(USDEquivalent, NumberStyles.Currency, new NumberFormatInfo { CurrencyDecimalSeparator = ".", CurrencySymbol = "$" }); -// } -// } -//} \ No newline at end of file + public decimal GetUSDEquivalent() + { + return decimal.Parse(USDEquivalent, NumberStyles.Currency, new NumberFormatInfo { CurrencyDecimalSeparator = ".", CurrencySymbol = "$" }); + } + } +} \ No newline at end of file diff --git a/GhostfolioSidekick/FileImporter/ScalableCaptial/ScalableCapitalParser.cs b/GhostfolioSidekick/FileImporter/ScalableCaptial/ScalableCapitalParser.cs index c18f0ee8..5c8b7405 100644 --- a/GhostfolioSidekick/FileImporter/ScalableCaptial/ScalableCapitalParser.cs +++ b/GhostfolioSidekick/FileImporter/ScalableCaptial/ScalableCapitalParser.cs @@ -39,10 +39,10 @@ public Task CanParseActivities(IEnumerable filenames) } - public async Task ConvertActivitiesForAccount(string accountName, IEnumerable filenames) + public async Task ConvertActivitiesForAccount(string accountName, IEnumerable filenames) { - var list = new ConcurrentDictionary, Model.Activity>(); - Tuple GetKey(Model.Activity x) + var list = new ConcurrentDictionary, Activity>(); + Tuple GetKey(Activity x) { return Tuple.Create(x.Asset, x.UnitPrice.Currency, x.Date, x.UnitPrice.Amount, x.Quantity); }; @@ -111,7 +111,7 @@ static string DetermineKey(BaaderBankRKKRecord x) return account; } - private async Task ConvertToOrder(BaaderBankRKKRecord record) + private async Task ConvertToOrder(BaaderBankRKKRecord record) { var orderType = GetOrderType(record); if (orderType == null) @@ -124,7 +124,7 @@ static string DetermineKey(BaaderBankRKKRecord x) var quantity = decimal.Parse(record.Quantity.Replace("STK ", string.Empty), GetCultureForParsingNumbers()); var unitPrice = record.UnitPrice.GetValueOrDefault() / quantity; - return new Model.Activity( + return new Activity( orderType.Value, asset, record.Date.ToDateTime(TimeOnly.MinValue), @@ -136,13 +136,13 @@ static string DetermineKey(BaaderBankRKKRecord x) ); } - private async Task ConvertToOrder(BaaderBankWUMRecord record, ConcurrentDictionary rkkRecords) + private async Task ConvertToOrder(BaaderBankWUMRecord record, ConcurrentDictionary rkkRecords) { var asset = await api.FindSymbolByISIN(record.Isin); var fee = FindFeeRecord(rkkRecords, record.Reference); - return new Model.Activity( + return new Activity( GetOrderType(record), asset, record.Date.ToDateTime(record.Time), @@ -164,24 +164,24 @@ static string DetermineKey(BaaderBankRKKRecord x) return null; } - private Model.ActivityType GetOrderType(BaaderBankWUMRecord record) + private ActivityType GetOrderType(BaaderBankWUMRecord record) { switch (record.OrderType) { case "Verkauf": - return Model.ActivityType.Sell; + return ActivityType.Sell; case "Kauf": - return Model.ActivityType.Buy; + return ActivityType.Buy; default: throw new NotSupportedException(); } } - private Model.ActivityType? GetOrderType(BaaderBankRKKRecord record) + private ActivityType? GetOrderType(BaaderBankRKKRecord record) { if (record.OrderType == "Coupons/Dividende") { - return Model.ActivityType.Dividend; + return ActivityType.Dividend; } return null; diff --git a/GhostfolioSidekick/FileImporter/Trading212/Trading212Parser.cs b/GhostfolioSidekick/FileImporter/Trading212/Trading212Parser.cs index fbe9b587..6a6afeb4 100644 --- a/GhostfolioSidekick/FileImporter/Trading212/Trading212Parser.cs +++ b/GhostfolioSidekick/FileImporter/Trading212/Trading212Parser.cs @@ -11,12 +11,12 @@ public Trading212Parser(IGhostfolioAPI api) : base(api) { } - protected override async Task> ConvertOrders(Trading212Record record, Model.Account account, IEnumerable allRecords) + protected override async Task> ConvertOrders(Trading212Record record, Account account, IEnumerable allRecords) { var activityType = GetOrderType(record); if (activityType == null) { - return Array.Empty(); + return Array.Empty(); } var asset = string.IsNullOrWhiteSpace(record.ISIN) ? null : await api.FindSymbolByISIN(record.ISIN); @@ -28,11 +28,11 @@ public Trading212Parser(IGhostfolioAPI api) : base(api) var fee = GetFee(record); - if (activityType == Model.ActivityType.Convert) + if (activityType == ActivityType.Convert) { var parsed = ParserConvertion(record); - var activitySource = new Model.Activity( - Model.ActivityType.CashWithdrawal, + var activitySource = new Activity( + ActivityType.CashWithdrawal, asset, record.Time, 1, @@ -41,8 +41,8 @@ public Trading212Parser(IGhostfolioAPI api) : base(api) $"Transaction Reference: [{record.Id}_SourceCurrencyConversion]", record.Id + "_SourceCurrencyConversion" ); - var activityTarget = new Model.Activity( - Model.ActivityType.CashDeposit, + var activityTarget = new Activity( + ActivityType.CashDeposit, asset, record.Time, 1, @@ -54,17 +54,17 @@ public Trading212Parser(IGhostfolioAPI api) : base(api) return new[] { activitySource, activityTarget }; } - else if (activityType == Model.ActivityType.CashDeposit || - activityType == Model.ActivityType.CashWithdrawal || - activityType == Model.ActivityType.Interest) + else if (activityType == ActivityType.CashDeposit || + activityType == ActivityType.CashWithdrawal || + activityType == ActivityType.Interest) { - var activity = new Model.Activity( + var activity = new Activity( activityType.Value, asset, record.Time, 1, - new Model.Money(record.Currency == string.Empty ? record.CurrencyTotal : record.Currency, record.Total.GetValueOrDefault(0), record.Time), - fee.Fee == null ? null : new Model.Money(fee.Currency, fee.Fee ?? 0, record.Time), + new Money(record.Currency == string.Empty ? record.CurrencyTotal : record.Currency, record.Total.GetValueOrDefault(0), record.Time), + fee.Fee == null ? null : new Money(fee.Currency, fee.Fee ?? 0, record.Time), $"Transaction Reference: [{record.Id}]", record.Id ); @@ -72,13 +72,13 @@ public Trading212Parser(IGhostfolioAPI api) : base(api) } else { - var activity = new Model.Activity( + var activity = new Activity( activityType.Value, asset, record.Time, record.NumberOfShares.Value, - new Model.Money(record.Currency, record.Price.Value, record.Time), - fee.Fee == null ? null : new Model.Money(fee.Currency, fee.Fee ?? 0, record.Time), + new Money(record.Currency, record.Price.Value, record.Time), + fee.Fee == null ? null : new Money(fee.Currency, fee.Fee ?? 0, record.Time), $"Transaction Reference: [{record.Id}]", record.Id ); @@ -124,23 +124,23 @@ protected override CsvConfiguration GetConfig() { if (record.FeeUK > 0) { - record.FeeUK = api.GetConvertedPrice(new Model.Money(record.FeeUKCurrency, record.FeeUK ?? 0, record.Time), CurrencyHelper.ParseCurrency(record.ConversionFeeCurrency), record.Time).Result.Amount; + record.FeeUK = api.GetConvertedPrice(new Money(record.FeeUKCurrency, record.FeeUK ?? 0, record.Time), CurrencyHelper.ParseCurrency(record.ConversionFeeCurrency), record.Time).Result.Amount; } } return (record.ConversionFeeCurrency, record.ConversionFee + record.FeeUK); } - private Model.ActivityType? GetOrderType(Trading212Record record) + private ActivityType? GetOrderType(Trading212Record record) { return record.Action switch { - "Deposit" => Model.ActivityType.CashDeposit, - "Interest on cash" => Model.ActivityType.Interest, - "Currency conversion" => Model.ActivityType.Convert, - "Market buy" => Model.ActivityType.Buy, - "Market sell" => Model.ActivityType.Sell, - string d when d.Contains("Dividend") => Model.ActivityType.Dividend, + "Deposit" => ActivityType.CashDeposit, + "Interest on cash" => ActivityType.Interest, + "Currency conversion" => ActivityType.Convert, + "Market buy" => ActivityType.Buy, + "Market sell" => ActivityType.Sell, + string d when d.Contains("Dividend") => ActivityType.Dividend, _ => throw new NotSupportedException(), }; } diff --git a/GhostfolioSidekick/Ghostfolio/API/GhostfolioAPI.cs b/GhostfolioSidekick/Ghostfolio/API/GhostfolioAPI.cs index 26ea1bf5..abb99d13 100644 --- a/GhostfolioSidekick/Ghostfolio/API/GhostfolioAPI.cs +++ b/GhostfolioSidekick/Ghostfolio/API/GhostfolioAPI.cs @@ -193,7 +193,7 @@ public async Task DeleteMarketData(Model.MarketDataInfo marketData) private async Task GetInfo() { var content = await restCall.DoRestGet($"api/v1/info/", CacheDuration.Short()); - return JsonConvert.DeserializeObject(content); + return JsonConvert.DeserializeObject(content); } private async Task WriteOrder(Contract.Activity activity) diff --git a/GhostfolioSidekick/Ghostfolio/API/IGhostfolioAPI.cs b/GhostfolioSidekick/Ghostfolio/API/IGhostfolioAPI.cs index 9dc052f5..64dae601 100644 --- a/GhostfolioSidekick/Ghostfolio/API/IGhostfolioAPI.cs +++ b/GhostfolioSidekick/Ghostfolio/API/IGhostfolioAPI.cs @@ -4,15 +4,15 @@ namespace GhostfolioSidekick.Ghostfolio.API { public interface IGhostfolioAPI { - Task GetAccountByName(string name); + Task GetAccountByName(string name); - public Task UpdateAccount(Model.Account account); + public Task UpdateAccount(Account account); - Task FindSymbolByISIN(string? identifier, Func, Model.Asset?> selector = null); + Task FindSymbolByISIN(string? identifier, Func, Asset?> selector = null); Task GetConvertedPrice(Money money, Currency targetCurrency, DateTime date); - Task GetMarketPrice(Model.Asset asset, DateTime date); + Task GetMarketPrice(Asset asset, DateTime date); Task> GetMarketDataInfo(); diff --git a/GhostfolioSidekick/Ghostfolio/API/Mapper/ModelToContractMapper.cs b/GhostfolioSidekick/Ghostfolio/API/Mapper/ModelToContractMapper.cs index 5f943f66..4df9b960 100644 --- a/GhostfolioSidekick/Ghostfolio/API/Mapper/ModelToContractMapper.cs +++ b/GhostfolioSidekick/Ghostfolio/API/Mapper/ModelToContractMapper.cs @@ -11,14 +11,14 @@ public ModelToContractMapper(ICurrentPriceCalculator currentPriceCalculator) this.currentPriceCalculator = currentPriceCalculator; } - public Contract.Activity ConvertToGhostfolioActivity(Model.Account account, Model.Activity activity) + public Contract.Activity ConvertToGhostfolioActivity(Account account, Activity activity) { decimal Round(decimal? value) { return Math.Round(value ?? 0, 10); }; - if (activity.ActivityType == Model.ActivityType.Interest) + if (activity.ActivityType == ActivityType.Interest) { return new Contract.Activity { @@ -63,31 +63,31 @@ decimal Round(decimal? value) }; } - private Contract.ActivityType ParseType(Model.ActivityType? type) + private Contract.ActivityType ParseType(ActivityType? type) { switch (type) { case null: return Contract.ActivityType.IGNORE; - case Model.ActivityType.Buy: + case ActivityType.Buy: return Contract.ActivityType.BUY; - case Model.ActivityType.Sell: + case ActivityType.Sell: return Contract.ActivityType.SELL; - case Model.ActivityType.Dividend: + case ActivityType.Dividend: return Contract.ActivityType.DIVIDEND; - case Model.ActivityType.Send: + case ActivityType.Send: return Contract.ActivityType.SELL; // TODO: - case Model.ActivityType.Receive: + case ActivityType.Receive: return Contract.ActivityType.BUY; // TODO: - case Model.ActivityType.Convert: + case ActivityType.Convert: return Contract.ActivityType.IGNORE; // TODO: - case Model.ActivityType.Interest: + case ActivityType.Interest: return Contract.ActivityType.INTEREST; - case Model.ActivityType.Gift: + case ActivityType.Gift: return Contract.ActivityType.BUY; // TODO: - case Model.ActivityType.LearningReward: + case ActivityType.LearningReward: return Contract.ActivityType.IGNORE; // TODO: - case Model.ActivityType.StakingReward: + case ActivityType.StakingReward: return Contract.ActivityType.IGNORE; // TODO: default: throw new NotSupportedException($"ActivityType {type} not supported"); diff --git a/GhostfolioSidekick/Ghostfolio/API/MergeOrder.cs b/GhostfolioSidekick/Ghostfolio/API/MergeOrder.cs index 1516e280..68c7921e 100644 --- a/GhostfolioSidekick/Ghostfolio/API/MergeOrder.cs +++ b/GhostfolioSidekick/Ghostfolio/API/MergeOrder.cs @@ -4,21 +4,21 @@ namespace GhostfolioSidekick.Ghostfolio.API { public sealed class MergeOrder { - public MergeOrder(Operation operation, Contract.Activity order1) + public MergeOrder(Operation operation, Activity order1) { Operation = operation; Order1 = order1; Order2 = null; } - public MergeOrder(Operation operation, Contract.Activity order1, RawActivity? order2) : this(operation, order1) + public MergeOrder(Operation operation, Activity order1, RawActivity? order2) : this(operation, order1) { Order2 = order2; } public Operation Operation { get; } - public Contract.Activity Order1 { get; } + public Activity Order1 { get; } public RawActivity? Order2 { get; } } diff --git a/GhostfolioSidekick/Model/ActivityType.cs b/GhostfolioSidekick/Model/ActivityType.cs index 2b14996f..0fc7eef3 100644 --- a/GhostfolioSidekick/Model/ActivityType.cs +++ b/GhostfolioSidekick/Model/ActivityType.cs @@ -2,7 +2,9 @@ { public enum ActivityType { - Buy, + Undefined = 0, + + Buy = 1, Sell, diff --git a/README.md b/README.md index 44c91346..52202cf8 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ IDENTIFIER,ATOM-USD,Cosmos USD | De Giro | Export of transaction history | X | - | X | X | | Scalable Capital | The CSV files of the Baader bank. Type WUM and RKK | X | X | X | X | | Bunq (bank) | Export CSV (Semicolom delimited) | - | - | - | X | -| ~~Coinbase (Experimental)~~ | Export of transaction history | X | X | - | X | +| Coinbase (Experimental) | Export of transaction history | X | X | - | - (Interest not yet supported due to missing stake rewards) | | ~~Nexo (Experimental)~~ | Export of transaction history | X | - | - | X | #### Generic import format