Feature/improve investments by sector (#172)
* Improve investments analysis by sector * Update changelog
This commit is contained in:
parent
198eaf57d3
commit
0264b592b9
@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Improved the pie chart: Investments by sector
|
||||||
|
|
||||||
## 1.17.0 - 15.06.2021
|
## 1.17.0 - 15.06.2021
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
UserWithSettings
|
UserWithSettings
|
||||||
} from '@ghostfolio/common/interfaces';
|
} from '@ghostfolio/common/interfaces';
|
||||||
import { Country } from '@ghostfolio/common/interfaces/country.interface';
|
import { Country } from '@ghostfolio/common/interfaces/country.interface';
|
||||||
|
import { Sector } from '@ghostfolio/common/interfaces/sector.interface';
|
||||||
import { DateRange, OrderWithAccount } from '@ghostfolio/common/types';
|
import { DateRange, OrderWithAccount } from '@ghostfolio/common/types';
|
||||||
import { Prisma } from '@prisma/client';
|
import { Prisma } from '@prisma/client';
|
||||||
import { continents, countries } from 'countries-list';
|
import { continents, countries } from 'countries-list';
|
||||||
@ -210,6 +211,7 @@ export class Portfolio implements PortfolioInterface {
|
|||||||
symbols.forEach((symbol) => {
|
symbols.forEach((symbol) => {
|
||||||
const accounts: PortfolioPosition['accounts'] = {};
|
const accounts: PortfolioPosition['accounts'] = {};
|
||||||
let countriesOfSymbol: Country[];
|
let countriesOfSymbol: Country[];
|
||||||
|
let sectorsOfSymbol: Sector[];
|
||||||
const [portfolioItem] = portfolioItems;
|
const [portfolioItem] = portfolioItems;
|
||||||
|
|
||||||
const ordersBySymbol = this.getOrders().filter((order) => {
|
const ordersBySymbol = this.getOrders().filter((order) => {
|
||||||
@ -264,6 +266,17 @@ export class Portfolio implements PortfolioInterface {
|
|||||||
weight: weight as number
|
weight: weight as number
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sectorsOfSymbol = (
|
||||||
|
(orderOfSymbol.getSymbolProfile()?.sectors as Prisma.JsonArray) ?? []
|
||||||
|
).map((sector) => {
|
||||||
|
const { name, weight } = sector as Prisma.JsonObject;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: (name as string) ?? UNKNOWN_KEY,
|
||||||
|
weight: weight as number
|
||||||
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let now = portfolioItemsNow.positions[symbol].marketPrice;
|
let now = portfolioItemsNow.positions[symbol].marketPrice;
|
||||||
@ -318,6 +331,7 @@ export class Portfolio implements PortfolioInterface {
|
|||||||
grossPerformancePercent: roundTo((now - before) / before, 4),
|
grossPerformancePercent: roundTo((now - before) / before, 4),
|
||||||
investment: portfolioItem.positions[symbol].investment,
|
investment: portfolioItem.positions[symbol].investment,
|
||||||
quantity: portfolioItem.positions[symbol].quantity,
|
quantity: portfolioItem.positions[symbol].quantity,
|
||||||
|
sectors: sectorsOfSymbol,
|
||||||
transactionCount: portfolioItem.positions[symbol].transactionCount,
|
transactionCount: portfolioItem.positions[symbol].transactionCount,
|
||||||
value: this.exchangeRateDataService.toCurrency(
|
value: this.exchangeRateDataService.toCurrency(
|
||||||
portfolioItem.positions[symbol].quantity * now,
|
portfolioItem.positions[symbol].quantity * now,
|
||||||
|
@ -12,9 +12,7 @@ import { DataProviderInterface } from '../../interfaces/data-provider.interface'
|
|||||||
import {
|
import {
|
||||||
IDataProviderHistoricalResponse,
|
IDataProviderHistoricalResponse,
|
||||||
IDataProviderResponse,
|
IDataProviderResponse,
|
||||||
Industry,
|
|
||||||
MarketState,
|
MarketState,
|
||||||
Sector,
|
|
||||||
Type
|
Type
|
||||||
} from '../../interfaces/interfaces';
|
} from '../../interfaces/interfaces';
|
||||||
import {
|
import {
|
||||||
@ -70,16 +68,6 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
type: this.parseType(this.getType(symbol, value))
|
type: this.parseType(this.getType(symbol, value))
|
||||||
};
|
};
|
||||||
|
|
||||||
const industry = this.parseIndustry(value.summaryProfile?.industry);
|
|
||||||
if (industry) {
|
|
||||||
response[symbol].industry = industry;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sector = this.parseSector(value.summaryProfile?.sector);
|
|
||||||
if (sector) {
|
|
||||||
response[symbol].sector = sector;
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = value.summaryProfile?.website;
|
const url = value.summaryProfile?.website;
|
||||||
if (url) {
|
if (url) {
|
||||||
response[symbol].url = url;
|
response[symbol].url = url;
|
||||||
@ -228,55 +216,6 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
return aString;
|
return aString;
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseIndustry(aString: string): Industry {
|
|
||||||
if (aString === undefined) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aString?.toLowerCase() === 'auto manufacturers') {
|
|
||||||
return Industry.Automotive;
|
|
||||||
} else if (aString?.toLowerCase() === 'biotechnology') {
|
|
||||||
return Industry.Biotechnology;
|
|
||||||
} else if (
|
|
||||||
aString?.toLowerCase() === 'drug manufacturers—specialty & generic'
|
|
||||||
) {
|
|
||||||
return Industry.Pharmaceutical;
|
|
||||||
} else if (
|
|
||||||
aString?.toLowerCase() === 'internet content & information' ||
|
|
||||||
aString?.toLowerCase() === 'internet retail'
|
|
||||||
) {
|
|
||||||
return Industry.Internet;
|
|
||||||
} else if (aString?.toLowerCase() === 'packaged foods') {
|
|
||||||
return Industry.Food;
|
|
||||||
} else if (aString?.toLowerCase() === 'software—application') {
|
|
||||||
return Industry.Software;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Industry.Unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
private parseSector(aString: string): Sector {
|
|
||||||
if (aString === undefined) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
aString?.toLowerCase() === 'consumer cyclical' ||
|
|
||||||
aString?.toLowerCase() === 'consumer defensive'
|
|
||||||
) {
|
|
||||||
return Sector.Consumer;
|
|
||||||
} else if (aString?.toLowerCase() === 'healthcare') {
|
|
||||||
return Sector.Healthcare;
|
|
||||||
} else if (
|
|
||||||
aString?.toLowerCase() === 'communication services' ||
|
|
||||||
aString?.toLowerCase() === 'technology'
|
|
||||||
) {
|
|
||||||
return Sector.Technology;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Sector.Unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
private parseType(aString: string): Type {
|
private parseType(aString: string): Type {
|
||||||
if (aString?.toLowerCase() === 'cryptocurrency') {
|
if (aString?.toLowerCase() === 'cryptocurrency') {
|
||||||
return Type.Cryptocurrency;
|
return Type.Cryptocurrency;
|
||||||
@ -291,6 +230,6 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const convertFromYahooSymbol = (aSymbol: string) => {
|
export const convertFromYahooSymbol = (aSymbol: string) => {
|
||||||
let symbol = aSymbol.replace('-', '');
|
const symbol = aSymbol.replace('-', '');
|
||||||
return symbol.replace('=X', '');
|
return symbol.replace('=X', '');
|
||||||
};
|
};
|
||||||
|
@ -3,29 +3,12 @@ import { Account, Currency, DataSource, SymbolProfile } from '@prisma/client';
|
|||||||
|
|
||||||
import { OrderType } from '../../models/order-type';
|
import { OrderType } from '../../models/order-type';
|
||||||
|
|
||||||
export const Industry = {
|
|
||||||
Automotive: 'Automotive',
|
|
||||||
Biotechnology: 'Biotechnology',
|
|
||||||
Food: 'Food',
|
|
||||||
Internet: 'Internet',
|
|
||||||
Pharmaceutical: 'Pharmaceutical',
|
|
||||||
Software: 'Software',
|
|
||||||
Unknown: UNKNOWN_KEY
|
|
||||||
};
|
|
||||||
|
|
||||||
export const MarketState = {
|
export const MarketState = {
|
||||||
closed: 'closed',
|
closed: 'closed',
|
||||||
delayed: 'delayed',
|
delayed: 'delayed',
|
||||||
open: 'open'
|
open: 'open'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Sector = {
|
|
||||||
Consumer: 'Consumer',
|
|
||||||
Healthcare: 'Healthcare',
|
|
||||||
Technology: 'Technology',
|
|
||||||
Unknown: UNKNOWN_KEY
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Type = {
|
export const Type = {
|
||||||
Cryptocurrency: 'Cryptocurrency',
|
Cryptocurrency: 'Cryptocurrency',
|
||||||
ETF: 'ETF',
|
ETF: 'ETF',
|
||||||
@ -55,13 +38,11 @@ export interface IDataProviderResponse {
|
|||||||
currency: Currency;
|
currency: Currency;
|
||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
exchange?: string;
|
exchange?: string;
|
||||||
industry?: Industry;
|
|
||||||
marketChange?: number;
|
marketChange?: number;
|
||||||
marketChangePercent?: number;
|
marketChangePercent?: number;
|
||||||
marketPrice: number;
|
marketPrice: number;
|
||||||
marketState: MarketState;
|
marketState: MarketState;
|
||||||
name: string;
|
name: string;
|
||||||
sector?: Sector;
|
|
||||||
type?: Type;
|
type?: Type;
|
||||||
url?: string;
|
url?: string;
|
||||||
}
|
}
|
||||||
@ -72,10 +53,6 @@ export interface IDataGatheringItem {
|
|||||||
symbol: string;
|
symbol: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Industry = typeof Industry[keyof typeof Industry];
|
|
||||||
|
|
||||||
export type MarketState = typeof MarketState[keyof typeof MarketState];
|
export type MarketState = typeof MarketState[keyof typeof MarketState];
|
||||||
|
|
||||||
export type Sector = typeof Sector[keyof typeof Sector];
|
|
||||||
|
|
||||||
export type Type = typeof Type[keyof typeof Type];
|
export type Type = typeof Type[keyof typeof Type];
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
PortfolioPosition,
|
PortfolioPosition,
|
||||||
User
|
User
|
||||||
} from '@ghostfolio/common/interfaces';
|
} from '@ghostfolio/common/interfaces';
|
||||||
|
import { Sector } from '@ghostfolio/common/interfaces/sector.interface';
|
||||||
import { DeviceDetectorService } from 'ngx-device-detector';
|
import { DeviceDetectorService } from 'ngx-device-detector';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
@ -39,6 +40,9 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
|
|||||||
public portfolioPositions: { [symbol: string]: PortfolioPosition };
|
public portfolioPositions: { [symbol: string]: PortfolioPosition };
|
||||||
public positions: { [symbol: string]: any };
|
public positions: { [symbol: string]: any };
|
||||||
public positionsArray: PortfolioPosition[];
|
public positionsArray: PortfolioPosition[];
|
||||||
|
public sectors: {
|
||||||
|
[name: string]: { name: string; value: number };
|
||||||
|
};
|
||||||
public user: User;
|
public user: User;
|
||||||
|
|
||||||
private unsubscribeSubject = new Subject<void>();
|
private unsubscribeSubject = new Subject<void>();
|
||||||
@ -118,13 +122,17 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
|
|||||||
};
|
};
|
||||||
this.positions = {};
|
this.positions = {};
|
||||||
this.positionsArray = [];
|
this.positionsArray = [];
|
||||||
|
this.sectors = {
|
||||||
|
[UNKNOWN_KEY]: {
|
||||||
|
name: UNKNOWN_KEY,
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
for (const [symbol, position] of Object.entries(aPortfolioPositions)) {
|
for (const [symbol, position] of Object.entries(aPortfolioPositions)) {
|
||||||
this.positions[symbol] = {
|
this.positions[symbol] = {
|
||||||
currency: position.currency,
|
currency: position.currency,
|
||||||
exchange: position.exchange,
|
exchange: position.exchange,
|
||||||
industry: position.industry,
|
|
||||||
sector: position.sector,
|
|
||||||
type: position.type,
|
type: position.type,
|
||||||
value:
|
value:
|
||||||
aPeriod === 'original'
|
aPeriod === 'original'
|
||||||
@ -188,6 +196,30 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
|
|||||||
? this.portfolioPositions[symbol].investment
|
? this.portfolioPositions[symbol].investment
|
||||||
: this.portfolioPositions[symbol].value;
|
: this.portfolioPositions[symbol].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (position.sectors.length > 0) {
|
||||||
|
for (const sector of position.sectors) {
|
||||||
|
const { name, weight } = sector;
|
||||||
|
|
||||||
|
if (this.sectors[name]?.value) {
|
||||||
|
this.sectors[name].value += weight * position.value;
|
||||||
|
} else {
|
||||||
|
this.sectors[name] = {
|
||||||
|
name,
|
||||||
|
value:
|
||||||
|
weight *
|
||||||
|
(aPeriod === 'original'
|
||||||
|
? this.portfolioPositions[symbol].investment
|
||||||
|
: this.portfolioPositions[symbol].value)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.sectors[UNKNOWN_KEY].value +=
|
||||||
|
aPeriod === 'original'
|
||||||
|
? this.portfolioPositions[symbol].investment
|
||||||
|
: this.portfolioPositions[symbol].value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,52 +58,6 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
|
||||||
<mat-card class="mb-3">
|
|
||||||
<mat-card-header class="w-100">
|
|
||||||
<mat-card-title i18n>By Sector</mat-card-title>
|
|
||||||
<gf-toggle
|
|
||||||
[defaultValue]="period"
|
|
||||||
[isLoading]="false"
|
|
||||||
[options]="periodOptions"
|
|
||||||
(change)="onChangePeriod($event.value)"
|
|
||||||
></gf-toggle>
|
|
||||||
</mat-card-header>
|
|
||||||
<mat-card-content>
|
|
||||||
<gf-portfolio-proportion-chart
|
|
||||||
key="sector"
|
|
||||||
[baseCurrency]="user?.settings?.baseCurrency"
|
|
||||||
[isInPercent]="true"
|
|
||||||
[locale]="user?.settings?.locale"
|
|
||||||
[maxItems]="10"
|
|
||||||
[positions]="positions"
|
|
||||||
></gf-portfolio-proportion-chart>
|
|
||||||
</mat-card-content>
|
|
||||||
</mat-card>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<mat-card class="mb-3">
|
|
||||||
<mat-card-header class="w-100">
|
|
||||||
<mat-card-title i18n>By Industry</mat-card-title>
|
|
||||||
<gf-toggle
|
|
||||||
[defaultValue]="period"
|
|
||||||
[isLoading]="false"
|
|
||||||
[options]="periodOptions"
|
|
||||||
(change)="onChangePeriod($event.value)"
|
|
||||||
></gf-toggle>
|
|
||||||
</mat-card-header>
|
|
||||||
<mat-card-content>
|
|
||||||
<gf-portfolio-proportion-chart
|
|
||||||
key="industry"
|
|
||||||
[baseCurrency]="user?.settings?.baseCurrency"
|
|
||||||
[isInPercent]="true"
|
|
||||||
[locale]="user?.settings?.locale"
|
|
||||||
[maxItems]="10"
|
|
||||||
[positions]="positions"
|
|
||||||
></gf-portfolio-proportion-chart>
|
|
||||||
</mat-card-content>
|
|
||||||
</mat-card>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<mat-card class="mb-3">
|
<mat-card class="mb-3">
|
||||||
<mat-card-header class="w-100">
|
<mat-card-header class="w-100">
|
||||||
@ -148,6 +102,29 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<mat-card class="mb-3">
|
||||||
|
<mat-card-header class="w-100">
|
||||||
|
<mat-card-title i18n>By Sector</mat-card-title>
|
||||||
|
<gf-toggle
|
||||||
|
[defaultValue]="period"
|
||||||
|
[isLoading]="false"
|
||||||
|
[options]="periodOptions"
|
||||||
|
(change)="onChangePeriod($event.value)"
|
||||||
|
></gf-toggle>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<gf-portfolio-proportion-chart
|
||||||
|
key="name"
|
||||||
|
[baseCurrency]="user?.settings?.baseCurrency"
|
||||||
|
[isInPercent]="false"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
|
[maxItems]="10"
|
||||||
|
[positions]="sectors"
|
||||||
|
></gf-portfolio-proportion-chart>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<mat-card class="mb-3">
|
<mat-card class="mb-3">
|
||||||
<mat-card-header class="w-100">
|
<mat-card-header class="w-100">
|
||||||
|
@ -2,6 +2,7 @@ import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces';
|
|||||||
import { Currency } from '@prisma/client';
|
import { Currency } from '@prisma/client';
|
||||||
|
|
||||||
import { Country } from './country.interface';
|
import { Country } from './country.interface';
|
||||||
|
import { Sector } from './sector.interface';
|
||||||
|
|
||||||
export interface PortfolioPosition {
|
export interface PortfolioPosition {
|
||||||
accounts: {
|
accounts: {
|
||||||
@ -14,7 +15,6 @@ export interface PortfolioPosition {
|
|||||||
exchange?: string;
|
exchange?: string;
|
||||||
grossPerformance: number;
|
grossPerformance: number;
|
||||||
grossPerformancePercent: number;
|
grossPerformancePercent: number;
|
||||||
industry?: string;
|
|
||||||
investment: number;
|
investment: number;
|
||||||
marketChange?: number;
|
marketChange?: number;
|
||||||
marketChangePercent?: number;
|
marketChangePercent?: number;
|
||||||
@ -22,7 +22,7 @@ export interface PortfolioPosition {
|
|||||||
marketState: MarketState;
|
marketState: MarketState;
|
||||||
name: string;
|
name: string;
|
||||||
quantity: number;
|
quantity: number;
|
||||||
sector?: string;
|
sectors: Sector[];
|
||||||
transactionCount: number;
|
transactionCount: number;
|
||||||
symbol: string;
|
symbol: string;
|
||||||
type?: string;
|
type?: string;
|
||||||
|
4
libs/common/src/lib/interfaces/sector.interface.ts
Normal file
4
libs/common/src/lib/interfaces/sector.interface.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export interface Sector {
|
||||||
|
name: string;
|
||||||
|
weight: number;
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "SymbolProfile" ADD COLUMN "sectors" JSONB;
|
@ -120,6 +120,7 @@ model SymbolProfile {
|
|||||||
name String?
|
name String?
|
||||||
Order Order[]
|
Order Order[]
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
sectors Json?
|
||||||
symbol String
|
symbol String
|
||||||
|
|
||||||
@@unique([dataSource, symbol])
|
@@unique([dataSource, symbol])
|
||||||
|
@ -142,18 +142,21 @@ async function main() {
|
|||||||
countries: [{ code: 'US', weight: 1 }],
|
countries: [{ code: 'US', weight: 1 }],
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
id: '2bd26362-136e-411c-b578-334084b4cdcc',
|
id: '2bd26362-136e-411c-b578-334084b4cdcc',
|
||||||
|
sectors: [{ name: 'Consumer Cyclical', weight: 1 }],
|
||||||
symbol: 'AMZN'
|
symbol: 'AMZN'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
countries: null,
|
countries: null,
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
id: 'fdc42ea6-1321-44f5-9fb0-d7f1f2cf9b1e',
|
id: 'fdc42ea6-1321-44f5-9fb0-d7f1f2cf9b1e',
|
||||||
|
sectors: null,
|
||||||
symbol: 'BTCUSD'
|
symbol: 'BTCUSD'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
countries: [{ code: 'US', weight: 1 }],
|
countries: [{ code: 'US', weight: 1 }],
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
id: 'd1ee9681-fb21-4f99-a3b7-afd4fc04df2e',
|
id: 'd1ee9681-fb21-4f99-a3b7-afd4fc04df2e',
|
||||||
|
sectors: [{ name: 'Consumer Cyclical', weight: 1 }],
|
||||||
symbol: 'TSLA'
|
symbol: 'TSLA'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -164,6 +167,21 @@ async function main() {
|
|||||||
],
|
],
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
id: '7d9c8540-061e-4e7e-b019-0d0f4a84e796',
|
id: '7d9c8540-061e-4e7e-b019-0d0f4a84e796',
|
||||||
|
sectors: [
|
||||||
|
{ name: 'Technology', weight: 0.31393799999999955 },
|
||||||
|
{ name: 'Consumer Cyclical', weight: 0.149224 },
|
||||||
|
{ name: 'Financials', weight: 0.11716100000000002 },
|
||||||
|
{ name: 'Healthcare', weight: 0.13285199999999994 },
|
||||||
|
{ name: 'Consumer Staples', weight: 0.053919000000000016 },
|
||||||
|
{ name: 'Energy', weight: 0.025529999999999997 },
|
||||||
|
{ name: 'Telecommunications', weight: 0.012579 },
|
||||||
|
{ name: 'Industrials', weight: 0.09526399999999995 },
|
||||||
|
{ name: 'Utilities', weight: 0.024791999999999988 },
|
||||||
|
{ name: 'Materials', weight: 0.027664 },
|
||||||
|
{ name: 'Real Estate', weight: 0.03239999999999998 },
|
||||||
|
{ name: 'Communication', weight: 0.0036139999999999996 },
|
||||||
|
{ name: 'Other', weight: 0.000218 }
|
||||||
|
],
|
||||||
symbol: 'VTI'
|
symbol: 'VTI'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user