Bugfix/fix currency conversion in accounts (#937)
* Fix currency conversion in accounts * Update changelog
This commit is contained in:
parent
f5819cc399
commit
af0863d193
@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed an issue with the currency conversion in the account calculations
|
||||||
- Fixed an issue with countries in the symbol profile overrides
|
- Fixed an issue with countries in the symbol profile overrides
|
||||||
|
|
||||||
## 1.149.0 - 16.05.2022
|
## 1.149.0 - 16.05.2022
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { parseDate, resetHours } from '@ghostfolio/common/helper';
|
import { parseDate, resetHours } from '@ghostfolio/common/helper';
|
||||||
import { addDays, endOfDay, isBefore, isSameDay } from 'date-fns';
|
import { addDays, endOfDay, isBefore, isSameDay } from 'date-fns';
|
||||||
|
|
||||||
|
import { GetValueObject } from './interfaces/get-value-object.interface';
|
||||||
import { GetValuesParams } from './interfaces/get-values-params.interface';
|
import { GetValuesParams } from './interfaces/get-values-params.interface';
|
||||||
|
|
||||||
function mockGetValue(symbol: string, date: Date) {
|
function mockGetValue(symbol: string, date: Date) {
|
||||||
@ -33,8 +34,11 @@ function mockGetValue(symbol: string, date: Date) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const CurrentRateServiceMock = {
|
export const CurrentRateServiceMock = {
|
||||||
getValues: ({ dataGatheringItems, dateQuery }: GetValuesParams) => {
|
getValues: ({
|
||||||
const result = [];
|
dataGatheringItems,
|
||||||
|
dateQuery
|
||||||
|
}: GetValuesParams): Promise<GetValueObject[]> => {
|
||||||
|
const result: GetValueObject[] = [];
|
||||||
if (dateQuery.lt) {
|
if (dateQuery.lt) {
|
||||||
for (
|
for (
|
||||||
let date = resetHours(dateQuery.gte);
|
let date = resetHours(dateQuery.gte);
|
||||||
@ -44,8 +48,10 @@ export const CurrentRateServiceMock = {
|
|||||||
for (const dataGatheringItem of dataGatheringItems) {
|
for (const dataGatheringItem of dataGatheringItems) {
|
||||||
result.push({
|
result.push({
|
||||||
date,
|
date,
|
||||||
marketPrice: mockGetValue(dataGatheringItem.symbol, date)
|
marketPriceInBaseCurrency: mockGetValue(
|
||||||
.marketPrice,
|
dataGatheringItem.symbol,
|
||||||
|
date
|
||||||
|
).marketPrice,
|
||||||
symbol: dataGatheringItem.symbol
|
symbol: dataGatheringItem.symbol
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -55,8 +61,10 @@ export const CurrentRateServiceMock = {
|
|||||||
for (const dataGatheringItem of dataGatheringItems) {
|
for (const dataGatheringItem of dataGatheringItems) {
|
||||||
result.push({
|
result.push({
|
||||||
date,
|
date,
|
||||||
marketPrice: mockGetValue(dataGatheringItem.symbol, date)
|
marketPriceInBaseCurrency: mockGetValue(
|
||||||
.marketPrice,
|
dataGatheringItem.symbol,
|
||||||
|
date
|
||||||
|
).marketPrice,
|
||||||
symbol: dataGatheringItem.symbol
|
symbol: dataGatheringItem.symbol
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import { MarketDataService } from '@ghostfolio/api/services/market-data.service'
|
|||||||
import { DataSource, MarketData } from '@prisma/client';
|
import { DataSource, MarketData } from '@prisma/client';
|
||||||
|
|
||||||
import { CurrentRateService } from './current-rate.service';
|
import { CurrentRateService } from './current-rate.service';
|
||||||
|
import { GetValueObject } from './interfaces/get-value-object.interface';
|
||||||
|
|
||||||
jest.mock('@ghostfolio/api/services/market-data.service', () => {
|
jest.mock('@ghostfolio/api/services/market-data.service', () => {
|
||||||
return {
|
return {
|
||||||
@ -96,15 +97,15 @@ describe('CurrentRateService', () => {
|
|||||||
},
|
},
|
||||||
userCurrency: 'CHF'
|
userCurrency: 'CHF'
|
||||||
})
|
})
|
||||||
).toMatchObject([
|
).toMatchObject<GetValueObject[]>([
|
||||||
{
|
{
|
||||||
date: undefined,
|
date: undefined,
|
||||||
marketPrice: 1841.823902,
|
marketPriceInBaseCurrency: 1841.823902,
|
||||||
symbol: 'AMZN'
|
symbol: 'AMZN'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: undefined,
|
date: undefined,
|
||||||
marketPrice: 1847.839966,
|
marketPriceInBaseCurrency: 1847.839966,
|
||||||
symbol: 'AMZN'
|
symbol: 'AMZN'
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
@ -28,13 +28,7 @@ export class CurrentRateService {
|
|||||||
(!dateQuery.gte || isBefore(dateQuery.gte, new Date())) &&
|
(!dateQuery.gte || isBefore(dateQuery.gte, new Date())) &&
|
||||||
(!dateQuery.in || this.containsToday(dateQuery.in));
|
(!dateQuery.in || this.containsToday(dateQuery.in));
|
||||||
|
|
||||||
const promises: Promise<
|
const promises: Promise<GetValueObject[]>[] = [];
|
||||||
{
|
|
||||||
date: Date;
|
|
||||||
marketPrice: number;
|
|
||||||
symbol: string;
|
|
||||||
}[]
|
|
||||||
>[] = [];
|
|
||||||
|
|
||||||
if (includeToday) {
|
if (includeToday) {
|
||||||
const today = resetHours(new Date());
|
const today = resetHours(new Date());
|
||||||
@ -42,16 +36,17 @@ export class CurrentRateService {
|
|||||||
this.dataProviderService
|
this.dataProviderService
|
||||||
.getQuotes(dataGatheringItems)
|
.getQuotes(dataGatheringItems)
|
||||||
.then((dataResultProvider) => {
|
.then((dataResultProvider) => {
|
||||||
const result = [];
|
const result: GetValueObject[] = [];
|
||||||
for (const dataGatheringItem of dataGatheringItems) {
|
for (const dataGatheringItem of dataGatheringItems) {
|
||||||
result.push({
|
result.push({
|
||||||
date: today,
|
date: today,
|
||||||
marketPrice: this.exchangeRateDataService.toCurrency(
|
marketPriceInBaseCurrency:
|
||||||
dataResultProvider?.[dataGatheringItem.symbol]?.marketPrice ??
|
this.exchangeRateDataService.toCurrency(
|
||||||
0,
|
dataResultProvider?.[dataGatheringItem.symbol]
|
||||||
dataResultProvider?.[dataGatheringItem.symbol]?.currency,
|
?.marketPrice ?? 0,
|
||||||
userCurrency
|
dataResultProvider?.[dataGatheringItem.symbol]?.currency,
|
||||||
),
|
userCurrency
|
||||||
|
),
|
||||||
symbol: dataGatheringItem.symbol
|
symbol: dataGatheringItem.symbol
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -74,11 +69,12 @@ export class CurrentRateService {
|
|||||||
return data.map((marketDataItem) => {
|
return data.map((marketDataItem) => {
|
||||||
return {
|
return {
|
||||||
date: marketDataItem.date,
|
date: marketDataItem.date,
|
||||||
marketPrice: this.exchangeRateDataService.toCurrency(
|
marketPriceInBaseCurrency:
|
||||||
marketDataItem.marketPrice,
|
this.exchangeRateDataService.toCurrency(
|
||||||
currencies[marketDataItem.symbol],
|
marketDataItem.marketPrice,
|
||||||
userCurrency
|
currencies[marketDataItem.symbol],
|
||||||
),
|
userCurrency
|
||||||
|
),
|
||||||
symbol: marketDataItem.symbol
|
symbol: marketDataItem.symbol
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export interface GetValueObject {
|
export interface GetValueObject {
|
||||||
date: Date;
|
date: Date;
|
||||||
marketPrice: number;
|
marketPriceInBaseCurrency: number;
|
||||||
symbol: string;
|
symbol: string;
|
||||||
}
|
}
|
||||||
|
@ -231,9 +231,9 @@ export class PortfolioCalculator {
|
|||||||
if (!marketSymbolMap[date]) {
|
if (!marketSymbolMap[date]) {
|
||||||
marketSymbolMap[date] = {};
|
marketSymbolMap[date] = {};
|
||||||
}
|
}
|
||||||
if (marketSymbol.marketPrice) {
|
if (marketSymbol.marketPriceInBaseCurrency) {
|
||||||
marketSymbolMap[date][marketSymbol.symbol] = new Big(
|
marketSymbolMap[date][marketSymbol.symbol] = new Big(
|
||||||
marketSymbol.marketPrice
|
marketSymbol.marketPriceInBaseCurrency
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -548,9 +548,9 @@ export class PortfolioCalculator {
|
|||||||
if (!marketSymbolMap[date]) {
|
if (!marketSymbolMap[date]) {
|
||||||
marketSymbolMap[date] = {};
|
marketSymbolMap[date] = {};
|
||||||
}
|
}
|
||||||
if (marketSymbol.marketPrice) {
|
if (marketSymbol.marketPriceInBaseCurrency) {
|
||||||
marketSymbolMap[date][marketSymbol.symbol] = new Big(
|
marketSymbolMap[date][marketSymbol.symbol] = new Big(
|
||||||
marketSymbol.marketPrice
|
marketSymbol.marketPriceInBaseCurrency
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -462,8 +462,9 @@ export class PortfolioService {
|
|||||||
|
|
||||||
const accounts = await this.getValueOfAccounts({
|
const accounts = await this.getValueOfAccounts({
|
||||||
orders,
|
orders,
|
||||||
userId,
|
|
||||||
portfolioItemsNow,
|
portfolioItemsNow,
|
||||||
|
userCurrency,
|
||||||
|
userId,
|
||||||
filters: aFilters
|
filters: aFilters
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -899,7 +900,8 @@ export class PortfolioService {
|
|||||||
const accounts = await this.getValueOfAccounts({
|
const accounts = await this.getValueOfAccounts({
|
||||||
orders,
|
orders,
|
||||||
portfolioItemsNow,
|
portfolioItemsNow,
|
||||||
userId
|
userId,
|
||||||
|
userCurrency: currency
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
rules: {
|
rules: {
|
||||||
@ -1268,11 +1270,13 @@ export class PortfolioService {
|
|||||||
filters = [],
|
filters = [],
|
||||||
orders,
|
orders,
|
||||||
portfolioItemsNow,
|
portfolioItemsNow,
|
||||||
|
userCurrency,
|
||||||
userId
|
userId
|
||||||
}: {
|
}: {
|
||||||
filters?: Filter[];
|
filters?: Filter[];
|
||||||
orders: OrderWithAccount[];
|
orders: OrderWithAccount[];
|
||||||
portfolioItemsNow: { [p: string]: TimelinePosition };
|
portfolioItemsNow: { [p: string]: TimelinePosition };
|
||||||
|
userCurrency: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
}) {
|
}) {
|
||||||
const accounts: PortfolioDetails['accounts'] = {};
|
const accounts: PortfolioDetails['accounts'] = {};
|
||||||
@ -1301,34 +1305,47 @@ export class PortfolioService {
|
|||||||
accounts[account.id] = {
|
accounts[account.id] = {
|
||||||
balance: account.balance,
|
balance: account.balance,
|
||||||
currency: account.currency,
|
currency: account.currency,
|
||||||
current: account.balance,
|
current: this.exchangeRateDataService.toCurrency(
|
||||||
|
account.balance,
|
||||||
|
account.currency,
|
||||||
|
userCurrency
|
||||||
|
),
|
||||||
name: account.name,
|
name: account.name,
|
||||||
original: account.balance
|
original: this.exchangeRateDataService.toCurrency(
|
||||||
|
account.balance,
|
||||||
|
account.currency,
|
||||||
|
userCurrency
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const order of ordersByAccount) {
|
for (const order of ordersByAccount) {
|
||||||
let currentValueOfSymbol =
|
let currentValueOfSymbolInBaseCurrency =
|
||||||
order.quantity *
|
order.quantity *
|
||||||
portfolioItemsNow[order.SymbolProfile.symbol].marketPrice;
|
portfolioItemsNow[order.SymbolProfile.symbol].marketPrice;
|
||||||
let originalValueOfSymbol = order.quantity * order.unitPrice;
|
let originalValueOfSymbolInBaseCurrency =
|
||||||
|
this.exchangeRateDataService.toCurrency(
|
||||||
|
order.quantity * order.unitPrice,
|
||||||
|
order.SymbolProfile.currency,
|
||||||
|
userCurrency
|
||||||
|
);
|
||||||
|
|
||||||
if (order.type === 'SELL') {
|
if (order.type === 'SELL') {
|
||||||
currentValueOfSymbol *= -1;
|
currentValueOfSymbolInBaseCurrency *= -1;
|
||||||
originalValueOfSymbol *= -1;
|
originalValueOfSymbolInBaseCurrency *= -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accounts[order.Account?.id || UNKNOWN_KEY]?.current) {
|
if (accounts[order.Account?.id || UNKNOWN_KEY]?.current) {
|
||||||
accounts[order.Account?.id || UNKNOWN_KEY].current +=
|
accounts[order.Account?.id || UNKNOWN_KEY].current +=
|
||||||
currentValueOfSymbol;
|
currentValueOfSymbolInBaseCurrency;
|
||||||
accounts[order.Account?.id || UNKNOWN_KEY].original +=
|
accounts[order.Account?.id || UNKNOWN_KEY].original +=
|
||||||
originalValueOfSymbol;
|
originalValueOfSymbolInBaseCurrency;
|
||||||
} else {
|
} else {
|
||||||
accounts[order.Account?.id || UNKNOWN_KEY] = {
|
accounts[order.Account?.id || UNKNOWN_KEY] = {
|
||||||
balance: 0,
|
balance: 0,
|
||||||
currency: order.Account?.currency,
|
currency: order.Account?.currency,
|
||||||
current: currentValueOfSymbol,
|
current: currentValueOfSymbolInBaseCurrency,
|
||||||
name: account.name,
|
name: account.name,
|
||||||
original: originalValueOfSymbol
|
original: originalValueOfSymbolInBaseCurrency
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user