From 1e5ea8ca5863a4a268a18e52422d1e00edd731d2 Mon Sep 17 00:00:00 2001 From: Agustin Alexander Date: Sun, 12 Feb 2023 12:04:39 -0300 Subject: [PATCH 1/9] Set default to unformatted --- .../yahoo-finance/yahoo-finance.service.ts | 71 ++++++++++--------- 1 file changed, 37 insertions(+), 34 deletions(-) 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 bccc5c648..758f2f2d4 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,15 +1,15 @@ -import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; -import { ConfigurationService } from '@ghostfolio/api/services/configuration.service'; -import { CryptocurrencyService } from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.service'; -import { DataProviderInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface'; +import {LookupItem} from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; +import {ConfigurationService} from '@ghostfolio/api/services/configuration.service'; +import {CryptocurrencyService} from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.service'; +import {DataProviderInterface} from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface'; import { IDataProviderHistoricalResponse, IDataProviderResponse } from '@ghostfolio/api/services/interfaces/interfaces'; -import { UNKNOWN_KEY } from '@ghostfolio/common/config'; -import { DATE_FORMAT, isCurrency } from '@ghostfolio/common/helper'; -import { Granularity } from '@ghostfolio/common/types'; -import { Injectable, Logger } from '@nestjs/common'; +import {UNKNOWN_KEY} from '@ghostfolio/common/config'; +import {DATE_FORMAT, isCurrency} from '@ghostfolio/common/helper'; +import {Granularity} from '@ghostfolio/common/types'; +import {Injectable, Logger} from '@nestjs/common'; import { AssetClass, AssetSubClass, @@ -17,10 +17,10 @@ import { SymbolProfile } from '@prisma/client'; import Big from 'big.js'; -import { countries } from 'countries-list'; -import { addDays, format, isSameDay } from 'date-fns'; +import {countries} from 'countries-list'; +import {addDays, format, isSameDay} from 'date-fns'; import yahooFinance from 'yahoo-finance2'; -import type { Price } from 'yahoo-finance2/dist/esm/src/modules/quoteSummary-iface'; +import type {Price} from 'yahoo-finance2/dist/esm/src/modules/quoteSummary-iface'; @Injectable() export class YahooFinanceService implements DataProviderInterface { @@ -101,7 +101,7 @@ export class YahooFinanceService implements DataProviderInterface { modules: ['price', 'summaryProfile', 'topHoldings'] }); - const { assetClass, assetSubClass } = this.parseAssetClass( + const {assetClass, assetSubClass} = this.parseAssetClass( assetProfile.price ); @@ -123,7 +123,7 @@ export class YahooFinanceService implements DataProviderInterface { for (const sectorWeighting of assetProfile.topHoldings ?.sectorWeightings ?? []) { for (const [sector, weight] of Object.entries(sectorWeighting)) { - response.sectors.push({ weight, name: this.parseSector(sector) }); + response.sectors.push({weight, name: this.parseSector(sector)}); } } } else if ( @@ -138,13 +138,14 @@ export class YahooFinanceService implements DataProviderInterface { }); if (code) { - response.countries = [{ code, weight: 1 }]; + response.countries = [{code, weight: 1}]; } - } catch {} + } catch { + } if (assetProfile.summaryProfile?.sector) { response.sectors = [ - { name: assetProfile.summaryProfile?.sector, weight: 1 } + {name: assetProfile.summaryProfile?.sector, weight: 1} ]; } } @@ -161,11 +162,11 @@ export class YahooFinanceService implements DataProviderInterface { } public async getDividends({ - from, - granularity = 'day', - symbol, - to - }: { + from, + granularity = 'day', + symbol, + to + }: { from: Date; granularity: Granularity; symbol: string; @@ -368,7 +369,7 @@ export class YahooFinanceService implements DataProviderInterface { // Filter out undefined symbols return quote.symbol; }) - .filter(({ quoteType, symbol }) => { + .filter(({quoteType, symbol}) => { return ( (quoteType === 'CRYPTOCURRENCY' && this.cryptocurrencyService.isCryptocurrency( @@ -380,7 +381,7 @@ export class YahooFinanceService implements DataProviderInterface { ['EQUITY', 'ETF', 'FUTURE', 'MUTUALFUND'].includes(quoteType) ); }) - .filter(({ quoteType, symbol }) => { + .filter(({quoteType, symbol}) => { if (quoteType === 'CRYPTOCURRENCY') { // Only allow cryptocurrencies in base currency to avoid having redundancy in the database. // Transactions need to be converted manually to the base currency before @@ -394,7 +395,7 @@ export class YahooFinanceService implements DataProviderInterface { }); const marketData = await yahooFinance.quote( - quotes.map(({ symbol }) => { + quotes.map(({symbol}) => { return symbol; }) ); @@ -424,15 +425,15 @@ export class YahooFinanceService implements DataProviderInterface { Logger.error(error, 'YahooFinanceService'); } - return { items }; + return {items}; } private formatName({ - longName, - quoteType, - shortName, - symbol - }: { + longName, + quoteType, + shortName, + symbol + }: { longName: Price['longName']; quoteType: Price['quoteType']; shortName: Price['shortName']; @@ -462,9 +463,9 @@ export class YahooFinanceService implements DataProviderInterface { } private getConvertedValue({ - symbol, - value - }: { + symbol, + value + }: { symbol: string; value: number; }) { @@ -522,7 +523,7 @@ export class YahooFinanceService implements DataProviderInterface { break; } - return { assetClass, assetSubClass }; + return {assetClass, assetSubClass}; } private parseSector(aString: string): string { @@ -562,6 +563,8 @@ export class YahooFinanceService implements DataProviderInterface { case 'utilities': sector = 'Utilities'; break; + default: + sector = aString; } return sector; From d9e8cade6daddeb8e409c4d1f7dc117a56c3d6ce Mon Sep 17 00:00:00 2001 From: Agustin Alexander Date: Sun, 12 Feb 2023 20:53:14 -0300 Subject: [PATCH 2/9] Added Unknown Mode disabled so that users can get cleaner graphs when some assets are not classified with country or sector. --- .../src/app/portfolio/portfolio.service.ts | 18 ++++++++++++++- .../src/app/user/update-user-setting.dto.ts | 7 +++++- apps/api/src/app/user/user.service.ts | 4 ++++ .../yahoo-finance/yahoo-finance.service.ts | 2 +- .../pages/account/account-page.component.ts | 22 +++++++++++++++++++ .../src/app/pages/account/account-page.html | 16 ++++++++++++++ .../allocations/allocations-page.component.ts | 4 ++-- .../app/pages/public/public-page.component.ts | 18 ++++++++++++--- .../lib/interfaces/user-settings.interface.ts | 3 ++- libs/common/src/lib/permissions.ts | 9 +++++--- libs/common/src/lib/types/index.ts | 5 +++-- libs/common/src/lib/types/view-mode.type.ts | 1 + .../migration.sql | 2 ++ prisma/schema.prisma | 5 +++++ 14 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 prisma/migrations/20230212232240_added_unknown_mode/migration.sql diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 6700eda99..6e34525d8 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -85,6 +85,8 @@ import { } from './interfaces/portfolio-position-detail.interface'; import { PortfolioCalculator } from './portfolio-calculator'; import { RulesService } from './rules.service'; +import {countries} from "countries-list"; +import {Country} from "@ghostfolio/common/interfaces/country.interface"; const developedMarkets = require('../../assets/countries/developed-markets.json'); const emergingMarkets = require('../../assets/countries/emerging-markets.json'); @@ -462,7 +464,7 @@ export class PortfolioService { }); const holdings: PortfolioDetails['holdings'] = {}; - const totalInvestmentInBaseCurrency = currentPositions.totalInvestment.plus( + currentPositions.totalInvestment.plus( cashDetails.balanceInBaseCurrency ); let filteredValueInBaseCurrency = currentPositions.currentValue; @@ -1269,10 +1271,24 @@ export class PortfolioService { cashPositions[symbol].allocationInPercentage = value.gt(0) ? new Big(cashPositions[symbol].value).div(value).toNumber() : 0; + cashPositions[symbol].sectors = [ { + "name": "OTHER", + "weight": 1 + }] + cashPositions[symbol].countries = this.matchCurrencyToCountries(symbol) } return cashPositions; } + private matchCurrencyToCountries(aString: string): Country[] { + const csformat = [] + switch (aString) { + case 'USD': + csformat.push(countries.US) + break; + } + return csformat; + } private getDividend({ activities, diff --git a/apps/api/src/app/user/update-user-setting.dto.ts b/apps/api/src/app/user/update-user-setting.dto.ts index 97062df9d..a096f76f8 100644 --- a/apps/api/src/app/user/update-user-setting.dto.ts +++ b/apps/api/src/app/user/update-user-setting.dto.ts @@ -1,7 +1,8 @@ import type { ColorScheme, DateRange, - ViewMode + ViewMode, + UnknownMode } from '@ghostfolio/common/types'; import { IsBoolean, @@ -55,4 +56,8 @@ export class UpdateUserSettingDto { @IsIn(['DEFAULT', 'ZEN']) @IsOptional() viewMode?: ViewMode; + + @IsIn(['DEFAULT', 'OFF']) + @IsOptional() + unknownMode?: UnknownMode; } diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index b45d1849d..f9cc97936 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -163,6 +163,10 @@ export class UserService { (user.Settings.settings as UserSettings).viewMode = 'DEFAULT'; } + if (!(user.Settings.settings as UserSettings).unknownMode) { + (user.Settings.settings as UserSettings).unknownMode = 'DEFAULT'; + } + let currentPermissions = getPermissions(user.role); if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { 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 758f2f2d4..9f09c8570 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 @@ -117,7 +117,7 @@ export class YahooFinanceService implements DataProviderInterface { }); response.symbol = aSymbol; - if (assetSubClass === AssetSubClass.MUTUALFUND) { + if (assetSubClass === AssetSubClass.MUTUALFUND || assetSubClass === AssetSubClass.ETF) { response.sectors = []; for (const sectorWeighting of assetProfile.topHoldings 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 56e43c755..30e3e26a5 100644 --- a/apps/client/src/app/pages/account/account-page.component.ts +++ b/apps/client/src/app/pages/account/account-page.component.ts @@ -53,6 +53,7 @@ export class AccountPageComponent implements OnDestroy, OnInit { public hasPermissionToCreateAccess: boolean; public hasPermissionToDeleteAccess: boolean; public hasPermissionToUpdateViewMode: boolean; + public hasPermissionToUpdateUnknownMode: boolean; public hasPermissionToUpdateUserSettings: boolean; public language = document.documentElement.lang; public locales = [ @@ -138,6 +139,11 @@ export class AccountPageComponent implements OnDestroy, OnInit { permissions.updateViewMode ); + this.hasPermissionToUpdateUnknownMode = hasPermission( + this.user.permissions, + permissions.updateUnknownMode + ); + this.locales.push(this.user.settings.locale); this.locales = uniq(this.locales.sort()); @@ -330,6 +336,22 @@ export class AccountPageComponent implements OnDestroy, OnInit { }); }); } + public onUnknownChange(aEvent: MatSlideToggleChange) { + this.dataService + .putUserSetting({ unknownMode: aEvent.checked === true ? 'DEFAULT' : 'OFF'}) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(() => { + this.userService.remove(); + + this.userService + .get() + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((user) => { + this.user = user; + this.changeDetectorRef.markForCheck(); + }); + }); + } public ngOnDestroy() { this.unsubscribeSubject.next(); diff --git a/apps/client/src/app/pages/account/account-page.html b/apps/client/src/app/pages/account/account-page.html index 8779273ae..536366850 100644 --- a/apps/client/src/app/pages/account/account-page.html +++ b/apps/client/src/app/pages/account/account-page.html @@ -225,6 +225,22 @@ > +
+
+
Unknown Mode
+
+ Show Unknown categories in Portfolio Allocation View +
+
+
+ +
+
Sign in with fingerprint
diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts index 325b39af7..4ecdf70a0 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts @@ -309,7 +309,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit { }; } } - } else { + } else if (this.user.settings.unknownMode === "DEFAULT") { this.continents[UNKNOWN_KEY].value += this.portfolioDetails.holdings[symbol].value; @@ -330,7 +330,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit { }; } } - } else { + } else if (this.user.settings.unknownMode === "DEFAULT") { this.sectors[UNKNOWN_KEY].value += this.portfolioDetails.holdings[symbol].value; } diff --git a/apps/client/src/app/pages/public/public-page.component.ts b/apps/client/src/app/pages/public/public-page.component.ts index f25c69dae..5940c5f9d 100644 --- a/apps/client/src/app/pages/public/public-page.component.ts +++ b/apps/client/src/app/pages/public/public-page.component.ts @@ -5,7 +5,7 @@ import { UNKNOWN_KEY } from '@ghostfolio/common/config'; import { prettifySymbol } from '@ghostfolio/common/helper'; import { PortfolioPosition, - PortfolioPublicDetails + PortfolioPublicDetails, User } from '@ghostfolio/common/interfaces'; import { Market } from '@ghostfolio/common/types'; import { StatusCodes } from 'http-status-codes'; @@ -13,6 +13,7 @@ import { isNumber } from 'lodash'; import { DeviceDetectorService } from 'ngx-device-detector'; import { EMPTY, Subject } from 'rxjs'; import { catchError, takeUntil } from 'rxjs/operators'; +import { UserService } from '@ghostfolio/client/services/user/user.service'; @Component({ host: { class: 'page' }, @@ -47,23 +48,34 @@ export class PublicPageComponent implements OnInit { }; private id: string; + + private user: User; + private unsubscribeSubject = new Subject(); public constructor( private activatedRoute: ActivatedRoute, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private userService: UserService, private deviceService: DeviceDetectorService, private router: Router ) { this.activatedRoute.params.subscribe((params) => { this.id = params['id']; }); + this.userService.stateChanged + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((state) => { + if (state?.user) { + this.user = state.user; + this.initializeAnalysisData() + } + }); } public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; - this.dataService .fetchPortfolioPublic(this.id) .pipe( @@ -191,7 +203,7 @@ export class PublicPageComponent implements OnInit { }; } } - } else { + } else if (this.user.settings.unknownMode === "DEFAULT") { this.sectors[UNKNOWN_KEY].value += this.portfolioPublicDetails.holdings[symbol].value; } diff --git a/libs/common/src/lib/interfaces/user-settings.interface.ts b/libs/common/src/lib/interfaces/user-settings.interface.ts index 1dedc6277..890345390 100644 --- a/libs/common/src/lib/interfaces/user-settings.interface.ts +++ b/libs/common/src/lib/interfaces/user-settings.interface.ts @@ -1,4 +1,4 @@ -import { ColorScheme, DateRange, ViewMode } from '@ghostfolio/common/types'; +import {ColorScheme, DateRange, UnknownMode, ViewMode} from '@ghostfolio/common/types'; export interface UserSettings { baseCurrency?: string; @@ -12,4 +12,5 @@ export interface UserSettings { locale?: string; savingsRate?: number; viewMode?: ViewMode; + unknownMode?: UnknownMode; } diff --git a/libs/common/src/lib/permissions.ts b/libs/common/src/lib/permissions.ts index b9dc6806a..75e571528 100644 --- a/libs/common/src/lib/permissions.ts +++ b/libs/common/src/lib/permissions.ts @@ -27,7 +27,8 @@ export const permissions = { updateAuthDevice: 'updateAuthDevice', updateOrder: 'updateOrder', updateUserSettings: 'updateUserSettings', - updateViewMode: 'updateViewMode' + updateViewMode: 'updateViewMode', + updateUnknownMode: 'updateUnknownMode' }; export function getPermissions(aRole: Role): string[] { @@ -47,7 +48,8 @@ export function getPermissions(aRole: Role): string[] { permissions.updateAuthDevice, permissions.updateOrder, permissions.updateUserSettings, - permissions.updateViewMode + permissions.updateViewMode, + permissions.updateUnknownMode ]; case 'DEMO': @@ -66,7 +68,8 @@ export function getPermissions(aRole: Role): string[] { permissions.updateAuthDevice, permissions.updateOrder, permissions.updateUserSettings, - permissions.updateViewMode + permissions.updateViewMode, + permissions.updateUnknownMode ]; default: diff --git a/libs/common/src/lib/types/index.ts b/libs/common/src/lib/types/index.ts index 12bee4132..e9072ed9d 100644 --- a/libs/common/src/lib/types/index.ts +++ b/libs/common/src/lib/types/index.ts @@ -10,7 +10,7 @@ import { Market } from './market.type'; import type { OrderWithAccount } from './order-with-account.type'; import type { RequestWithUser } from './request-with-user.type'; import { ToggleOption } from './toggle-option.type'; -import type { ViewMode } from './view-mode.type'; +import type { ViewMode, UnknownMode } from './view-mode.type'; export type { AccessWithGranteeUser, @@ -25,5 +25,6 @@ export type { OrderWithAccount, RequestWithUser, ToggleOption, - ViewMode + ViewMode, + UnknownMode }; diff --git a/libs/common/src/lib/types/view-mode.type.ts b/libs/common/src/lib/types/view-mode.type.ts index ad38adb0a..4222deb13 100644 --- a/libs/common/src/lib/types/view-mode.type.ts +++ b/libs/common/src/lib/types/view-mode.type.ts @@ -1 +1,2 @@ export type ViewMode = 'DEFAULT' | 'ZEN'; +export type UnknownMode = 'DEFAULT' | 'OFF'; diff --git a/prisma/migrations/20230212232240_added_unknown_mode/migration.sql b/prisma/migrations/20230212232240_added_unknown_mode/migration.sql new file mode 100644 index 000000000..5de1899b0 --- /dev/null +++ b/prisma/migrations/20230212232240_added_unknown_mode/migration.sql @@ -0,0 +1,2 @@ +-- CreateEnum +CREATE TYPE "UnknownMode" AS ENUM ('DEFAULT', 'OFF'); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index ae5f29dee..86659bb4b 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -218,6 +218,11 @@ enum ViewMode { ZEN } +enum UnknownMode { + DEFAULT + OFF +} + enum Provider { ANONYMOUS GOOGLE From e0a8a8ff27976356f37cdd8890081f9f53093fad Mon Sep 17 00:00:00 2001 From: Agustin Alexander Date: Sun, 12 Feb 2023 20:57:05 -0300 Subject: [PATCH 3/9] Unlinted and added env file --- .env | 3 ++ .../yahoo-finance/yahoo-finance.service.ts | 45 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.env b/.env index 4f6dc7cd1..27ee6064d 100644 --- a/.env +++ b/.env @@ -14,3 +14,6 @@ ACCESS_TOKEN_SALT= ALPHA_VANTAGE_API_KEY= DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?sslmode=prefer JWT_SECRET_KEY= + +# If TZ different than US change it so that Yahoo finance query does not fail +# TZ='America/New_York' 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 9f09c8570..d994ac1b1 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,15 +1,15 @@ -import {LookupItem} from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; -import {ConfigurationService} from '@ghostfolio/api/services/configuration.service'; -import {CryptocurrencyService} from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.service'; -import {DataProviderInterface} from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface'; +import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; +import { ConfigurationService } from '@ghostfolio/api/services/configuration.service'; +import { CryptocurrencyService } from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.service'; +import { DataProviderInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface'; import { IDataProviderHistoricalResponse, IDataProviderResponse } from '@ghostfolio/api/services/interfaces/interfaces'; -import {UNKNOWN_KEY} from '@ghostfolio/common/config'; -import {DATE_FORMAT, isCurrency} from '@ghostfolio/common/helper'; -import {Granularity} from '@ghostfolio/common/types'; -import {Injectable, Logger} from '@nestjs/common'; +import { UNKNOWN_KEY } from '@ghostfolio/common/config'; +import { DATE_FORMAT, isCurrency } from '@ghostfolio/common/helper'; +import { Granularity } from '@ghostfolio/common/types'; +import { Injectable, Logger } from '@nestjs/common'; import { AssetClass, AssetSubClass, @@ -17,10 +17,10 @@ import { SymbolProfile } from '@prisma/client'; import Big from 'big.js'; -import {countries} from 'countries-list'; -import {addDays, format, isSameDay} from 'date-fns'; +import { countries } from 'countries-list'; +import { addDays, format, isSameDay } from 'date-fns'; import yahooFinance from 'yahoo-finance2'; -import type {Price} from 'yahoo-finance2/dist/esm/src/modules/quoteSummary-iface'; +import type { Price } from 'yahoo-finance2/dist/esm/src/modules/quoteSummary-iface'; @Injectable() export class YahooFinanceService implements DataProviderInterface { @@ -101,7 +101,7 @@ export class YahooFinanceService implements DataProviderInterface { modules: ['price', 'summaryProfile', 'topHoldings'] }); - const {assetClass, assetSubClass} = this.parseAssetClass( + const { assetClass, assetSubClass } = this.parseAssetClass( assetProfile.price ); @@ -123,7 +123,7 @@ export class YahooFinanceService implements DataProviderInterface { for (const sectorWeighting of assetProfile.topHoldings ?.sectorWeightings ?? []) { for (const [sector, weight] of Object.entries(sectorWeighting)) { - response.sectors.push({weight, name: this.parseSector(sector)}); + response.sectors.push({ weight, name: this.parseSector(sector) }); } } } else if ( @@ -138,14 +138,13 @@ export class YahooFinanceService implements DataProviderInterface { }); if (code) { - response.countries = [{code, weight: 1}]; + response.countries = [{ code, weight: 1 }]; } - } catch { - } + } catch {} if (assetProfile.summaryProfile?.sector) { response.sectors = [ - {name: assetProfile.summaryProfile?.sector, weight: 1} + { name: assetProfile.summaryProfile?.sector, weight: 1 } ]; } } @@ -369,7 +368,7 @@ export class YahooFinanceService implements DataProviderInterface { // Filter out undefined symbols return quote.symbol; }) - .filter(({quoteType, symbol}) => { + .filter(({ quoteType, symbol }) => { return ( (quoteType === 'CRYPTOCURRENCY' && this.cryptocurrencyService.isCryptocurrency( @@ -381,7 +380,7 @@ export class YahooFinanceService implements DataProviderInterface { ['EQUITY', 'ETF', 'FUTURE', 'MUTUALFUND'].includes(quoteType) ); }) - .filter(({quoteType, symbol}) => { + .filter(({ quoteType, symbol }) => { if (quoteType === 'CRYPTOCURRENCY') { // Only allow cryptocurrencies in base currency to avoid having redundancy in the database. // Transactions need to be converted manually to the base currency before @@ -395,7 +394,7 @@ export class YahooFinanceService implements DataProviderInterface { }); const marketData = await yahooFinance.quote( - quotes.map(({symbol}) => { + quotes.map(({ symbol }) => { return symbol; }) ); @@ -425,7 +424,7 @@ export class YahooFinanceService implements DataProviderInterface { Logger.error(error, 'YahooFinanceService'); } - return {items}; + return { items }; } private formatName({ @@ -523,7 +522,7 @@ export class YahooFinanceService implements DataProviderInterface { break; } - return {assetClass, assetSubClass}; + return { assetClass, assetSubClass }; } private parseSector(aString: string): string { @@ -563,8 +562,6 @@ export class YahooFinanceService implements DataProviderInterface { case 'utilities': sector = 'Utilities'; break; - default: - sector = aString; } return sector; From d4b84402e2ac2bb14cbdb58c784e7b6633896b9d Mon Sep 17 00:00:00 2001 From: Agustin Alexander Date: Sun, 12 Feb 2023 21:00:04 -0300 Subject: [PATCH 4/9] Update yahoo-finance.service.ts --- .../yahoo-finance/yahoo-finance.service.ts | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) 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 d994ac1b1..3e56a9eba 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 @@ -161,11 +161,11 @@ export class YahooFinanceService implements DataProviderInterface { } public async getDividends({ - from, - granularity = 'day', - symbol, - to - }: { + from, + granularity = 'day', + symbol, + to + }: { from: Date; granularity: Granularity; symbol: string; @@ -428,11 +428,11 @@ export class YahooFinanceService implements DataProviderInterface { } private formatName({ - longName, - quoteType, - shortName, - symbol - }: { + longName, + quoteType, + shortName, + symbol + }: { longName: Price['longName']; quoteType: Price['quoteType']; shortName: Price['shortName']; @@ -462,9 +462,9 @@ export class YahooFinanceService implements DataProviderInterface { } private getConvertedValue({ - symbol, - value - }: { + symbol, + value + }: { symbol: string; value: number; }) { From f62b1f53732f1ef0a1c42fc4c12e4078169c9479 Mon Sep 17 00:00:00 2001 From: Agustin Alexander Date: Sun, 12 Feb 2023 21:13:30 -0300 Subject: [PATCH 5/9] Reverted cash setting to other --- apps/api/src/app/portfolio/portfolio.service.ts | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 6e34525d8..98b2698e0 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -1271,25 +1271,10 @@ export class PortfolioService { cashPositions[symbol].allocationInPercentage = value.gt(0) ? new Big(cashPositions[symbol].value).div(value).toNumber() : 0; - cashPositions[symbol].sectors = [ { - "name": "OTHER", - "weight": 1 - }] - cashPositions[symbol].countries = this.matchCurrencyToCountries(symbol) } return cashPositions; } - private matchCurrencyToCountries(aString: string): Country[] { - const csformat = [] - switch (aString) { - case 'USD': - csformat.push(countries.US) - break; - } - return csformat; - } - private getDividend({ activities, date = new Date(0), From fcb5dcae3cde17e98917e8e2f2f91c036ab36be1 Mon Sep 17 00:00:00 2001 From: Agustin Alexander Date: Sun, 12 Feb 2023 21:14:58 -0300 Subject: [PATCH 6/9] Update portfolio.service.ts --- apps/api/src/app/portfolio/portfolio.service.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 98b2698e0..03ce4831c 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -85,8 +85,6 @@ import { } from './interfaces/portfolio-position-detail.interface'; import { PortfolioCalculator } from './portfolio-calculator'; import { RulesService } from './rules.service'; -import {countries} from "countries-list"; -import {Country} from "@ghostfolio/common/interfaces/country.interface"; const developedMarkets = require('../../assets/countries/developed-markets.json'); const emergingMarkets = require('../../assets/countries/emerging-markets.json'); From 3505af68961033277906a2d873f75934975d4769 Mon Sep 17 00:00:00 2001 From: Agustin Alexander Date: Sun, 12 Feb 2023 21:15:34 -0300 Subject: [PATCH 7/9] Update portfolio.service.ts --- apps/api/src/app/portfolio/portfolio.service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 03ce4831c..fac99ca9d 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -1273,6 +1273,7 @@ export class PortfolioService { return cashPositions; } + private getDividend({ activities, date = new Date(0), From b10767a13b3e3ce3ce9f2fb05d07c004d5e355ab Mon Sep 17 00:00:00 2001 From: Agustin Alexander Date: Sun, 12 Feb 2023 21:24:41 -0300 Subject: [PATCH 8/9] Update portfolio.service.ts --- apps/api/src/app/portfolio/portfolio.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index fac99ca9d..6700eda99 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -462,7 +462,7 @@ export class PortfolioService { }); const holdings: PortfolioDetails['holdings'] = {}; - currentPositions.totalInvestment.plus( + const totalInvestmentInBaseCurrency = currentPositions.totalInvestment.plus( cashDetails.balanceInBaseCurrency ); let filteredValueInBaseCurrency = currentPositions.currentValue; @@ -1273,7 +1273,7 @@ export class PortfolioService { return cashPositions; } - + private getDividend({ activities, date = new Date(0), From 60f84fb1ca56fe93c4b292b6765d62e81f6c714f Mon Sep 17 00:00:00 2001 From: Agustin Alexander Date: Thu, 2 Mar 2023 10:32:48 -0300 Subject: [PATCH 9/9] Update .env --- .env | 3 --- 1 file changed, 3 deletions(-) diff --git a/.env b/.env index 27ee6064d..4f6dc7cd1 100644 --- a/.env +++ b/.env @@ -14,6 +14,3 @@ ACCESS_TOKEN_SALT= ALPHA_VANTAGE_API_KEY= DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?sslmode=prefer JWT_SECRET_KEY= - -# If TZ different than US change it so that Yahoo finance query does not fail -# TZ='America/New_York'