Extend current rate service with getRange()

pull/239/head
Thomas 4 years ago
parent 7dac059a55
commit 099571437e

@ -17,6 +17,28 @@ jest.mock('./market-data.service', () => {
id: 'aefcbe3a-ee10-4c4f-9f2d-8ffad7b05584',
marketPrice: 1847.839966
});
},
getRange: (
dateRangeEnd: Date,
dateRangeStart: Date,
symbol: string
) => {
return Promise.resolve<MarketData[]>([
{
date: dateRangeStart,
symbol,
createdAt: dateRangeStart,
id: '8fa48fde-f397-4b0d-adbc-fb940e830e6d',
marketPrice: 1841.823902
},
{
date: dateRangeEnd,
symbol,
createdAt: dateRangeEnd,
id: '082d6893-df27-4c91-8a5d-092e84315b56',
marketPrice: 1847.839966
}
]);
}
};
})
@ -71,6 +93,29 @@ describe('CurrentRateService', () => {
symbol: 'AMZN',
userCurrency: Currency.CHF
})
).toEqual(1847.839966);
).toMatchObject({
marketPrice: 1847.839966
});
});
it('getValues', async () => {
expect(
await currentRateService.getValues({
currency: Currency.USD,
dateRangeEnd: new Date(Date.UTC(2020, 0, 2, 0, 0, 0)),
dateRangeStart: new Date(Date.UTC(2020, 0, 1, 0, 0, 0)),
symbol: 'AMZN',
userCurrency: Currency.CHF
})
).toMatchObject([
{
// date
marketPrice: 1841.823902
},
{
// date
marketPrice: 1847.839966
}
]);
});
});

@ -1,5 +1,6 @@
import { DataProviderService } from '@ghostfolio/api/services/data-provider.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
import { resetHours } from '@ghostfolio/common/helper';
import { Injectable } from '@nestjs/common';
import { Currency } from '@prisma/client';
import { isToday } from 'date-fns';
@ -19,10 +20,13 @@ export class CurrentRateService {
date,
symbol,
userCurrency
}: GetValueParams): Promise<number> {
}: GetValueParams): Promise<GetValueObject> {
if (isToday(date)) {
const dataProviderResult = await this.dataProviderService.get([symbol]);
return dataProviderResult?.[symbol]?.marketPrice ?? 0;
return {
date: resetHours(date),
marketPrice: dataProviderResult?.[symbol]?.marketPrice ?? 0
};
}
const marketData = await this.marketDataService.get({
@ -31,14 +35,50 @@ export class CurrentRateService {
});
if (marketData) {
return this.exchangeRateDataService.toCurrency(
marketData.marketPrice,
currency,
userCurrency
);
return {
date: marketData.date,
marketPrice: this.exchangeRateDataService.toCurrency(
marketData.marketPrice,
currency,
userCurrency
)
};
}
throw new Error(`Value not found for ${symbol} at ${date}`);
throw new Error(`Value not found for ${symbol} at ${resetHours(date)}`);
}
public async getValues({
currency,
dateRangeEnd,
dateRangeStart,
symbol,
userCurrency
}: GetValuesParams): Promise<GetValueObject[]> {
const marketData = await this.marketDataService.getRange({
dateRangeEnd,
dateRangeStart,
symbol
});
if (marketData) {
return marketData.map((marketDataItem) => {
return {
date: marketDataItem.date,
marketPrice: this.exchangeRateDataService.toCurrency(
marketDataItem.marketPrice,
currency,
userCurrency
)
};
});
}
throw new Error(
`Values not found for ${symbol} from ${resetHours(
dateRangeStart
)} to ${resetHours(dateRangeEnd)}`
);
}
}
@ -48,3 +88,16 @@ export interface GetValueParams {
currency: Currency;
userCurrency: Currency;
}
export interface GetValuesParams {
dateRangeEnd: Date;
dateRangeStart: Date;
symbol: string;
currency: Currency;
userCurrency: Currency;
}
export interface GetValueObject {
date: Date;
marketPrice: number;
}

@ -2,6 +2,7 @@ import { PrismaService } from '@ghostfolio/api/services/prisma.service';
import { resetHours } from '@ghostfolio/common/helper';
import { Injectable } from '@nestjs/common';
import { MarketData } from '@prisma/client';
import { endOfDay } from 'date-fns';
@Injectable()
export class MarketDataService {
@ -21,4 +22,24 @@ export class MarketDataService {
}
});
}
public async getRange({
dateRangeEnd,
dateRangeStart,
symbol
}: {
dateRangeEnd: Date;
dateRangeStart: Date;
symbol: string;
}): Promise<MarketData[]> {
return await this.prisma.marketData.findMany({
where: {
date: {
gte: dateRangeStart,
lt: endOfDay(dateRangeEnd)
},
symbol
}
});
}
}

@ -1,15 +1,15 @@
import {
CurrentRateService,
GetValueParams
} from '@ghostfolio/api/app/core/current-rate.service';
import {
PortfolioCalculator,
PortfolioOrder,
TimelinePeriod,
TimelineSpecification
} from '@ghostfolio/api/app/core/portfolio-calculator';
import {
CurrentRateService,
GetValueParams
} from '@ghostfolio/api/app/core/current-rate.service';
import { Currency } from '@prisma/client';
import { OrderType } from '@ghostfolio/api/models/order-type';
import { Currency } from '@prisma/client';
import Big from 'big.js';
import { differenceInCalendarDays, parse } from 'date-fns';
@ -46,21 +46,21 @@ jest.mock('./current-rate.service.ts', () => {
const today = new Date();
if (symbol === 'VTI') {
if (dateEqual(today, date)) {
return Promise.resolve(new Big('213.32'));
return Promise.resolve({ marketPrice: new Big('213.32') });
} else {
const startDate = parse('2019-02-01', 'yyyy-MM-dd', new Date());
const daysInBetween = differenceInCalendarDays(date, startDate);
const result = new Big('144.38').plus(
const marketPrice = new Big('144.38').plus(
new Big('0.08').mul(daysInBetween)
);
return Promise.resolve(result);
return Promise.resolve({ marketPrice });
}
} else if (symbol === 'AMZN') {
return Promise.resolve(2021.99);
return Promise.resolve({ marketPrice: new Big('2021.99') });
}
return Promise.resolve(new Big('0'));
return Promise.resolve({ marketPrice: new Big('0') });
}
};
})

@ -1,6 +1,6 @@
import { Currency } from '@prisma/client';
import { CurrentRateService } from '@ghostfolio/api/app/core/current-rate.service';
import { OrderType } from '@ghostfolio/api/models/order-type';
import { Currency } from '@prisma/client';
import Big from 'big.js';
import {
addDays,
@ -110,7 +110,7 @@ export class PortfolioCalculator {
const result: { [symbol: string]: TimelinePosition } = {};
for (const item of lastTransactionPoint.items) {
const marketPrice = await this.currentRateService.getValue({
const marketValue = await this.currentRateService.getValue({
date: new Date(),
symbol: item.symbol,
currency: item.currency,
@ -122,7 +122,7 @@ export class PortfolioCalculator {
quantity: item.quantity,
symbol: item.symbol,
investment: item.investment,
marketPrice: marketPrice,
marketPrice: marketValue.marketPrice,
transactionCount: item.transactionCount
};
}
@ -186,7 +186,7 @@ export class PortfolioCalculator {
currency: item.currency,
userCurrency: this.currency
})
.then((v) => new Big(v).mul(item.quantity))
.then(({ marketPrice }) => new Big(marketPrice).mul(item.quantity))
);
}
}

Loading…
Cancel
Save