diff --git a/CHANGELOG.md b/CHANGELOG.md index 64bf66cf3..c648ceac8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,16 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -### Fixed +### Added -- Hid the net performance in the _Presenter View_ (portfolio holdings and summary tab on the home page) -- Hid the sign if the performance is zero in the value component +- Added the data source attribute to the symbol profile model ### Changed +- Respected the data source attribute in the data provider service - Respected the data source attribute in the symbol data endpoint - Improved the search functionality of the data management (multiple data sources) +### Fixed + +- Hid the net performance in the _Presenter View_ (portfolio holdings and summary tab on the home page) +- Hid the sign if the performance is zero in the value component + +### Todo + +- Apply data migration (`yarn database:push`) + ## 1.53.0 - 13.09.2021 ### Changed 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 78f209ef4..7054633a0 100644 --- a/apps/api/src/app/portfolio/current-rate.service.spec.ts +++ b/apps/api/src/app/portfolio/current-rate.service.spec.ts @@ -14,6 +14,7 @@ jest.mock('./market-data.service', () => { date, symbol, createdAt: date, + dataSource: DataSource.YAHOO, id: 'aefcbe3a-ee10-4c4f-9f2d-8ffad7b05584', marketPrice: 1847.839966 }); @@ -30,6 +31,7 @@ jest.mock('./market-data.service', () => { return Promise.resolve([ { createdAt: dateRangeStart, + dataSource: DataSource.YAHOO, date: dateRangeStart, id: '8fa48fde-f397-4b0d-adbc-fb940e830e6d', marketPrice: 1841.823902, @@ -37,6 +39,7 @@ jest.mock('./market-data.service', () => { }, { createdAt: dateRangeEnd, + dataSource: DataSource.YAHOO, date: dateRangeEnd, id: '082d6893-df27-4c91-8a5d-092e84315b56', marketPrice: 1847.839966, diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 9d19b6459..88a8ffeeb 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -333,6 +333,7 @@ export class PortfolioService { const { averagePrice, currency, + dataSource, firstBuyDate, marketPrice, quantity, @@ -358,7 +359,7 @@ export class PortfolioService { ); const historicalData = await this.dataProviderService.getHistorical( - [aSymbol], + [{ dataSource, symbol: aSymbol }], 'day', parseISO(firstBuyDate), new Date() @@ -434,7 +435,7 @@ export class PortfolioService { const marketPrice = currentData[aSymbol]?.marketPrice; let historicalData = await this.dataProviderService.getHistorical( - [aSymbol], + [{ dataSource: DataSource.YAHOO, symbol: aSymbol }], 'day', portfolioStart, new Date() diff --git a/apps/api/src/services/data-gathering.service.ts b/apps/api/src/services/data-gathering.service.ts index 918965b0a..2809d17e6 100644 --- a/apps/api/src/services/data-gathering.service.ts +++ b/apps/api/src/services/data-gathering.service.ts @@ -206,6 +206,7 @@ export class DataGatheringService { try { await this.prismaService.marketData.create({ data: { + dataSource, symbol, date: currentDate, marketPrice: lastMarketPrice diff --git a/apps/api/src/services/data-provider/data-provider.service.ts b/apps/api/src/services/data-provider/data-provider.service.ts index a9bcf4064..0fe506a92 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -66,7 +66,7 @@ export class DataProviderService { } public async getHistorical( - aSymbols: string[], + aItems: IDataGatheringItem[], aGranularity: Granularity = 'month', from: Date, to: Date @@ -90,8 +90,17 @@ export class DataProviderService { )}'` : ''; + const dataSources = aItems.map((item) => { + return item.dataSource; + }); + const symbols = aItems.map((item) => { + return item.symbol; + }); + try { - const queryRaw = `SELECT * FROM "MarketData" WHERE "symbol" IN ('${aSymbols.join( + const queryRaw = `SELECT * FROM "MarketData" WHERE "dataSource" IN ('${dataSources.join( + `','` + )}') AND "symbol" IN ('${symbols.join( `','` )}') ${granularityQuery} ${rangeQuery} ORDER BY date;`; diff --git a/apps/api/src/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service.ts b/apps/api/src/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service.ts index a230f88bd..aad7dbd0f 100644 --- a/apps/api/src/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service.ts +++ b/apps/api/src/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service.ts @@ -94,6 +94,7 @@ export class RakutenRapidApiService implements DataProviderInterface { await this.prismaService.marketData.create({ data: { symbol, + dataSource: DataSource.RAKUTEN, date: subWeeks(getToday(), 1), marketPrice: fgi.oneWeekAgo.value } @@ -102,6 +103,7 @@ export class RakutenRapidApiService implements DataProviderInterface { await this.prismaService.marketData.create({ data: { symbol, + dataSource: DataSource.RAKUTEN, date: subMonths(getToday(), 1), marketPrice: fgi.oneMonthAgo.value } @@ -110,6 +112,7 @@ export class RakutenRapidApiService implements DataProviderInterface { await this.prismaService.marketData.create({ data: { symbol, + dataSource: DataSource.RAKUTEN, date: subYears(getToday(), 1), marketPrice: fgi.oneYearAgo.value } diff --git a/apps/api/src/services/exchange-rate-data.service.ts b/apps/api/src/services/exchange-rate-data.service.ts index f4c853e7d..a9a4e2d6e 100644 --- a/apps/api/src/services/exchange-rate-data.service.ts +++ b/apps/api/src/services/exchange-rate-data.service.ts @@ -6,10 +6,11 @@ import { format } from 'date-fns'; import { isEmpty, isNumber } from 'lodash'; import { DataProviderService } from './data-provider/data-provider.service'; +import { IDataGatheringItem } from './interfaces/interfaces'; @Injectable() export class ExchangeRateDataService { - private currencyPairs: string[] = []; + private currencyPairs: IDataGatheringItem[] = []; private exchangeRates: { [currencyPair: string]: number } = {}; public constructor(private dataProviderService: DataProviderService) { @@ -20,8 +21,8 @@ export class ExchangeRateDataService { this.currencyPairs = []; this.exchangeRates = {}; - for (const { currency1, currency2 } of currencyPairs) { - this.addCurrencyPairs(currency1, currency2); + for (const { currency1, currency2, dataSource } of currencyPairs) { + this.addCurrencyPairs({ currency1, currency2, dataSource }); } await this.loadCurrencies(); @@ -39,8 +40,8 @@ export class ExchangeRateDataService { // Load currencies directly from data provider as a fallback // if historical data is not yet available const historicalData = await this.dataProviderService.get( - this.currencyPairs.map((currencyPair) => { - return { dataSource: DataSource.YAHOO, symbol: currencyPair }; + this.currencyPairs.map(({ dataSource, symbol }) => { + return { dataSource, symbol }; }) ); @@ -67,21 +68,21 @@ export class ExchangeRateDataService { }; }); - this.currencyPairs.forEach((pair) => { - const [currency1, currency2] = pair.match(/.{1,3}/g); + this.currencyPairs.forEach(({ symbol }) => { + const [currency1, currency2] = symbol.match(/.{1,3}/g); const date = format(getYesterday(), DATE_FORMAT); - this.exchangeRates[pair] = resultExtended[pair]?.[date]?.marketPrice; + this.exchangeRates[symbol] = resultExtended[symbol]?.[date]?.marketPrice; - if (!this.exchangeRates[pair]) { + if (!this.exchangeRates[symbol]) { // Not found, calculate indirectly via USD - this.exchangeRates[pair] = + this.exchangeRates[symbol] = resultExtended[`${currency1}${Currency.USD}`]?.[date]?.marketPrice * resultExtended[`${Currency.USD}${currency2}`]?.[date]?.marketPrice; // Calculate the opposite direction this.exchangeRates[`${currency2}${currency1}`] = - 1 / this.exchangeRates[pair]; + 1 / this.exchangeRates[symbol]; } }); } @@ -123,8 +124,22 @@ export class ExchangeRateDataService { return aValue; } - private addCurrencyPairs(aCurrency1: Currency, aCurrency2: Currency) { - this.currencyPairs.push(`${aCurrency1}${aCurrency2}`); - this.currencyPairs.push(`${aCurrency2}${aCurrency1}`); + private addCurrencyPairs({ + currency1, + currency2, + dataSource + }: { + currency1: Currency; + currency2: Currency; + dataSource: DataSource; + }) { + this.currencyPairs.push({ + dataSource, + symbol: `${currency1}${currency2}` + }); + this.currencyPairs.push({ + dataSource, + symbol: `${currency2}${currency1}` + }); } } diff --git a/prisma/migrations/20210916182355_added_data_source_to_market_data/migration.sql b/prisma/migrations/20210916182355_added_data_source_to_market_data/migration.sql new file mode 100644 index 000000000..83911236a --- /dev/null +++ b/prisma/migrations/20210916182355_added_data_source_to_market_data/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "MarketData" ADD COLUMN "dataSource" "DataSource" NOT NULL DEFAULT E'YAHOO'; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 15bf573c1..8cff7862c 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -61,9 +61,10 @@ model AuthDevice { } model MarketData { - createdAt DateTime @default(now()) + createdAt DateTime @default(now()) + dataSource DataSource @default(YAHOO) date DateTime - id String @default(uuid()) + id String @default(uuid()) symbol String marketPrice Float