diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index 7bd8606ee..c9e15ce4a 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -15,7 +15,6 @@ import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathe import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { DATA_GATHERING_QUEUE_PRIORITY_HIGH } from '@ghostfolio/common/config'; import { - DATE_FORMAT, getAssetProfileIdentifier, parseDate } from '@ghostfolio/common/helper'; @@ -29,8 +28,8 @@ import { import { Injectable } from '@nestjs/common'; import { DataSource, Prisma, SymbolProfile } from '@prisma/client'; import { Big } from 'big.js'; -import { endOfToday, format, isAfter, isSameSecond, parseISO } from 'date-fns'; -import { isNumber, uniqBy } from 'lodash'; +import { endOfToday, isAfter, isSameSecond, parseISO } from 'date-fns'; +import { uniqBy } from 'lodash'; import { v4 as uuidv4 } from 'uuid'; @Injectable() @@ -121,14 +120,14 @@ export class ImportService { currency: undefined, createdAt: undefined, fee: 0, - feeInSymbolCurrency: 0, + feeInAssetProfileCurrency: 0, id: assetProfile.id, isDraft: false, SymbolProfile: assetProfile, symbolProfileId: assetProfile.id, type: 'DIVIDEND', unitPrice: marketPrice, - unitPriceInSymbolCurrency: marketPrice, + unitPriceInAssetProfileCurrency: marketPrice, updatedAt: undefined, userId: Account?.userId, valueInBaseCurrency: @@ -267,17 +266,17 @@ export class ImportService { const activities: Activity[] = []; - for (const [index, activity] of activitiesExtendedWithErrors.entries()) { + for (const activity of activitiesExtendedWithErrors) { const accountId = activity.accountId; const comment = activity.comment; const currency = activity.currency; const date = activity.date; const error = activity.error; - let fee = activity.fee; + const fee = activity.fee; const quantity = activity.quantity; const SymbolProfile = activity.SymbolProfile; const type = activity.type; - let unitPrice = activity.unitPrice; + const unitPrice = activity.unitPrice; const assetProfile = assetProfiles[ getAssetProfileIdentifier({ @@ -285,7 +284,6 @@ export class ImportService { symbol: SymbolProfile.symbol }) ] ?? { - currency: SymbolProfile.currency, dataSource: SymbolProfile.dataSource, symbol: SymbolProfile.symbol }; @@ -321,35 +319,6 @@ export class ImportService { Account?: { id: string; name: string }; }); - if (SymbolProfile.currency !== assetProfile.currency) { - // Convert the unit price and fee to the asset currency if the imported - // activity is in a different currency - unitPrice = await this.exchangeRateDataService.toCurrencyAtDate( - unitPrice, - SymbolProfile.currency, - assetProfile.currency, - date - ); - - if (!isNumber(unitPrice)) { - throw new Error( - `activities.${index} historical exchange rate at ${format( - date, - DATE_FORMAT - )} is not available from "${SymbolProfile.currency}" to "${ - assetProfile.currency - }"` - ); - } - - fee = await this.exchangeRateDataService.toCurrencyAtDate( - fee, - SymbolProfile.currency, - assetProfile.currency, - date - ); - } - if (isDryRun) { order = { comment, @@ -401,6 +370,7 @@ export class ImportService { order = await this.orderService.createOrder({ comment, + currency, date, fee, quantity, @@ -445,7 +415,7 @@ export class ImportService { valueInBaseCurrency: await this.exchangeRateDataService.toCurrencyAtDate( value, - assetProfile.currency, + currency ?? assetProfile.currency, userCurrency, date ) @@ -515,7 +485,8 @@ export class ImportService { return ( activity.accountId === accountId && activity.comment === comment && - activity.SymbolProfile.currency === currency && + (activity.currency === currency || + activity.SymbolProfile.currency === currency) && activity.SymbolProfile.dataSource === dataSource && isSameSecond(activity.date, date) && activity.fee === fee && @@ -533,6 +504,7 @@ export class ImportService { return { accountId, comment, + currency, date, error, fee, @@ -540,7 +512,7 @@ export class ImportService { type, unitPrice, SymbolProfile: { - currency, + currency: undefined, dataSource, symbol, activitiesCount: undefined, diff --git a/apps/api/src/app/order/interfaces/activities.interface.ts b/apps/api/src/app/order/interfaces/activities.interface.ts index c3b487e0c..3dcde1464 100644 --- a/apps/api/src/app/order/interfaces/activities.interface.ts +++ b/apps/api/src/app/order/interfaces/activities.interface.ts @@ -11,10 +11,10 @@ export interface Activities { export interface Activity extends Order { Account?: AccountWithPlatform; error?: ActivityError; - feeInSymbolCurrency: number; + feeInAssetProfileCurrency: number; SymbolProfile?: EnhancedSymbolProfile; tags?: Tag[]; - unitPriceInSymbolCurrency: number; + unitPriceInAssetProfileCurrency: number; updateAccountBalance?: boolean; value: number; valueInBaseCurrency: number; diff --git a/apps/api/src/app/order/order.service.ts b/apps/api/src/app/order/order.service.ts index eaf576220..0745aa3d9 100644 --- a/apps/api/src/app/order/order.service.ts +++ b/apps/api/src/app/order/order.service.ts @@ -534,7 +534,7 @@ export class OrderService { return { ...order, value, - feeInSymbolCurrency: + feeInAssetProfileCurrency: await this.exchangeRateDataService.toCurrencyAtDate( order.fee, order.currency ?? order.SymbolProfile.currency, @@ -542,7 +542,7 @@ export class OrderService { order.date ), SymbolProfile: assetProfile, - unitPriceInSymbolCurrency: + unitPriceInAssetProfileCurrency: await this.exchangeRateDataService.toCurrencyAtDate( order.unitPrice, order.currency ?? order.SymbolProfile.currency, diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 1657733ef..9698cb315 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -112,12 +112,12 @@ export abstract class PortfolioCalculator { .map( ({ date, - feeInSymbolCurrency, + feeInAssetProfileCurrency, quantity, SymbolProfile, tags = [], type, - unitPriceInSymbolCurrency + unitPriceInAssetProfileCurrency }) => { if (isBefore(date, dateOfFirstActivity)) { dateOfFirstActivity = date; @@ -134,9 +134,9 @@ export abstract class PortfolioCalculator { tags, type, date: format(date, DATE_FORMAT), - fee: new Big(feeInSymbolCurrency), + fee: new Big(feeInAssetProfileCurrency), quantity: new Big(quantity), - unitPrice: new Big(unitPriceInSymbolCurrency) + unitPrice: new Big(unitPriceInAssetProfileCurrency) }; } ) diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts index be216239b..eed5a1e80 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts @@ -91,7 +91,7 @@ describe('PortfolioCalculator', () => { { ...activityDummyData, date: new Date('2021-11-22'), - feeInSymbolCurrency: 1.55, + feeInAssetProfileCurrency: 1.55, quantity: 2, SymbolProfile: { ...symbolProfileDummyData, @@ -101,12 +101,12 @@ describe('PortfolioCalculator', () => { symbol: 'BALN.SW' }, type: 'BUY', - unitPriceInSymbolCurrency: 142.9 + unitPriceInAssetProfileCurrency: 142.9 }, { ...activityDummyData, date: new Date('2021-11-30'), - feeInSymbolCurrency: 1.65, + feeInAssetProfileCurrency: 1.65, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -116,12 +116,12 @@ describe('PortfolioCalculator', () => { symbol: 'BALN.SW' }, type: 'SELL', - unitPriceInSymbolCurrency: 136.6 + unitPriceInAssetProfileCurrency: 136.6 }, { ...activityDummyData, date: new Date('2021-11-30'), - feeInSymbolCurrency: 0, + feeInAssetProfileCurrency: 0, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -131,7 +131,7 @@ describe('PortfolioCalculator', () => { symbol: 'BALN.SW' }, type: 'SELL', - unitPriceInSymbolCurrency: 136.6 + unitPriceInAssetProfileCurrency: 136.6 } ]; diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts index ac15f5be0..15f3983fe 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts @@ -91,7 +91,7 @@ describe('PortfolioCalculator', () => { { ...activityDummyData, date: new Date('2021-11-22'), - feeInSymbolCurrency: 1.55, + feeInAssetProfileCurrency: 1.55, quantity: 2, SymbolProfile: { ...symbolProfileDummyData, @@ -101,12 +101,12 @@ describe('PortfolioCalculator', () => { symbol: 'BALN.SW' }, type: 'BUY', - unitPriceInSymbolCurrency: 142.9 + unitPriceInAssetProfileCurrency: 142.9 }, { ...activityDummyData, date: new Date('2021-11-30'), - feeInSymbolCurrency: 1.65, + feeInAssetProfileCurrency: 1.65, quantity: 2, SymbolProfile: { ...symbolProfileDummyData, @@ -116,7 +116,7 @@ describe('PortfolioCalculator', () => { symbol: 'BALN.SW' }, type: 'SELL', - unitPriceInSymbolCurrency: 136.6 + unitPriceInAssetProfileCurrency: 136.6 } ]; diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts index 4c3fbd5bf..7a34bd114 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts @@ -91,7 +91,7 @@ describe('PortfolioCalculator', () => { { ...activityDummyData, date: new Date('2021-11-30'), - feeInSymbolCurrency: 1.55, + feeInAssetProfileCurrency: 1.55, quantity: 2, SymbolProfile: { ...symbolProfileDummyData, @@ -101,7 +101,7 @@ describe('PortfolioCalculator', () => { symbol: 'BALN.SW' }, type: 'BUY', - unitPriceInSymbolCurrency: 136.6 + unitPriceInAssetProfileCurrency: 136.6 } ]; diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts index 2f2440ead..3158076cb 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts @@ -105,7 +105,7 @@ describe('PortfolioCalculator', () => { { ...activityDummyData, date: new Date('2015-01-01'), - feeInSymbolCurrency: 0, + feeInAssetProfileCurrency: 0, quantity: 2, SymbolProfile: { ...symbolProfileDummyData, @@ -115,12 +115,12 @@ describe('PortfolioCalculator', () => { symbol: 'BTCUSD' }, type: 'BUY', - unitPriceInSymbolCurrency: 320.43 + unitPriceInAssetProfileCurrency: 320.43 }, { ...activityDummyData, date: new Date('2017-12-31'), - feeInSymbolCurrency: 0, + feeInAssetProfileCurrency: 0, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -130,7 +130,7 @@ describe('PortfolioCalculator', () => { symbol: 'BTCUSD' }, type: 'SELL', - unitPriceInSymbolCurrency: 14156.4 + unitPriceInAssetProfileCurrency: 14156.4 } ]; diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts index 022c96621..22a34af24 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts @@ -91,7 +91,7 @@ describe('PortfolioCalculator', () => { { ...activityDummyData, date: new Date('2021-09-01'), - feeInSymbolCurrency: 49, + feeInAssetProfileCurrency: 49, quantity: 0, SymbolProfile: { ...symbolProfileDummyData, @@ -101,7 +101,7 @@ describe('PortfolioCalculator', () => { symbol: '2c463fb3-af07-486e-adb0-8301b3d72141' }, type: 'FEE', - unitPriceInSymbolCurrency: 0 + unitPriceInAssetProfileCurrency: 0 } ]; diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts index 32e4bc6c1..41299eb40 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts @@ -104,7 +104,7 @@ describe('PortfolioCalculator', () => { { ...activityDummyData, date: new Date('2023-01-03'), - feeInSymbolCurrency: 1, + feeInAssetProfileCurrency: 1, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -114,7 +114,7 @@ describe('PortfolioCalculator', () => { symbol: 'GOOGL' }, type: 'BUY', - unitPriceInSymbolCurrency: 89.12 + unitPriceInAssetProfileCurrency: 89.12 } ]; diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-item.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-item.spec.ts index 1d89d848d..721c9ae96 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-item.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-item.spec.ts @@ -91,7 +91,7 @@ describe('PortfolioCalculator', () => { { ...activityDummyData, date: new Date('2022-01-01'), - feeInSymbolCurrency: 0, + feeInAssetProfileCurrency: 0, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -101,7 +101,7 @@ describe('PortfolioCalculator', () => { symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde' }, type: 'ITEM', - unitPriceInSymbolCurrency: 500000 + unitPriceInAssetProfileCurrency: 500000 } ]; diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-liability.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-liability.spec.ts index 00c1a3720..a82e605d4 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-liability.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-liability.spec.ts @@ -91,7 +91,7 @@ describe('PortfolioCalculator', () => { { ...activityDummyData, date: new Date('2023-01-01'), // Date in future - feeInSymbolCurrency: 0, + feeInAssetProfileCurrency: 0, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -101,7 +101,7 @@ describe('PortfolioCalculator', () => { symbol: '55196015-1365-4560-aa60-8751ae6d18f8' }, type: 'LIABILITY', - unitPriceInSymbolCurrency: 3000 + unitPriceInAssetProfileCurrency: 3000 } ]; diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts index f841384c9..d8e774639 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts @@ -104,7 +104,7 @@ describe('PortfolioCalculator', () => { { ...activityDummyData, date: new Date('2021-09-16'), - feeInSymbolCurrency: 19, + feeInAssetProfileCurrency: 19, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -114,12 +114,12 @@ describe('PortfolioCalculator', () => { symbol: 'MSFT' }, type: 'BUY', - unitPriceInSymbolCurrency: 298.58 + unitPriceInAssetProfileCurrency: 298.58 }, { ...activityDummyData, date: new Date('2021-11-16'), - feeInSymbolCurrency: 0, + feeInAssetProfileCurrency: 0, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -129,7 +129,7 @@ describe('PortfolioCalculator', () => { symbol: 'MSFT' }, type: 'DIVIDEND', - unitPriceInSymbolCurrency: 0.62 + unitPriceInAssetProfileCurrency: 0.62 } ]; diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts index 1620ff258..ffbfe7345 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts @@ -105,7 +105,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, ...activity, date: parseDate(activity.date), - feeInSymbolCurrency: activity.fee, + feeInAssetProfileCurrency: activity.fee, SymbolProfile: { ...symbolProfileDummyData, currency: activity.currency, @@ -113,7 +113,7 @@ describe('PortfolioCalculator', () => { name: 'Novartis AG', symbol: activity.symbol }, - unitPriceInSymbolCurrency: activity.unitPrice + unitPriceInAssetProfileCurrency: activity.unitPrice })); const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts index 457248faa..0256a6a1e 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts @@ -105,7 +105,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, ...activity, date: parseDate(activity.date), - feeInSymbolCurrency: activity.fee, + feeInAssetProfileCurrency: activity.fee, SymbolProfile: { ...symbolProfileDummyData, currency: activity.currency, @@ -113,7 +113,7 @@ describe('PortfolioCalculator', () => { name: 'Novartis AG', symbol: activity.symbol }, - unitPriceInSymbolCurrency: activity.unitPrice + unitPriceInAssetProfileCurrency: activity.unitPrice })); const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ diff --git a/apps/client/src/app/services/import-activities.service.ts b/apps/client/src/app/services/import-activities.service.ts index c1b2209b3..f334a159f 100644 --- a/apps/client/src/app/services/import-activities.service.ts +++ b/apps/client/src/app/services/import-activities.service.ts @@ -126,6 +126,7 @@ export class ImportActivitiesService { private convertToCreateOrderDto({ accountId, comment, + currency, date, fee, quantity, @@ -137,12 +138,12 @@ export class ImportActivitiesService { return { accountId, comment, + currency, fee, quantity, type, unitPrice, updateAccountBalance, - currency: SymbolProfile.currency, dataSource: SymbolProfile.dataSource, date: date.toString(), symbol: SymbolProfile.symbol