From dcee651098d1ac41b30962b71397ddad2730832d Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 24 Sep 2021 21:09:48 +0200 Subject: [PATCH] Feature/support unlimited currencies (#387) * Support unlimited currencies * Update changelog --- CHANGELOG.md | 6 + apps/api/src/app/account/account.service.ts | 4 +- .../api/src/app/account/create-account.dto.ts | 4 +- .../api/src/app/account/update-account.dto.ts | 4 +- apps/api/src/app/admin/admin.service.ts | 65 ++--- apps/api/src/app/cache/cache.module.ts | 3 +- .../src/app/experimental/create-order.dto.ts | 6 +- .../experimental/interfaces/data.interface.ts | 4 +- apps/api/src/app/export/export.module.ts | 3 +- apps/api/src/app/info/info.module.ts | 2 + apps/api/src/app/info/info.service.ts | 5 +- apps/api/src/app/order/create-order.dto.ts | 4 +- apps/api/src/app/order/update-order.dto.ts | 6 +- .../portfolio/current-rate.service.spec.ts | 12 +- .../interfaces/get-value-params.interface.ts | 6 +- .../interfaces/get-values-params.interface.ts | 5 +- .../interfaces/portfolio-order.interface.ts | 4 +- .../portfolio-position-detail.interface.ts | 4 +- .../transaction-point-symbol.interface.ts | 4 +- .../portfolio/portfolio-calculator.spec.ts | 227 +++++++++--------- .../src/app/portfolio/portfolio-calculator.ts | 7 +- .../src/app/portfolio/portfolio.service.ts | 16 +- apps/api/src/app/portfolio/rules.service.ts | 3 +- .../interfaces/lookup-item.interface.ts | 4 +- .../interfaces/symbol-item.interface.ts | 4 +- apps/api/src/app/symbol/symbol.service.ts | 4 +- .../user-settings-params.interface.ts | 4 +- .../src/app/user/update-user-settings.dto.ts | 4 +- apps/api/src/app/user/user.service.ts | 12 +- .../interfaces/user-settings.interface.ts | 4 +- apps/api/src/models/order.ts | 4 +- apps/api/src/models/rule.ts | 3 +- .../base-currency-current-investment.ts | 4 +- .../base-currency-initial-investment.ts | 3 +- .../current-investment.ts | 3 +- .../initial-investment.ts | 3 +- .../fees/fee-ratio-initial-investment.ts | 3 +- .../api/src/services/data-gathering.module.ts | 9 +- .../src/services/data-gathering.service.ts | 21 +- .../interfaces/scraper-config.interface.ts | 4 +- .../yahoo-finance/yahoo-finance.service.ts | 20 +- .../src/services/exchange-rate-data.module.ts | 4 +- .../services/exchange-rate-data.service.ts | 95 ++++++-- .../api/src/services/interfaces/interfaces.ts | 5 +- .../interfaces/symbol-profile.interface.ts | 9 +- .../portfolio-performance.component.ts | 3 +- .../portfolio-summary.component.ts | 3 +- .../world-map-chart.component.ts | 3 +- .../pages/account/account-page.component.ts | 3 +- ...eate-or-update-account-dialog.component.ts | 5 +- ...-or-update-transaction-dialog.component.ts | 3 +- libs/common/src/lib/config.ts | 21 +- libs/common/src/lib/helper.ts | 11 +- .../src/lib/interfaces/info-item.interface.ts | 4 +- .../portfolio-position.interface.ts | 4 +- .../src/lib/interfaces/position.interface.ts | 4 +- .../interfaces/timeline-position.interface.ts | 4 +- .../lib/interfaces/user-settings.interface.ts | 4 +- .../portfolio-proportion-chart.component.ts | 3 +- .../migration.sql | 14 ++ prisma/schema.prisma | 15 +- prisma/seed.ts | 25 +- 62 files changed, 375 insertions(+), 384 deletions(-) create mode 100644 prisma/migrations/20210921151004_changed_currency_from_enum_to_string/migration.sql diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ebbca8a4..39383d729 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,12 +15,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Changed the navigation to always show the portfolio page +- Migrated the data type of currencies from `enum` to `string` in the database +- Supported unlimited currencies (instead of `CHF`, `EUR`, `GBP` and `USD`) ### Fixed - Hid the actions from the accounts table in the _Presenter View_ - Hid the actions from the transactions table in the _Presenter View_ +### Todo + +- Apply data migration (`yarn prisma migrate deploy`) + ## 1.55.0 - 20.09.2021 ### Changed diff --git a/apps/api/src/app/account/account.service.ts b/apps/api/src/app/account/account.service.ts index 011470b4b..58d98e5cf 100644 --- a/apps/api/src/app/account/account.service.ts +++ b/apps/api/src/app/account/account.service.ts @@ -1,7 +1,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma.service'; import { Injectable } from '@nestjs/common'; -import { Account, Currency, Order, Platform, Prisma } from '@prisma/client'; +import { Account, Order, Platform, Prisma } from '@prisma/client'; import { CashDetails } from './interfaces/cash-details.interface'; @@ -95,7 +95,7 @@ export class AccountService { public async getCashDetails( aUserId: string, - aCurrency: Currency + aCurrency: string ): Promise { let totalCashBalance = 0; diff --git a/apps/api/src/app/account/create-account.dto.ts b/apps/api/src/app/account/create-account.dto.ts index ef310293b..f53a20e76 100644 --- a/apps/api/src/app/account/create-account.dto.ts +++ b/apps/api/src/app/account/create-account.dto.ts @@ -1,4 +1,4 @@ -import { AccountType, Currency } from '@prisma/client'; +import { AccountType } from '@prisma/client'; import { IsNumber, IsString, ValidateIf } from 'class-validator'; export class CreateAccountDto { @@ -9,7 +9,7 @@ export class CreateAccountDto { balance: number; @IsString() - currency: Currency; + currency: string; @IsString() name: string; diff --git a/apps/api/src/app/account/update-account.dto.ts b/apps/api/src/app/account/update-account.dto.ts index fc32d283f..343f46a7a 100644 --- a/apps/api/src/app/account/update-account.dto.ts +++ b/apps/api/src/app/account/update-account.dto.ts @@ -1,4 +1,4 @@ -import { AccountType, Currency } from '@prisma/client'; +import { AccountType } from '@prisma/client'; import { IsNumber, IsString, ValidateIf } from 'class-validator'; export class UpdateAccountDto { @@ -9,7 +9,7 @@ export class UpdateAccountDto { balance: number; @IsString() - currency: Currency; + currency: string; @IsString() id: string; diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 2d8d09fac..be78d668a 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -3,9 +3,9 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration.ser import { DataGatheringService } from '@ghostfolio/api/services/data-gathering.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma.service'; +import { baseCurrency } from '@ghostfolio/common/config'; import { AdminData } from '@ghostfolio/common/interfaces'; import { Injectable } from '@nestjs/common'; -import { Currency } from '@prisma/client'; import { differenceInDays } from 'date-fns'; @Injectable() @@ -20,53 +20,22 @@ export class AdminService { public async get(): Promise { return { - exchangeRates: [ - { - label1: Currency.EUR, - label2: Currency.CHF, - value: await this.exchangeRateDataService.toCurrency( - 1, - Currency.EUR, - Currency.CHF - ) - }, - { - label1: Currency.GBP, - label2: Currency.CHF, - value: await this.exchangeRateDataService.toCurrency( - 1, - Currency.GBP, - Currency.CHF - ) - }, - { - label1: Currency.USD, - label2: Currency.CHF, - value: await this.exchangeRateDataService.toCurrency( - 1, - Currency.USD, - Currency.CHF - ) - }, - { - label1: Currency.USD, - label2: Currency.EUR, - value: await this.exchangeRateDataService.toCurrency( - 1, - Currency.USD, - Currency.EUR - ) - }, - { - label1: Currency.USD, - label2: Currency.GBP, - value: await this.exchangeRateDataService.toCurrency( - 1, - Currency.USD, - Currency.GBP - ) - } - ], + exchangeRates: this.exchangeRateDataService + .getCurrencies() + .filter((currency) => { + return currency !== baseCurrency; + }) + .map((currency) => { + return { + label1: baseCurrency, + label2: currency, + value: this.exchangeRateDataService.toCurrency( + 1, + baseCurrency, + currency + ) + }; + }), lastDataGathering: await this.getLastDataGathering(), transactionCount: await this.prismaService.order.count(), userCount: await this.prismaService.user.count(), diff --git a/apps/api/src/app/cache/cache.module.ts b/apps/api/src/app/cache/cache.module.ts index 15e63e818..bbbd8f108 100644 --- a/apps/api/src/app/cache/cache.module.ts +++ b/apps/api/src/app/cache/cache.module.ts @@ -7,13 +7,14 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider/data import { GhostfolioScraperApiService } from '@ghostfolio/api/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service'; import { RakutenRapidApiService } from '@ghostfolio/api/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service'; import { YahooFinanceService } from '@ghostfolio/api/services/data-provider/yahoo-finance/yahoo-finance.service'; +import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data.module'; import { PrismaService } from '@ghostfolio/api/services/prisma.service'; import { Module } from '@nestjs/common'; import { CacheController } from './cache.controller'; @Module({ - imports: [RedisCacheModule], + imports: [ExchangeRateDataModule, RedisCacheModule], controllers: [CacheController], providers: [ AlphaVantageService, diff --git a/apps/api/src/app/experimental/create-order.dto.ts b/apps/api/src/app/experimental/create-order.dto.ts index c30f020ba..f2503794a 100644 --- a/apps/api/src/app/experimental/create-order.dto.ts +++ b/apps/api/src/app/experimental/create-order.dto.ts @@ -1,9 +1,9 @@ -import { Currency, Type } from '@prisma/client'; -import { IsISO8601, IsNumber, IsString, ValidateIf } from 'class-validator'; +import { Type } from '@prisma/client'; +import { IsISO8601, IsNumber, IsString } from 'class-validator'; export class CreateOrderDto { @IsString() - currency: Currency; + currency: string; @IsISO8601() date: string; diff --git a/apps/api/src/app/experimental/interfaces/data.interface.ts b/apps/api/src/app/experimental/interfaces/data.interface.ts index 3f581e943..11e78c0c3 100644 --- a/apps/api/src/app/experimental/interfaces/data.interface.ts +++ b/apps/api/src/app/experimental/interfaces/data.interface.ts @@ -1,6 +1,4 @@ -import { Currency } from '@prisma/client'; - export interface Data { - currency: Currency; + currency: string; value: number; } diff --git a/apps/api/src/app/export/export.module.ts b/apps/api/src/app/export/export.module.ts index c30743d31..dd273c717 100644 --- a/apps/api/src/app/export/export.module.ts +++ b/apps/api/src/app/export/export.module.ts @@ -1,4 +1,3 @@ -import { CacheService } from '@ghostfolio/api/app/cache/cache.service'; import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module'; import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering.module'; @@ -18,6 +17,6 @@ import { ExportService } from './export.service'; RedisCacheModule ], controllers: [ExportController], - providers: [CacheService, ExportService] + providers: [ExportService] }) export class ExportModule {} diff --git a/apps/api/src/app/info/info.module.ts b/apps/api/src/app/info/info.module.ts index 71fae0fe2..c1b8ee21e 100644 --- a/apps/api/src/app/info/info.module.ts +++ b/apps/api/src/app/info/info.module.ts @@ -5,6 +5,7 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider/data import { GhostfolioScraperApiService } from '@ghostfolio/api/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service'; import { RakutenRapidApiService } from '@ghostfolio/api/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service'; import { YahooFinanceService } from '@ghostfolio/api/services/data-provider/yahoo-finance/yahoo-finance.service'; +import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data.module'; import { PrismaService } from '@ghostfolio/api/services/prisma.service'; import { Module } from '@nestjs/common'; import { JwtModule } from '@nestjs/jwt'; @@ -14,6 +15,7 @@ import { InfoService } from './info.service'; @Module({ imports: [ + ExchangeRateDataModule, JwtModule.register({ secret: process.env.JWT_SECRET_KEY, signOptions: { expiresIn: '30 days' } diff --git a/apps/api/src/app/info/info.service.ts b/apps/api/src/app/info/info.service.ts index 1edbe072a..9486f1527 100644 --- a/apps/api/src/app/info/info.service.ts +++ b/apps/api/src/app/info/info.service.ts @@ -1,12 +1,12 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration.service'; import { DataGatheringService } from '@ghostfolio/api/services/data-gathering.service'; +import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma.service'; import { InfoItem } from '@ghostfolio/common/interfaces'; import { Subscription } from '@ghostfolio/common/interfaces/subscription.interface'; import { permissions } from '@ghostfolio/common/permissions'; import { Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; -import { Currency } from '@prisma/client'; import * as bent from 'bent'; import { subDays } from 'date-fns'; @@ -16,6 +16,7 @@ export class InfoService { public constructor( private readonly configurationService: ConfigurationService, + private readonly exchangeRateDataService: ExchangeRateDataService, private readonly dataGatheringService: DataGatheringService, private readonly jwtService: JwtService, private readonly prismaService: PrismaService @@ -56,7 +57,7 @@ export class InfoService { ...info, globalPermissions, platforms, - currencies: Object.values(Currency), + currencies: this.exchangeRateDataService.getCurrencies(), demoAuthToken: this.getDemoAuthToken(), lastDataGathering: await this.getLastDataGathering(), statistics: await this.getStatistics(), diff --git a/apps/api/src/app/order/create-order.dto.ts b/apps/api/src/app/order/create-order.dto.ts index ef307f941..942915843 100644 --- a/apps/api/src/app/order/create-order.dto.ts +++ b/apps/api/src/app/order/create-order.dto.ts @@ -1,4 +1,4 @@ -import { Currency, DataSource, Type } from '@prisma/client'; +import { DataSource, Type } from '@prisma/client'; import { IsISO8601, IsNumber, IsString } from 'class-validator'; export class CreateOrderDto { @@ -6,7 +6,7 @@ export class CreateOrderDto { accountId: string; @IsString() - currency: Currency; + currency: string; @IsString() dataSource: DataSource; diff --git a/apps/api/src/app/order/update-order.dto.ts b/apps/api/src/app/order/update-order.dto.ts index 115ca3c1d..58a046c5b 100644 --- a/apps/api/src/app/order/update-order.dto.ts +++ b/apps/api/src/app/order/update-order.dto.ts @@ -1,12 +1,12 @@ -import { Currency, DataSource, Type } from '@prisma/client'; -import { IsISO8601, IsNumber, IsString, ValidateIf } from 'class-validator'; +import { DataSource, Type } from '@prisma/client'; +import { IsISO8601, IsNumber, IsString } from 'class-validator'; export class UpdateOrderDto { @IsString() accountId: string; @IsString() - currency: Currency; + currency: string; @IsString() dataSource: DataSource; diff --git a/apps/api/src/app/portfolio/current-rate.service.spec.ts b/apps/api/src/app/portfolio/current-rate.service.spec.ts index 7054633a0..a166a11af 100644 --- a/apps/api/src/app/portfolio/current-rate.service.spec.ts +++ b/apps/api/src/app/portfolio/current-rate.service.spec.ts @@ -1,6 +1,6 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; -import { Currency, DataSource, MarketData } from '@prisma/client'; +import { DataSource, MarketData } from '@prisma/client'; import { CurrentRateService } from './current-rate.service'; import { MarketDataService } from './market-data.service'; @@ -80,7 +80,7 @@ describe('CurrentRateService', () => { null, null ); - exchangeRateDataService = new ExchangeRateDataService(null); + exchangeRateDataService = new ExchangeRateDataService(null, null); marketDataService = new MarketDataService(null); await exchangeRateDataService.initialize(); @@ -95,10 +95,10 @@ describe('CurrentRateService', () => { it('getValue', async () => { expect( await currentRateService.getValue({ - currency: Currency.USD, + currency: 'USD', date: new Date(Date.UTC(2020, 0, 1, 0, 0, 0)), symbol: 'AMZN', - userCurrency: Currency.CHF + userCurrency: 'CHF' }) ).toMatchObject({ marketPrice: 1847.839966 @@ -108,13 +108,13 @@ describe('CurrentRateService', () => { it('getValues', async () => { expect( await currentRateService.getValues({ - currencies: { AMZN: Currency.USD }, + currencies: { AMZN: 'USD' }, dataGatheringItems: [{ dataSource: DataSource.YAHOO, symbol: 'AMZN' }], dateQuery: { lt: new Date(Date.UTC(2020, 0, 2, 0, 0, 0)), gte: new Date(Date.UTC(2020, 0, 1, 0, 0, 0)) }, - userCurrency: Currency.CHF + userCurrency: 'CHF' }) ).toMatchObject([ { diff --git a/apps/api/src/app/portfolio/interfaces/get-value-params.interface.ts b/apps/api/src/app/portfolio/interfaces/get-value-params.interface.ts index bff927206..a9b934271 100644 --- a/apps/api/src/app/portfolio/interfaces/get-value-params.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/get-value-params.interface.ts @@ -1,8 +1,6 @@ -import { Currency } from '@prisma/client'; - export interface GetValueParams { - currency: Currency; + currency: string; date: Date; symbol: string; - userCurrency: Currency; + userCurrency: string; } diff --git a/apps/api/src/app/portfolio/interfaces/get-values-params.interface.ts b/apps/api/src/app/portfolio/interfaces/get-values-params.interface.ts index c736eebf2..5b3ab7053 100644 --- a/apps/api/src/app/portfolio/interfaces/get-values-params.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/get-values-params.interface.ts @@ -1,11 +1,10 @@ import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; -import { Currency } from '@prisma/client'; import { DateQuery } from './date-query.interface'; export interface GetValuesParams { - currencies: { [symbol: string]: Currency }; + currencies: { [symbol: string]: string }; dataGatheringItems: IDataGatheringItem[]; dateQuery: DateQuery; - userCurrency: Currency; + userCurrency: string; } diff --git a/apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts b/apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts index 71e6cb99e..5fd3baf8d 100644 --- a/apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts @@ -1,9 +1,9 @@ import { OrderType } from '@ghostfolio/api/models/order-type'; -import { Currency, DataSource } from '@prisma/client'; +import { DataSource } from '@prisma/client'; import Big from 'big.js'; export interface PortfolioOrder { - currency: Currency; + currency: string; date: string; dataSource: DataSource; fee: Big; diff --git a/apps/api/src/app/portfolio/interfaces/portfolio-position-detail.interface.ts b/apps/api/src/app/portfolio/interfaces/portfolio-position-detail.interface.ts index 3e3b7048c..45d27dbef 100644 --- a/apps/api/src/app/portfolio/interfaces/portfolio-position-detail.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/portfolio-position-detail.interface.ts @@ -1,8 +1,6 @@ -import { Currency } from '@prisma/client'; - export interface PortfolioPositionDetail { averagePrice: number; - currency: Currency; + currency: string; firstBuyDate: string; grossPerformance: number; grossPerformancePercent: number; diff --git a/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts b/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts index 51465f8fd..cc199119e 100644 --- a/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts @@ -1,8 +1,8 @@ -import { Currency, DataSource } from '@prisma/client'; +import { DataSource } from '@prisma/client'; import Big from 'big.js'; export interface TransactionPointSymbol { - currency: Currency; + currency: string; dataSource: DataSource; fee: Big; firstBuyDate: string; diff --git a/apps/api/src/app/portfolio/portfolio-calculator.spec.ts b/apps/api/src/app/portfolio/portfolio-calculator.spec.ts index 9dda2e8f0..5dd8bb62a 100644 --- a/apps/api/src/app/portfolio/portfolio-calculator.spec.ts +++ b/apps/api/src/app/portfolio/portfolio-calculator.spec.ts @@ -1,7 +1,6 @@ -import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; import { OrderType } from '@ghostfolio/api/models/order-type'; import { parseDate, resetHours } from '@ghostfolio/common/helper'; -import { Currency, DataSource } from '@prisma/client'; +import { DataSource } from '@prisma/client'; import Big from 'big.js'; import { addDays, @@ -134,7 +133,7 @@ describe('PortfolioCalculator', () => { it('with orders of only one symbol', () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.computeTransactionPoints(ordersVTI); const portfolioItemsAtTransactionPoints = @@ -148,7 +147,7 @@ describe('PortfolioCalculator', () => { it('with orders of only one symbol and a fee', () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); const orders: PortfolioOrder[] = [ { @@ -158,7 +157,7 @@ describe('PortfolioCalculator', () => { symbol: 'VTI', type: OrderType.Buy, unitPrice: new Big('144.38'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big('5') }, @@ -169,7 +168,7 @@ describe('PortfolioCalculator', () => { symbol: 'VTI', type: OrderType.Buy, unitPrice: new Big('147.99'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big('10') }, @@ -180,7 +179,7 @@ describe('PortfolioCalculator', () => { symbol: 'VTI', type: OrderType.Sell, unitPrice: new Big('151.41'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big('5') } @@ -198,7 +197,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('10'), symbol: 'VTI', investment: new Big('1443.8'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-02-01', transactionCount: 1, fee: new Big('5') @@ -213,7 +212,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('20'), symbol: 'VTI', investment: new Big('2923.7'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-02-01', transactionCount: 2, fee: new Big('15') @@ -228,7 +227,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('5'), symbol: 'VTI', investment: new Big('652.55'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-02-01', transactionCount: 3, fee: new Big('20') @@ -241,7 +240,7 @@ describe('PortfolioCalculator', () => { it('with orders of two different symbols and a fee', () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); const orders: PortfolioOrder[] = [ { @@ -251,7 +250,7 @@ describe('PortfolioCalculator', () => { symbol: 'VTI', type: OrderType.Buy, unitPrice: new Big('144.38'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big('5') }, @@ -262,7 +261,7 @@ describe('PortfolioCalculator', () => { symbol: 'VTX', type: OrderType.Buy, unitPrice: new Big('147.99'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big('10') }, @@ -273,7 +272,7 @@ describe('PortfolioCalculator', () => { symbol: 'VTI', type: OrderType.Sell, unitPrice: new Big('151.41'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big('5') } @@ -291,7 +290,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('10'), symbol: 'VTI', investment: new Big('1443.8'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-02-01', transactionCount: 1, fee: new Big('5') @@ -306,7 +305,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('10'), symbol: 'VTI', investment: new Big('1443.8'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-02-01', transactionCount: 1, fee: new Big('5') @@ -316,7 +315,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('10'), symbol: 'VTX', investment: new Big('1479.9'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-08-03', transactionCount: 1, fee: new Big('10') @@ -331,7 +330,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('5'), symbol: 'VTI', investment: new Big('686.75'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-02-01', transactionCount: 2, fee: new Big('10') @@ -341,7 +340,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('10'), symbol: 'VTX', investment: new Big('1479.9'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-08-03', transactionCount: 1, fee: new Big('10') @@ -355,7 +354,7 @@ describe('PortfolioCalculator', () => { const orders: PortfolioOrder[] = [ ...ordersVTI, { - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, date: '2021-02-01', name: 'Vanguard Total Stock Market Index Fund ETF Shares', @@ -368,7 +367,7 @@ describe('PortfolioCalculator', () => { ]; const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.computeTransactionPoints(orders); const portfolioItemsAtTransactionPoints = @@ -379,7 +378,7 @@ describe('PortfolioCalculator', () => { date: '2019-02-01', items: [ { - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', investment: new Big('1443.8'), @@ -394,7 +393,7 @@ describe('PortfolioCalculator', () => { date: '2019-08-03', items: [ { - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', investment: new Big('2923.7'), @@ -409,7 +408,7 @@ describe('PortfolioCalculator', () => { date: '2020-02-02', items: [ { - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', investment: new Big('652.55'), @@ -424,7 +423,7 @@ describe('PortfolioCalculator', () => { date: '2021-02-01', items: [ { - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', investment: new Big('6627.05'), @@ -439,7 +438,7 @@ describe('PortfolioCalculator', () => { date: '2021-08-01', items: [ { - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', investment: new Big('8403.95'), @@ -457,7 +456,7 @@ describe('PortfolioCalculator', () => { const orders: PortfolioOrder[] = [ ...ordersVTI, { - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, date: '2019-09-01', name: 'Amazon.com, Inc.', @@ -470,7 +469,7 @@ describe('PortfolioCalculator', () => { ]; const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.computeTransactionPoints(orders); const portfolioItemsAtTransactionPoints = @@ -485,7 +484,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('10'), symbol: 'VTI', investment: new Big('1443.8'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-02-01', fee: new Big(0), transactionCount: 1 @@ -500,7 +499,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('20'), symbol: 'VTI', investment: new Big('2923.7'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-02-01', fee: new Big(0), transactionCount: 2 @@ -515,7 +514,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('5'), symbol: 'AMZN', investment: new Big('10109.95'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-09-01', fee: new Big(0), transactionCount: 1 @@ -525,7 +524,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('20'), symbol: 'VTI', investment: new Big('2923.7'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-02-01', fee: new Big(0), transactionCount: 2 @@ -540,7 +539,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('5'), symbol: 'AMZN', investment: new Big('10109.95'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-09-01', fee: new Big(0), transactionCount: 1 @@ -550,7 +549,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('5'), symbol: 'VTI', investment: new Big('652.55'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-02-01', fee: new Big(0), transactionCount: 3 @@ -565,7 +564,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('5'), symbol: 'AMZN', investment: new Big('10109.95'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-09-01', fee: new Big(0), transactionCount: 1 @@ -575,7 +574,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('15'), symbol: 'VTI', investment: new Big('2684.05'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-02-01', fee: new Big(0), transactionCount: 4 @@ -590,7 +589,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('5'), symbol: 'AMZN', investment: new Big('10109.95'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-09-01', fee: new Big(0), transactionCount: 1 @@ -600,7 +599,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('25'), symbol: 'VTI', investment: new Big('4460.95'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2019-02-01', fee: new Big(0), transactionCount: 5 @@ -620,7 +619,7 @@ describe('PortfolioCalculator', () => { symbol: 'AMZN', type: OrderType.Buy, unitPrice: new Big('2021.99'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big(0) }, @@ -631,14 +630,14 @@ describe('PortfolioCalculator', () => { symbol: 'AMZN', type: OrderType.Sell, unitPrice: new Big('2412.23'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big(0) } ]; const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.computeTransactionPoints(orders); const portfolioItemsAtTransactionPoints = @@ -652,7 +651,7 @@ describe('PortfolioCalculator', () => { it('with mixed symbols', () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.computeTransactionPoints(ordersMixedSymbols); const portfolioItemsAtTransactionPoints = @@ -667,7 +666,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('50'), symbol: 'TSLA', investment: new Big('2148.5'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2017-01-03', fee: new Big(0), transactionCount: 1 @@ -682,7 +681,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('0.5614682'), symbol: 'BTCUSD', investment: new Big('1999.9999999999998659756'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2017-07-01', fee: new Big(0), transactionCount: 1 @@ -692,7 +691,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('50'), symbol: 'TSLA', investment: new Big('2148.5'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2017-01-03', fee: new Big(0), transactionCount: 1 @@ -707,7 +706,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('5'), symbol: 'AMZN', investment: new Big('10109.95'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2018-09-01', fee: new Big(0), transactionCount: 1 @@ -717,7 +716,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('0.5614682'), symbol: 'BTCUSD', investment: new Big('1999.9999999999998659756'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2017-07-01', fee: new Big(0), transactionCount: 1 @@ -727,7 +726,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('50'), symbol: 'TSLA', investment: new Big('2148.5'), - currency: Currency.USD, + currency: 'USD', firstBuyDate: '2017-01-03', fee: new Big(0), transactionCount: 1 @@ -742,7 +741,7 @@ describe('PortfolioCalculator', () => { it('with single TSLA and early start', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.setTransactionPoints(orderTslaTransactionPoint); @@ -782,7 +781,7 @@ describe('PortfolioCalculator', () => { it('with single TSLA and buy day start', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.setTransactionPoints(orderTslaTransactionPoint); @@ -822,7 +821,7 @@ describe('PortfolioCalculator', () => { it('with single TSLA and late start', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.setTransactionPoints(orderTslaTransactionPoint); @@ -862,7 +861,7 @@ describe('PortfolioCalculator', () => { it('with VTI only', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints); @@ -905,7 +904,7 @@ describe('PortfolioCalculator', () => { it('with buy and sell', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.setTransactionPoints(transactionPointsBuyAndSell); @@ -959,7 +958,7 @@ describe('PortfolioCalculator', () => { it('with buy, sell, buy', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.setTransactionPoints([ { @@ -969,7 +968,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('5'), symbol: 'VTI', investment: new Big('805.9'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-09-01', fee: new Big(0), @@ -984,7 +983,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('0'), symbol: 'VTI', investment: new Big('0'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-09-01', fee: new Big(0), @@ -999,7 +998,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('5'), symbol: 'VTI', investment: new Big('1013.9'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-09-01', fee: new Big(0), @@ -1047,7 +1046,7 @@ describe('PortfolioCalculator', () => { it('with performance since Jan 1st, 2020', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); const transactionPoints: TransactionPoint[] = [ { @@ -1057,7 +1056,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('10'), symbol: 'VTI', investment: new Big('1443.8'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -1072,7 +1071,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('20'), symbol: 'VTI', investment: new Big('2923.7'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -1130,7 +1129,7 @@ describe('PortfolioCalculator', () => { it('with net performance since Jan 1st, 2020 - include fees', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); const transactionPoints: TransactionPoint[] = [ { @@ -1140,7 +1139,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('10'), symbol: 'VTI', investment: new Big('1443.8'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(50), @@ -1155,7 +1154,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('20'), symbol: 'VTI', investment: new Big('2923.7'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(100), @@ -1223,7 +1222,7 @@ describe('PortfolioCalculator', () => { it('with net performance since Feb 1st, 2019 - include fees', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); const transactionPoints: TransactionPoint[] = [ { @@ -1233,7 +1232,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('10'), symbol: 'VTI', investment: new Big('1443.8'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(50), @@ -1248,7 +1247,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('20'), symbol: 'VTI', investment: new Big('2923.7'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(100), @@ -1311,7 +1310,7 @@ describe('PortfolioCalculator', () => { it('with TWR example from Investopedia: Scenario 1', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.setTransactionPoints([ { @@ -1321,7 +1320,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('1000000'), // 1 million symbol: 'MFA', // Mutual Fund A investment: new Big('1000000'), // 1 million - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2010-12-31', fee: new Big(0), @@ -1336,7 +1335,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('1086022.689344541'), // 1,000,000 + 100,000 / 1.162484 symbol: 'MFA', // Mutual Fund A investment: new Big('1100000'), // 1,000,000 + 100,000 - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2010-12-31', fee: new Big(0), @@ -1388,7 +1387,7 @@ describe('PortfolioCalculator', () => { it('with example from chsoft.ch: Performance of a Combination of Investments', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.CHF + 'CHF' ); portfolioCalculator.setTransactionPoints([ { @@ -1398,7 +1397,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('200'), symbol: 'SPA', // Sub Portfolio A investment: new Big('200'), - currency: Currency.CHF, + currency: 'CHF', dataSource: DataSource.YAHOO, firstBuyDate: '2012-12-31', fee: new Big(0), @@ -1408,7 +1407,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('300'), symbol: 'SPB', // Sub Portfolio B investment: new Big('300'), - currency: Currency.CHF, + currency: 'CHF', dataSource: DataSource.YAHOO, firstBuyDate: '2012-12-31', fee: new Big(0), @@ -1423,7 +1422,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('200'), symbol: 'SPA', // Sub Portfolio A investment: new Big('200'), - currency: Currency.CHF, + currency: 'CHF', dataSource: DataSource.YAHOO, firstBuyDate: '2012-12-31', fee: new Big(0), @@ -1433,7 +1432,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('300'), symbol: 'SPB', // Sub Portfolio B investment: new Big('300'), - currency: Currency.CHF, + currency: 'CHF', dataSource: DataSource.YAHOO, firstBuyDate: '2012-12-31', fee: new Big(0), @@ -1494,7 +1493,7 @@ describe('PortfolioCalculator', () => { it('with yearly', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints); const timelineSpecification: TimelineSpecification[] = [ @@ -1537,7 +1536,7 @@ describe('PortfolioCalculator', () => { it('with yearly and fees', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); const transactionPoints: TransactionPoint[] = [ { @@ -1547,7 +1546,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('10'), symbol: 'VTI', investment: new Big('1443.8'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(50), @@ -1562,7 +1561,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('20'), symbol: 'VTI', investment: new Big('2923.7'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(100), @@ -1577,7 +1576,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('5'), symbol: 'VTI', investment: new Big('652.55'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(150), @@ -1592,7 +1591,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('15'), symbol: 'VTI', investment: new Big('2684.05'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(200), @@ -1607,7 +1606,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('25'), symbol: 'VTI', investment: new Big('4460.95'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(250), @@ -1657,7 +1656,7 @@ describe('PortfolioCalculator', () => { it('with monthly', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints); const timelineSpecification: TimelineSpecification[] = [ @@ -1889,7 +1888,7 @@ describe('PortfolioCalculator', () => { it('with yearly and monthly mixed', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints); const timelineSpecification: TimelineSpecification[] = [ @@ -1971,7 +1970,7 @@ describe('PortfolioCalculator', () => { it('with all mixed', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints); const timelineSpecification: TimelineSpecification[] = [ @@ -2262,7 +2261,7 @@ describe('PortfolioCalculator', () => { it('with mixed portfolio', async () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); portfolioCalculator.setTransactionPoints([ { @@ -2272,7 +2271,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('5'), symbol: 'AMZN', investment: new Big('10109.95'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -2282,7 +2281,7 @@ describe('PortfolioCalculator', () => { quantity: new Big('10'), symbol: 'VTI', investment: new Big('1443.8'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -2325,7 +2324,7 @@ describe('PortfolioCalculator', () => { describe('annualized performance percentage', () => { const portfolioCalculator = new PortfolioCalculator( currentRateService, - Currency.USD + 'USD' ); it('Get annualized performance', async () => { @@ -2391,7 +2390,7 @@ const ordersMixedSymbols: PortfolioOrder[] = [ symbol: 'TSLA', type: OrderType.Buy, unitPrice: new Big('42.97'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big(0) }, @@ -2402,7 +2401,7 @@ const ordersMixedSymbols: PortfolioOrder[] = [ symbol: 'BTCUSD', type: OrderType.Buy, unitPrice: new Big('3562.089535970158'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big(0) }, @@ -2413,7 +2412,7 @@ const ordersMixedSymbols: PortfolioOrder[] = [ symbol: 'AMZN', type: OrderType.Buy, unitPrice: new Big('2021.99'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big(0) } @@ -2427,7 +2426,7 @@ const ordersVTI: PortfolioOrder[] = [ symbol: 'VTI', type: OrderType.Buy, unitPrice: new Big('144.38'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big(0) }, @@ -2438,7 +2437,7 @@ const ordersVTI: PortfolioOrder[] = [ symbol: 'VTI', type: OrderType.Buy, unitPrice: new Big('147.99'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big(0) }, @@ -2449,7 +2448,7 @@ const ordersVTI: PortfolioOrder[] = [ symbol: 'VTI', type: OrderType.Sell, unitPrice: new Big('151.41'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big(0) }, @@ -2460,7 +2459,7 @@ const ordersVTI: PortfolioOrder[] = [ symbol: 'VTI', type: OrderType.Buy, unitPrice: new Big('177.69'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big(0) }, @@ -2471,7 +2470,7 @@ const ordersVTI: PortfolioOrder[] = [ symbol: 'VTI', type: OrderType.Buy, unitPrice: new Big('203.15'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, fee: new Big(0) } @@ -2485,7 +2484,7 @@ const orderTslaTransactionPoint: TransactionPoint[] = [ quantity: new Big('1'), symbol: 'TSLA', investment: new Big('719.46'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2021-01-01', fee: new Big(0), @@ -2503,7 +2502,7 @@ const ordersVTITransactionPoints: TransactionPoint[] = [ quantity: new Big('10'), symbol: 'VTI', investment: new Big('1443.8'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -2518,7 +2517,7 @@ const ordersVTITransactionPoints: TransactionPoint[] = [ quantity: new Big('20'), symbol: 'VTI', investment: new Big('2923.7'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -2533,7 +2532,7 @@ const ordersVTITransactionPoints: TransactionPoint[] = [ quantity: new Big('5'), symbol: 'VTI', investment: new Big('652.55'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -2548,7 +2547,7 @@ const ordersVTITransactionPoints: TransactionPoint[] = [ quantity: new Big('15'), symbol: 'VTI', investment: new Big('2684.05'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -2563,7 +2562,7 @@ const ordersVTITransactionPoints: TransactionPoint[] = [ quantity: new Big('25'), symbol: 'VTI', investment: new Big('4460.95'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -2581,7 +2580,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [ quantity: new Big('10'), symbol: 'VTI', investment: new Big('1443.8'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -2596,7 +2595,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [ quantity: new Big('20'), symbol: 'VTI', investment: new Big('2923.7'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -2611,7 +2610,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [ quantity: new Big('5'), symbol: 'AMZN', investment: new Big('10109.95'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-09-01', fee: new Big(0), @@ -2621,7 +2620,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [ quantity: new Big('20'), symbol: 'VTI', investment: new Big('2923.7'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -2636,7 +2635,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [ quantity: new Big('5'), symbol: 'AMZN', investment: new Big('10109.95'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-09-01', fee: new Big(0), @@ -2646,7 +2645,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [ quantity: new Big('5'), symbol: 'VTI', investment: new Big('652.55'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -2661,7 +2660,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [ quantity: new Big('0'), symbol: 'AMZN', investment: new Big('0'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-09-01', fee: new Big(0), @@ -2671,7 +2670,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [ quantity: new Big('5'), symbol: 'VTI', investment: new Big('652.55'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -2686,7 +2685,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [ quantity: new Big('0'), symbol: 'AMZN', investment: new Big('0'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-09-01', fee: new Big(0), @@ -2696,7 +2695,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [ quantity: new Big('15'), symbol: 'VTI', investment: new Big('2684.05'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), @@ -2711,7 +2710,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [ quantity: new Big('0'), symbol: 'AMZN', investment: new Big('0'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-09-01', fee: new Big(0), @@ -2721,7 +2720,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [ quantity: new Big('25'), symbol: 'VTI', investment: new Big('4460.95'), - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, firstBuyDate: '2019-02-01', fee: new Big(0), diff --git a/apps/api/src/app/portfolio/portfolio-calculator.ts b/apps/api/src/app/portfolio/portfolio-calculator.ts index a1be2a0b3..9676edc20 100644 --- a/apps/api/src/app/portfolio/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/portfolio-calculator.ts @@ -2,7 +2,6 @@ import { OrderType } from '@ghostfolio/api/models/order-type'; import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper'; import { TimelinePosition } from '@ghostfolio/common/interfaces'; -import { Currency, DataSource } from '@prisma/client'; import Big from 'big.js'; import { addDays, @@ -35,7 +34,7 @@ export class PortfolioCalculator { public constructor( private currentRateService: CurrentRateService, - private currency: Currency + private currency: string ) {} public computeTransactionPoints(orders: PortfolioOrder[]) { @@ -157,7 +156,7 @@ export class PortfolioCalculator { let firstIndex = this.transactionPoints.length; const dates = []; const dataGatheringItems: IDataGatheringItem[] = []; - const currencies: { [symbol: string]: Currency } = {}; + const currencies: { [symbol: string]: string } = {}; dates.push(resetHours(start)); for (const item of this.transactionPoints[firstIndex - 1].items) { @@ -521,7 +520,7 @@ export class PortfolioCalculator { [date: string]: { [symbol: string]: Big }; } = {}; if (j >= 0) { - const currencies: { [name: string]: Currency } = {}; + const currencies: { [name: string]: string } = {}; const dataGatheringItems: IDataGatheringItem[] = []; for (const item of this.transactionPoints[j].items) { diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 88a8ffeeb..78e9f27df 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -39,15 +39,9 @@ import type { } from '@ghostfolio/common/types'; import { Inject, Injectable } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; -import { - AssetClass, - Currency, - DataSource, - Type as TypeOfOrder -} from '@prisma/client'; +import { AssetClass, DataSource, Type as TypeOfOrder } from '@prisma/client'; import Big from 'big.js'; import { - differenceInDays, endOfToday, format, isAfter, @@ -59,7 +53,7 @@ import { subDays, subYears } from 'date-fns'; -import { isEmpty, isNumber } from 'lodash'; +import { isEmpty } from 'lodash'; import { HistoricalDataItem, @@ -775,7 +769,7 @@ export class PortfolioService { assetClass: AssetClass.CASH, assetSubClass: AssetClass.CASH, countries: [], - currency: Currency.CHF, + currency: 'CHF', grossPerformance: 0, grossPerformancePercent: 0, investment: cashValue.toNumber(), @@ -865,7 +859,7 @@ export class PortfolioService { private async getAccounts( orders: OrderWithAccount[], portfolioItemsNow: { [p: string]: TimelinePosition }, - userCurrency: Currency, + userCurrency: string, userId: string ) { const accounts: PortfolioDetails['accounts'] = {}; @@ -938,7 +932,7 @@ export class PortfolioService { private getTotalByType( orders: OrderWithAccount[], - currency: Currency, + currency: string, type: TypeOfOrder ) { return orders diff --git a/apps/api/src/app/portfolio/rules.service.ts b/apps/api/src/app/portfolio/rules.service.ts index 63f70771c..e3767c50f 100644 --- a/apps/api/src/app/portfolio/rules.service.ts +++ b/apps/api/src/app/portfolio/rules.service.ts @@ -1,7 +1,6 @@ import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { Rule } from '@ghostfolio/api/models/rule'; import { Injectable } from '@nestjs/common'; -import { Currency } from '@prisma/client'; @Injectable() export class RulesService { @@ -9,7 +8,7 @@ export class RulesService { public async evaluate( aRules: Rule[], - aUserSettings: { baseCurrency: Currency } + aUserSettings: { baseCurrency: string } ) { return aRules .filter((rule) => { diff --git a/apps/api/src/app/symbol/interfaces/lookup-item.interface.ts b/apps/api/src/app/symbol/interfaces/lookup-item.interface.ts index 92bbf7662..cf45f4c7e 100644 --- a/apps/api/src/app/symbol/interfaces/lookup-item.interface.ts +++ b/apps/api/src/app/symbol/interfaces/lookup-item.interface.ts @@ -1,7 +1,7 @@ -import { Currency, DataSource } from '@prisma/client'; +import { DataSource } from '@prisma/client'; export interface LookupItem { - currency: Currency; + currency: string; dataSource: DataSource; name: string; symbol: string; diff --git a/apps/api/src/app/symbol/interfaces/symbol-item.interface.ts b/apps/api/src/app/symbol/interfaces/symbol-item.interface.ts index fb18a2211..03554d649 100644 --- a/apps/api/src/app/symbol/interfaces/symbol-item.interface.ts +++ b/apps/api/src/app/symbol/interfaces/symbol-item.interface.ts @@ -1,7 +1,7 @@ -import { Currency, DataSource } from '@prisma/client'; +import { DataSource } from '@prisma/client'; export interface SymbolItem { - currency: Currency; + currency: string; dataSource: DataSource; marketPrice: number; } diff --git a/apps/api/src/app/symbol/symbol.service.ts b/apps/api/src/app/symbol/symbol.service.ts index 33307d6db..8940405aa 100644 --- a/apps/api/src/app/symbol/symbol.service.ts +++ b/apps/api/src/app/symbol/symbol.service.ts @@ -2,7 +2,7 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider/data import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; import { PrismaService } from '@ghostfolio/api/services/prisma.service'; import { Injectable } from '@nestjs/common'; -import { Currency, DataSource } from '@prisma/client'; +import { DataSource } from '@prisma/client'; import { LookupItem } from './interfaces/lookup-item.interface'; import { SymbolItem } from './interfaces/symbol-item.interface'; @@ -20,8 +20,8 @@ export class SymbolService { if (dataGatheringItem.dataSource && marketPrice) { return { + currency, marketPrice, - currency: (currency), dataSource: dataGatheringItem.dataSource }; } diff --git a/apps/api/src/app/user/interfaces/user-settings-params.interface.ts b/apps/api/src/app/user/interfaces/user-settings-params.interface.ts index e1e369e11..2df6285f6 100644 --- a/apps/api/src/app/user/interfaces/user-settings-params.interface.ts +++ b/apps/api/src/app/user/interfaces/user-settings-params.interface.ts @@ -1,7 +1,7 @@ -import { Currency, ViewMode } from '@prisma/client'; +import { ViewMode } from '@prisma/client'; export interface UserSettingsParams { - currency?: Currency; + currency?: string; userId: string; viewMode?: ViewMode; } diff --git a/apps/api/src/app/user/update-user-settings.dto.ts b/apps/api/src/app/user/update-user-settings.dto.ts index 953913bac..6f7c6338e 100644 --- a/apps/api/src/app/user/update-user-settings.dto.ts +++ b/apps/api/src/app/user/update-user-settings.dto.ts @@ -1,9 +1,9 @@ -import { Currency, ViewMode } from '@prisma/client'; +import { ViewMode } from '@prisma/client'; import { IsString } from 'class-validator'; export class UpdateUserSettingsDto { @IsString() - baseCurrency: Currency; + baseCurrency: string; @IsString() viewMode: ViewMode; diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 325f93284..d828c6988 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -1,12 +1,12 @@ import { SubscriptionService } from '@ghostfolio/api/app/subscription/subscription.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration.service'; import { PrismaService } from '@ghostfolio/api/services/prisma.service'; -import { locale } from '@ghostfolio/common/config'; +import { baseCurrency, locale } from '@ghostfolio/common/config'; import { User as IUser, UserWithSettings } from '@ghostfolio/common/interfaces'; import { getPermissions, permissions } from '@ghostfolio/common/permissions'; import { SubscriptionType } from '@ghostfolio/common/types/subscription.type'; import { Injectable } from '@nestjs/common'; -import { Currency, Prisma, Provider, User, ViewMode } from '@prisma/client'; +import { Prisma, Provider, User, ViewMode } from '@prisma/client'; import { UserSettingsParams } from './interfaces/user-settings-params.interface'; import { UserSettings } from './interfaces/user-settings.interface'; @@ -15,7 +15,7 @@ const crypto = require('crypto'); @Injectable() export class UserService { - public static DEFAULT_CURRENCY = Currency.USD; + public static DEFAULT_CURRENCY = 'USD'; public constructor( private readonly configurationService: ConfigurationService, @@ -144,9 +144,15 @@ export class UserService { ...data, Account: { create: { + currency: baseCurrency, isDefault: true, name: 'Default Account' } + }, + Settings: { + create: { + currency: baseCurrency + } } } }); diff --git a/apps/api/src/models/interfaces/user-settings.interface.ts b/apps/api/src/models/interfaces/user-settings.interface.ts index 6cfffedca..7da0c19ae 100644 --- a/apps/api/src/models/interfaces/user-settings.interface.ts +++ b/apps/api/src/models/interfaces/user-settings.interface.ts @@ -1,5 +1,3 @@ -import { Currency } from '@prisma/client'; - export interface UserSettings { - baseCurrency: Currency; + baseCurrency: string; } diff --git a/apps/api/src/models/order.ts b/apps/api/src/models/order.ts index c6ac4f2da..48928bc66 100644 --- a/apps/api/src/models/order.ts +++ b/apps/api/src/models/order.ts @@ -1,4 +1,4 @@ -import { Account, Currency, SymbolProfile } from '@prisma/client'; +import { Account, SymbolProfile } from '@prisma/client'; import { v4 as uuidv4 } from 'uuid'; import { IOrder } from '../services/interfaces/interfaces'; @@ -6,7 +6,7 @@ import { OrderType } from './order-type'; export class Order { private account: Account; - private currency: Currency; + private currency: string; private fee: number; private date: string; private id: string; diff --git a/apps/api/src/models/rule.ts b/apps/api/src/models/rule.ts index f725959fa..6bbb71e07 100644 --- a/apps/api/src/models/rule.ts +++ b/apps/api/src/models/rule.ts @@ -3,7 +3,6 @@ import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.in import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { groupBy } from '@ghostfolio/common/helper'; import { TimelinePosition } from '@ghostfolio/common/interfaces'; -import { Currency } from '@prisma/client'; import { EvaluationResult } from './interfaces/evaluation-result.interface'; import { RuleInterface } from './interfaces/rule.interface'; @@ -29,7 +28,7 @@ export abstract class Rule implements RuleInterface { public groupCurrentPositionsByAttribute( positions: TimelinePosition[], attribute: keyof TimelinePosition, - baseCurrency: Currency + baseCurrency: string ) { return Array.from(groupBy(attribute, positions).entries()).map( ([attributeValue, objs]) => ({ diff --git a/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts b/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts index 06e24960d..bd313153f 100644 --- a/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts +++ b/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts @@ -2,8 +2,6 @@ import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/curre import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; -import { PortfolioPosition } from '@ghostfolio/common/interfaces'; -import { Currency } from '@prisma/client'; import { Rule } from '../../rule'; @@ -69,5 +67,5 @@ export class CurrencyClusterRiskBaseCurrencyCurrentInvestment extends Rule { } interface Settings extends RuleSettings { - baseCurrency: Currency; + baseCurrency: string; threshold: number; } diff --git a/apps/api/src/models/rules/currency-cluster-risk/initial-investment.ts b/apps/api/src/models/rules/currency-cluster-risk/initial-investment.ts index 993e39247..541728d03 100644 --- a/apps/api/src/models/rules/currency-cluster-risk/initial-investment.ts +++ b/apps/api/src/models/rules/currency-cluster-risk/initial-investment.ts @@ -1,7 +1,6 @@ import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface'; -import { Currency } from '@prisma/client'; import { ExchangeRateDataService } from 'apps/api/src/services/exchange-rate-data.service'; import { Rule } from '../../rule'; @@ -69,6 +68,6 @@ export class CurrencyClusterRiskInitialInvestment extends Rule { } interface Settings extends RuleSettings { - baseCurrency: Currency; + baseCurrency: string; threshold: number; } diff --git a/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts b/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts index a51933016..105a9f199 100644 --- a/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts +++ b/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts @@ -1,6 +1,5 @@ import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface'; -import { Currency } from '@prisma/client'; import { ExchangeRateDataService } from 'apps/api/src/services/exchange-rate-data.service'; import { Rule } from '../../rule'; @@ -46,6 +45,6 @@ export class FeeRatioInitialInvestment extends Rule { } interface Settings extends RuleSettings { - baseCurrency: Currency; + baseCurrency: string; threshold: number; } diff --git a/apps/api/src/services/data-gathering.module.ts b/apps/api/src/services/data-gathering.module.ts index 539c76ac3..adf48a33b 100644 --- a/apps/api/src/services/data-gathering.module.ts +++ b/apps/api/src/services/data-gathering.module.ts @@ -4,8 +4,15 @@ import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data- import { PrismaModule } from '@ghostfolio/api/services/prisma.module'; import { Module } from '@nestjs/common'; +import { ExchangeRateDataModule } from './exchange-rate-data.module'; + @Module({ - imports: [ConfigurationModule, DataProviderModule, PrismaModule], + imports: [ + ConfigurationModule, + DataProviderModule, + ExchangeRateDataModule, + PrismaModule + ], providers: [DataGatheringService], exports: [DataGatheringService] }) diff --git a/apps/api/src/services/data-gathering.service.ts b/apps/api/src/services/data-gathering.service.ts index 2809d17e6..fb33823aa 100644 --- a/apps/api/src/services/data-gathering.service.ts +++ b/apps/api/src/services/data-gathering.service.ts @@ -1,6 +1,5 @@ import { benchmarks, - currencyPairs, ghostfolioFearAndGreedIndexSymbol } from '@ghostfolio/common/config'; import { DATE_FORMAT, getUtc, resetHours } from '@ghostfolio/common/helper'; @@ -19,6 +18,7 @@ import { import { ConfigurationService } from './configuration.service'; import { DataProviderService } from './data-provider/data-provider.service'; import { GhostfolioScraperApiService } from './data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service'; +import { ExchangeRateDataService } from './exchange-rate-data.service'; import { IDataGatheringItem } from './interfaces/interfaces'; import { PrismaService } from './prisma.service'; @@ -27,6 +27,7 @@ export class DataGatheringService { public constructor( private readonly configurationService: ConfigurationService, private readonly dataProviderService: DataProviderService, + private readonly exchangeRateDataService: ExchangeRateDataService, private readonly ghostfolioScraperApi: GhostfolioScraperApiService, private readonly prismaService: PrismaService ) {} @@ -230,6 +231,8 @@ export class DataGatheringService { } } + await this.exchangeRateDataService.initialize(); + if (hasError) { throw ''; } @@ -316,15 +319,15 @@ export class DataGatheringService { }; }); - const currencyPairsToGather = currencyPairs.map( - ({ dataSource, symbol }) => { + const currencyPairsToGather = this.exchangeRateDataService + .getCurrencyPairs() + .map(({ dataSource, symbol }) => { return { dataSource, symbol, date: startDate }; - } - ); + }); const customSymbolsToGather = await this.ghostfolioScraperApi.getCustomSymbolsToGather(startDate); @@ -343,15 +346,15 @@ export class DataGatheringService { const customSymbolsToGather = await this.ghostfolioScraperApi.getCustomSymbolsToGather(startDate); - const currencyPairsToGather = currencyPairs.map( - ({ dataSource, symbol }) => { + const currencyPairsToGather = this.exchangeRateDataService + .getCurrencyPairs() + .map(({ dataSource, symbol }) => { return { dataSource, symbol, date: startDate }; - } - ); + }); const symbolProfilesToGather = await this.prismaService.symbolProfile.findMany({ diff --git a/apps/api/src/services/data-provider/ghostfolio-scraper-api/interfaces/scraper-config.interface.ts b/apps/api/src/services/data-provider/ghostfolio-scraper-api/interfaces/scraper-config.interface.ts index 449ea987d..a6229bb85 100644 --- a/apps/api/src/services/data-provider/ghostfolio-scraper-api/interfaces/scraper-config.interface.ts +++ b/apps/api/src/services/data-provider/ghostfolio-scraper-api/interfaces/scraper-config.interface.ts @@ -1,7 +1,5 @@ -import { Currency } from '@prisma/client'; - export interface ScraperConfig { - currency: Currency; + currency: string; selector: string; symbol: string; url: string; diff --git a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts index 5383d6c28..a4408abdb 100644 --- a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts @@ -1,19 +1,9 @@ import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { UNKNOWN_KEY } from '@ghostfolio/common/config'; -import { - DATE_FORMAT, - isCrypto, - isCurrency, - parseCurrency -} from '@ghostfolio/common/helper'; +import { DATE_FORMAT, isCrypto, isCurrency } from '@ghostfolio/common/helper'; import { Granularity } from '@ghostfolio/common/types'; import { Injectable } from '@nestjs/common'; -import { - AssetClass, - AssetSubClass, - Currency, - DataSource -} from '@prisma/client'; +import { AssetClass, AssetSubClass, DataSource } from '@prisma/client'; import * as bent from 'bent'; import Big from 'big.js'; import { countries } from 'countries-list'; @@ -68,7 +58,7 @@ export class YahooFinanceService implements DataProviderInterface { response[symbol] = { assetClass, assetSubClass, - currency: parseCurrency(value.price?.currency), + currency: value.price?.currency, dataSource: DataSource.YAHOO, exchange: this.parseExchange(value.price?.exchangeName), marketState: @@ -81,7 +71,7 @@ export class YahooFinanceService implements DataProviderInterface { if (value.price?.currency === 'GBp') { // Convert GBp (pence) to GBP - response[symbol].currency = Currency.GBP; + response[symbol].currency = 'GBP'; response[symbol].marketPrice = new Big( value.price?.regularMarketPrice ?? 0 ) @@ -200,7 +190,7 @@ export class YahooFinanceService implements DataProviderInterface { .filter(({ quoteType, symbol }) => { if (quoteType === 'CRYPTOCURRENCY') { // Only allow cryptocurrencies in USD - return symbol.includes(Currency.USD); + return symbol.includes('USD'); } return true; diff --git a/apps/api/src/services/exchange-rate-data.module.ts b/apps/api/src/services/exchange-rate-data.module.ts index c95eb1ac1..4843b5c77 100644 --- a/apps/api/src/services/exchange-rate-data.module.ts +++ b/apps/api/src/services/exchange-rate-data.module.ts @@ -2,8 +2,10 @@ import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data- import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { Module } from '@nestjs/common'; +import { PrismaModule } from './prisma.module'; + @Module({ - imports: [DataProviderModule], + imports: [DataProviderModule, PrismaModule], providers: [ExchangeRateDataService], exports: [ExchangeRateDataService] }) diff --git a/apps/api/src/services/exchange-rate-data.service.ts b/apps/api/src/services/exchange-rate-data.service.ts index a9a4e2d6e..16432cc14 100644 --- a/apps/api/src/services/exchange-rate-data.service.ts +++ b/apps/api/src/services/exchange-rate-data.service.ts @@ -1,27 +1,45 @@ -import { currencyPairs } from '@ghostfolio/common/config'; +import { baseCurrency } from '@ghostfolio/common/config'; import { DATE_FORMAT, getYesterday } from '@ghostfolio/common/helper'; import { Injectable } from '@nestjs/common'; -import { Currency, DataSource } from '@prisma/client'; +import { DataSource } from '@prisma/client'; import { format } from 'date-fns'; -import { isEmpty, isNumber } from 'lodash'; +import { isEmpty, isNumber, uniq } from 'lodash'; import { DataProviderService } from './data-provider/data-provider.service'; import { IDataGatheringItem } from './interfaces/interfaces'; +import { PrismaService } from './prisma.service'; @Injectable() export class ExchangeRateDataService { + private currencies: string[] = []; private currencyPairs: IDataGatheringItem[] = []; private exchangeRates: { [currencyPair: string]: number } = {}; - public constructor(private dataProviderService: DataProviderService) { + public constructor( + private readonly dataProviderService: DataProviderService, + private readonly prismaService: PrismaService + ) { this.initialize(); } + public getCurrencies() { + return this.currencies?.length > 0 ? this.currencies : [baseCurrency]; + } + + public getCurrencyPairs() { + return this.currencyPairs; + } + public async initialize() { + this.currencies = await this.prepareCurrencies(); this.currencyPairs = []; this.exchangeRates = {}; - for (const { currency1, currency2, dataSource } of currencyPairs) { + for (const { + currency1, + currency2, + dataSource + } of this.prepareCurrencyPairs(this.currencies)) { this.addCurrencyPairs({ currency1, currency2, dataSource }); } @@ -77,8 +95,8 @@ export class ExchangeRateDataService { if (!this.exchangeRates[symbol]) { // Not found, calculate indirectly via USD this.exchangeRates[symbol] = - resultExtended[`${currency1}${Currency.USD}`]?.[date]?.marketPrice * - resultExtended[`${Currency.USD}${currency2}`]?.[date]?.marketPrice; + resultExtended[`${currency1}${'USD'}`]?.[date]?.marketPrice * + resultExtended[`${'USD'}${currency2}`]?.[date]?.marketPrice; // Calculate the opposite direction this.exchangeRates[`${currency2}${currency1}`] = @@ -89,10 +107,14 @@ export class ExchangeRateDataService { public toCurrency( aValue: number, - aFromCurrency: Currency, - aToCurrency: Currency + aFromCurrency: string, + aToCurrency: string ) { - if (isNaN(this.exchangeRates[`${Currency.USD}${Currency.CHF}`])) { + const hasNaN = Object.values(this.exchangeRates).some((exchangeRate) => { + return isNaN(exchangeRate); + }); + + if (hasNaN) { // Reinitialize if data is not loaded correctly this.initialize(); } @@ -104,8 +126,8 @@ export class ExchangeRateDataService { factor = this.exchangeRates[`${aFromCurrency}${aToCurrency}`]; } else { // Calculate indirectly via USD - const factor1 = this.exchangeRates[`${aFromCurrency}${Currency.USD}`]; - const factor2 = this.exchangeRates[`${Currency.USD}${aToCurrency}`]; + const factor1 = this.exchangeRates[`${aFromCurrency}${'USD'}`]; + const factor2 = this.exchangeRates[`${'USD'}${aToCurrency}`]; factor = factor1 * factor2; @@ -129,8 +151,8 @@ export class ExchangeRateDataService { currency2, dataSource }: { - currency1: Currency; - currency2: Currency; + currency1: string; + currency2: string; dataSource: DataSource; }) { this.currencyPairs.push({ @@ -142,4 +164,49 @@ export class ExchangeRateDataService { symbol: `${currency2}${currency1}` }); } + + private async prepareCurrencies(): Promise { + const currencies: string[] = []; + + const settings = await this.prismaService.settings.findMany({ + distinct: ['currency'], + orderBy: [{ currency: 'asc' }], + select: { currency: true } + }); + + settings.forEach((settingsItem) => { + if (settingsItem.currency) { + currencies.push(settingsItem.currency); + } + }); + + const symbolProfiles = await this.prismaService.symbolProfile.findMany({ + distinct: ['currency'], + orderBy: [{ currency: 'asc' }], + select: { currency: true } + }); + + symbolProfiles.forEach((symbolProfile) => { + if (symbolProfile.currency) { + currencies.push(symbolProfile.currency); + } + }); + + return uniq(currencies).sort(); + } + + private prepareCurrencyPairs(aCurrencies: string[]) { + return aCurrencies + .filter((currency) => { + return currency !== baseCurrency; + }) + .map((currency) => { + return { + currency1: baseCurrency, + currency2: currency, + dataSource: DataSource.YAHOO, + symbol: `${baseCurrency}${currency}` + }; + }); + } } diff --git a/apps/api/src/services/interfaces/interfaces.ts b/apps/api/src/services/interfaces/interfaces.ts index eef8d2dc0..a7d2e8d9f 100644 --- a/apps/api/src/services/interfaces/interfaces.ts +++ b/apps/api/src/services/interfaces/interfaces.ts @@ -2,7 +2,6 @@ import { Account, AssetClass, AssetSubClass, - Currency, DataSource, SymbolProfile } from '@prisma/client'; @@ -17,7 +16,7 @@ export const MarketState = { export interface IOrder { account: Account; - currency: Currency; + currency: string; date: string; fee: number; id?: string; @@ -38,7 +37,7 @@ export interface IDataProviderResponse { assetClass?: AssetClass; assetSubClass?: AssetSubClass; countries?: { code: string; weight: number }[]; - currency: Currency; + currency: string; dataSource: DataSource; exchange?: string; marketChange?: number; diff --git a/apps/api/src/services/interfaces/symbol-profile.interface.ts b/apps/api/src/services/interfaces/symbol-profile.interface.ts index 43585c3a9..2747319d1 100644 --- a/apps/api/src/services/interfaces/symbol-profile.interface.ts +++ b/apps/api/src/services/interfaces/symbol-profile.interface.ts @@ -1,17 +1,12 @@ import { Country } from '@ghostfolio/common/interfaces/country.interface'; import { Sector } from '@ghostfolio/common/interfaces/sector.interface'; -import { - AssetClass, - AssetSubClass, - Currency, - DataSource -} from '@prisma/client'; +import { AssetClass, AssetSubClass, DataSource } from '@prisma/client'; export interface EnhancedSymbolProfile { assetClass: AssetClass; assetSubClass: AssetSubClass; createdAt: Date; - currency: Currency | null; + currency: string | null; dataSource: DataSource; id: string; name: string | null; diff --git a/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts b/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts index 90d134d45..697941b70 100644 --- a/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts +++ b/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts @@ -8,7 +8,6 @@ import { ViewChild } from '@angular/core'; import { PortfolioPerformance } from '@ghostfolio/common/interfaces'; -import { Currency } from '@prisma/client'; import { CountUp } from 'countup.js'; import { isNumber } from 'lodash'; @@ -19,7 +18,7 @@ import { isNumber } from 'lodash'; styleUrls: ['./portfolio-performance.component.scss'] }) export class PortfolioPerformanceComponent implements OnChanges, OnInit { - @Input() baseCurrency: Currency; + @Input() baseCurrency: string; @Input() isLoading: boolean; @Input() locale: string; @Input() performance: PortfolioPerformance; diff --git a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts index 7ce3f33d8..77debbb0f 100644 --- a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts +++ b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts @@ -6,7 +6,6 @@ import { OnInit } from '@angular/core'; import { PortfolioSummary } from '@ghostfolio/common/interfaces'; -import { Currency } from '@prisma/client'; import { formatDistanceToNow } from 'date-fns'; @Component({ @@ -16,7 +15,7 @@ import { formatDistanceToNow } from 'date-fns'; styleUrls: ['./portfolio-summary.component.scss'] }) export class PortfolioSummaryComponent implements OnChanges, OnInit { - @Input() baseCurrency: Currency; + @Input() baseCurrency: string; @Input() isLoading: boolean; @Input() locale: string; @Input() summary: PortfolioSummary; diff --git a/apps/client/src/app/components/world-map-chart/world-map-chart.component.ts b/apps/client/src/app/components/world-map-chart/world-map-chart.component.ts index 70f201d27..85f5bc69f 100644 --- a/apps/client/src/app/components/world-map-chart/world-map-chart.component.ts +++ b/apps/client/src/app/components/world-map-chart/world-map-chart.component.ts @@ -7,7 +7,6 @@ import { OnDestroy, OnInit } from '@angular/core'; -import { Currency } from '@prisma/client'; import svgMap from 'svgmap'; @Component({ @@ -17,7 +16,7 @@ import svgMap from 'svgmap'; styleUrls: ['./world-map-chart.component.scss'] }) export class WorldMapChartComponent implements OnChanges, OnDestroy, OnInit { - @Input() baseCurrency: Currency; + @Input() baseCurrency: string; @Input() countries: { [code: string]: { name: string; value: number } }; public isLoading = true; diff --git a/apps/client/src/app/pages/account/account-page.component.ts b/apps/client/src/app/pages/account/account-page.component.ts index 3f87e37e1..764b8e1b0 100644 --- a/apps/client/src/app/pages/account/account-page.component.ts +++ b/apps/client/src/app/pages/account/account-page.component.ts @@ -15,7 +15,6 @@ import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service'; import { DEFAULT_DATE_FORMAT, baseCurrency } from '@ghostfolio/common/config'; import { Access, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; -import { Currency } from '@prisma/client'; import { StripeService } from 'ngx-stripe'; import { EMPTY, Subject } from 'rxjs'; import { catchError, switchMap, takeUntil } from 'rxjs/operators'; @@ -33,7 +32,7 @@ export class AccountPageComponent implements OnDestroy, OnInit { public baseCurrency = baseCurrency; public coupon: number; public couponId: string; - public currencies: Currency[] = []; + public currencies: string[] = []; public defaultDateFormat = DEFAULT_DATE_FORMAT; public hasPermissionForSubscription: boolean; public hasPermissionToUpdateViewMode: boolean; diff --git a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts index 2c8ecb416..23904e628 100644 --- a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts +++ b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts @@ -1,12 +1,10 @@ import { ChangeDetectionStrategy, - ChangeDetectorRef, Component, Inject, OnDestroy } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { Currency } from '@prisma/client'; import { Subject } from 'rxjs'; import { DataService } from '../../../services/data.service'; @@ -20,13 +18,12 @@ import { CreateOrUpdateAccountDialogParams } from './interfaces/interfaces'; templateUrl: 'create-or-update-account-dialog.html' }) export class CreateOrUpdateAccountDialog implements OnDestroy { - public currencies: Currency[] = []; + public currencies: string[] = []; public platforms: { id: string; name: string }[]; private unsubscribeSubject = new Subject(); public constructor( - private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: CreateOrUpdateAccountDialogParams diff --git a/apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.component.ts b/apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.component.ts index 6f5dfe6b3..262bdf774 100644 --- a/apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.component.ts +++ b/apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.component.ts @@ -11,7 +11,6 @@ import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { DataService } from '@ghostfolio/client/services/data.service'; -import { Currency } from '@prisma/client'; import { isString } from 'lodash'; import { EMPTY, Observable, Subject } from 'rxjs'; import { @@ -35,7 +34,7 @@ import { CreateOrUpdateTransactionDialogParams } from './interfaces/interfaces'; export class CreateOrUpdateTransactionDialog implements OnDestroy { @ViewChild('autocomplete') autocomplete; - public currencies: Currency[] = []; + public currencies: string[] = []; public currentMarketPrice = null; public filteredLookupItems: LookupItem[]; public filteredLookupItemsObservable: Observable; diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 6b27b7fae..fbf1449e5 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -1,31 +1,12 @@ import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; -import { Currency } from '@prisma/client'; import { DataSource } from '@prisma/client'; -export const baseCurrency = Currency.USD; +export const baseCurrency = 'USD'; export const benchmarks: Partial[] = [ { dataSource: DataSource.YAHOO, symbol: 'VOO' } ]; -export const currencyPairs: Partial< - IDataGatheringItem & { - currency1: Currency; - currency2: Currency; - } ->[] = (Object.keys(Currency) as Array) - .filter((currency) => { - return currency !== Currency.USD; - }) - .map((currency) => { - return { - currency1: Currency.USD, - currency2: Currency[currency], - dataSource: DataSource.YAHOO, - symbol: `${Currency.USD}${Currency[currency]}` - }; - }); - export const ghostfolioScraperApiSymbolPrefix = '_GF_'; export const ghostfolioCashSymbol = `${ghostfolioScraperApiSymbolPrefix}CASH`; export const ghostfolioFearAndGreedIndexSymbol = `${ghostfolioScraperApiSymbolPrefix}FEAR_AND_GREED_INDEX`; diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index 572724621..738399bf7 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -1,4 +1,3 @@ -import { Currency } from '@prisma/client'; import { getDate, getMonth, getYear, parse, subDays } from 'date-fns'; import { ghostfolioScraperApiSymbolPrefix } from './config'; @@ -87,9 +86,9 @@ export function isCrypto(aSymbol = '') { export function isCurrency(aSymbol = '') { return ( - (aSymbol.includes(Currency.CHF) || - aSymbol.includes(Currency.EUR) || - aSymbol.includes(Currency.USD)) && + (aSymbol.includes('CHF') || + aSymbol.includes('EUR') || + aSymbol.includes('USD')) && aSymbol.length >= 6 ); } @@ -102,10 +101,6 @@ export function isRakutenRapidApiSymbol(aSymbol = '') { return aSymbol === 'GF.FEAR_AND_GREED_INDEX'; } -export function parseCurrency(aCurrency: string): Currency { - return Currency[aCurrency]; -} - export function resetHours(aDate: Date) { const year = getYear(aDate); const month = getMonth(aDate); diff --git a/libs/common/src/lib/interfaces/info-item.interface.ts b/libs/common/src/lib/interfaces/info-item.interface.ts index 57d970993..9fad3d393 100644 --- a/libs/common/src/lib/interfaces/info-item.interface.ts +++ b/libs/common/src/lib/interfaces/info-item.interface.ts @@ -1,10 +1,8 @@ -import { Currency } from '@prisma/client'; - import { Statistics } from './statistics.interface'; import { Subscription } from './subscription.interface'; export interface InfoItem { - currencies: Currency[]; + currencies: string[]; demoAuthToken: string; globalPermissions: string[]; lastDataGathering?: Date; diff --git a/libs/common/src/lib/interfaces/portfolio-position.interface.ts b/libs/common/src/lib/interfaces/portfolio-position.interface.ts index 33d7769aa..ab86e0582 100644 --- a/libs/common/src/lib/interfaces/portfolio-position.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-position.interface.ts @@ -1,5 +1,5 @@ import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces'; -import { AssetClass, AssetSubClass, Currency } from '@prisma/client'; +import { AssetClass, AssetSubClass } from '@prisma/client'; import { Country } from './country.interface'; import { Sector } from './sector.interface'; @@ -10,7 +10,7 @@ export interface PortfolioPosition { assetClass?: AssetClass; assetSubClass?: AssetSubClass | 'CASH'; countries: Country[]; - currency: Currency; + currency: string; exchange?: string; grossPerformance: number; grossPerformancePercent: number; diff --git a/libs/common/src/lib/interfaces/position.interface.ts b/libs/common/src/lib/interfaces/position.interface.ts index 830c7fef1..d3ef64eb1 100644 --- a/libs/common/src/lib/interfaces/position.interface.ts +++ b/libs/common/src/lib/interfaces/position.interface.ts @@ -1,10 +1,10 @@ import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces'; -import { AssetClass, Currency } from '@prisma/client'; +import { AssetClass } from '@prisma/client'; export interface Position { assetClass: AssetClass; averagePrice: number; - currency: Currency; + currency: string; firstBuyDate: string; grossPerformance?: number; grossPerformancePercentage?: number; diff --git a/libs/common/src/lib/interfaces/timeline-position.interface.ts b/libs/common/src/lib/interfaces/timeline-position.interface.ts index f7f30f107..2e5aa6333 100644 --- a/libs/common/src/lib/interfaces/timeline-position.interface.ts +++ b/libs/common/src/lib/interfaces/timeline-position.interface.ts @@ -1,9 +1,9 @@ -import { Currency, DataSource } from '@prisma/client'; +import { DataSource } from '@prisma/client'; import Big from 'big.js'; export interface TimelinePosition { averagePrice: Big; - currency: Currency; + currency: string; dataSource: DataSource; firstBuyDate: string; grossPerformance: Big; diff --git a/libs/common/src/lib/interfaces/user-settings.interface.ts b/libs/common/src/lib/interfaces/user-settings.interface.ts index dd13c0e1e..d81f67f36 100644 --- a/libs/common/src/lib/interfaces/user-settings.interface.ts +++ b/libs/common/src/lib/interfaces/user-settings.interface.ts @@ -1,7 +1,7 @@ -import { Currency, ViewMode } from '@prisma/client'; +import { ViewMode } from '@prisma/client'; export interface UserSettings { - baseCurrency?: Currency; + baseCurrency?: string; isRestrictedView?: boolean; locale: string; viewMode?: ViewMode; diff --git a/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts b/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts index 5001fc758..917a1fe60 100644 --- a/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts +++ b/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts @@ -11,7 +11,6 @@ import { import { UNKNOWN_KEY } from '@ghostfolio/common/config'; import { getTextColor } from '@ghostfolio/common/helper'; import { PortfolioPosition } from '@ghostfolio/common/interfaces'; -import { Currency } from '@prisma/client'; import { Tooltip } from 'chart.js'; import { LinearScale } from 'chart.js'; import { ArcElement } from 'chart.js'; @@ -29,7 +28,7 @@ import * as Color from 'color'; export class PortfolioProportionChartComponent implements AfterViewInit, OnChanges, OnDestroy { - @Input() baseCurrency: Currency; + @Input() baseCurrency: string; @Input() isInPercent = false; @Input() keys: string[] = []; @Input() locale = ''; diff --git a/prisma/migrations/20210921151004_changed_currency_from_enum_to_string/migration.sql b/prisma/migrations/20210921151004_changed_currency_from_enum_to_string/migration.sql new file mode 100644 index 000000000..7ca7ad164 --- /dev/null +++ b/prisma/migrations/20210921151004_changed_currency_from_enum_to_string/migration.sql @@ -0,0 +1,14 @@ +-- AlterTable +ALTER TABLE "Account" ALTER COLUMN "currency" TYPE TEXT; + +-- AlterTable +ALTER TABLE "Order" ALTER COLUMN "currency" TYPE TEXT; + +-- AlterTable +ALTER TABLE "Settings" ALTER COLUMN "currency" TYPE TEXT; + +-- AlterTable +ALTER TABLE "SymbolProfile" ALTER COLUMN "currency" TYPE TEXT; + +-- DropEnum +DROP TYPE "Currency" CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 10f27e8ef..6eb2e04f6 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -28,7 +28,7 @@ model Account { accountType AccountType @default(SECURITIES) balance Float @default(0) createdAt DateTime @default(now()) - currency Currency @default(USD) + currency String? id String @default(uuid()) isDefault Boolean @default(false) name String? @@ -77,7 +77,7 @@ model Order { accountId String? accountUserId String? createdAt DateTime @default(now()) - currency Currency? + currency String? dataSource DataSource date DateTime fee Float @@ -109,7 +109,7 @@ model Property { } model Settings { - currency Currency? + currency String? settings Json? updatedAt DateTime @updatedAt viewMode ViewMode? @@ -122,7 +122,7 @@ model SymbolProfile { assetSubClass AssetSubClass? countries Json? createdAt DateTime @default(now()) - currency Currency? + currency String? dataSource DataSource id String @id @default(uuid()) name String? @@ -182,13 +182,6 @@ enum AssetSubClass { STOCK } -enum Currency { - CHF - EUR - GBP - USD -} - enum DataSource { ALPHA_VANTAGE GHOSTFOLIO diff --git a/prisma/seed.ts b/prisma/seed.ts index 5c99c0f9b..4622ac7c2 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -1,6 +1,5 @@ import { AccountType, - Currency, DataSource, PrismaClient, Role, @@ -88,7 +87,7 @@ async function main() { { accountType: AccountType.SECURITIES, balance: 0, - currency: Currency.USD, + currency: 'USD', id: 'f4425b66-9ba9-4ac4-93d7-fdf9a145e8cb', isDefault: true, name: 'Default Account' @@ -112,7 +111,7 @@ async function main() { { accountType: AccountType.SECURITIES, balance: 0, - currency: Currency.USD, + currency: 'USD', id: 'd804de69-0429-42dc-b6ca-b308fd7dd926', name: 'Coinbase Account', platformId: platformCoinbase.id @@ -120,7 +119,7 @@ async function main() { { accountType: AccountType.SECURITIES, balance: 0, - currency: Currency.EUR, + currency: 'EUR', id: '65cfb79d-b6c7-4591-9d46-73426bc62094', name: 'DEGIRO Account', platformId: platformDegiro.id @@ -128,7 +127,7 @@ async function main() { { accountType: AccountType.SECURITIES, balance: 0, - currency: Currency.USD, + currency: 'USD', id: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c', isDefault: true, name: 'Interactive Brokers Account', @@ -201,7 +200,7 @@ async function main() { { accountId: '65cfb79d-b6c7-4591-9d46-73426bc62094', accountUserId: userDemo.id, - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, date: new Date(Date.UTC(2017, 0, 3, 0, 0, 0)), fee: 30, @@ -216,7 +215,7 @@ async function main() { { accountId: 'd804de69-0429-42dc-b6ca-b308fd7dd926', accountUserId: userDemo.id, - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, date: new Date(Date.UTC(2017, 7, 16, 0, 0, 0)), fee: 29.9, @@ -231,7 +230,7 @@ async function main() { { accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c', accountUserId: userDemo.id, - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, date: new Date(Date.UTC(2018, 9, 1, 0, 0, 0)), fee: 80.79, @@ -246,7 +245,7 @@ async function main() { { accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c', accountUserId: userDemo.id, - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, date: new Date(Date.UTC(2019, 2, 1, 0, 0, 0)), fee: 19.9, @@ -261,7 +260,7 @@ async function main() { { accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c', accountUserId: userDemo.id, - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, date: new Date(Date.UTC(2019, 8, 3, 0, 0, 0)), fee: 19.9, @@ -276,7 +275,7 @@ async function main() { { accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c', accountUserId: userDemo.id, - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, date: new Date(Date.UTC(2020, 2, 2, 0, 0, 0)), fee: 19.9, @@ -291,7 +290,7 @@ async function main() { { accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c', accountUserId: userDemo.id, - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, date: new Date(Date.UTC(2020, 8, 1, 0, 0, 0)), fee: 19.9, @@ -306,7 +305,7 @@ async function main() { { accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c', accountUserId: userDemo.id, - currency: Currency.USD, + currency: 'USD', dataSource: DataSource.YAHOO, date: new Date(Date.UTC(2020, 2, 1, 0, 0, 0)), fee: 19.9,