Feature/support unlimited currencies (#387)
* Support unlimited currencies * Update changelog
This commit is contained in:
parent
508a48f4c3
commit
dcee651098
@ -15,12 +15,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Changed the navigation to always show the portfolio page
|
- Changed the navigation to always show the portfolio page
|
||||||
|
- Migrated the data type of currencies from `enum` to `string` in the database
|
||||||
|
- Supported unlimited currencies (instead of `CHF`, `EUR`, `GBP` and `USD`)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Hid the actions from the accounts table in the _Presenter View_
|
- Hid the actions from the accounts table in the _Presenter View_
|
||||||
- Hid the actions from the transactions table in the _Presenter View_
|
- Hid the actions from the transactions table in the _Presenter View_
|
||||||
|
|
||||||
|
### Todo
|
||||||
|
|
||||||
|
- Apply data migration (`yarn prisma migrate deploy`)
|
||||||
|
|
||||||
## 1.55.0 - 20.09.2021
|
## 1.55.0 - 20.09.2021
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||||
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { Account, Currency, Order, Platform, Prisma } from '@prisma/client';
|
import { Account, Order, Platform, Prisma } from '@prisma/client';
|
||||||
|
|
||||||
import { CashDetails } from './interfaces/cash-details.interface';
|
import { CashDetails } from './interfaces/cash-details.interface';
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ export class AccountService {
|
|||||||
|
|
||||||
public async getCashDetails(
|
public async getCashDetails(
|
||||||
aUserId: string,
|
aUserId: string,
|
||||||
aCurrency: Currency
|
aCurrency: string
|
||||||
): Promise<CashDetails> {
|
): Promise<CashDetails> {
|
||||||
let totalCashBalance = 0;
|
let totalCashBalance = 0;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { AccountType, Currency } from '@prisma/client';
|
import { AccountType } from '@prisma/client';
|
||||||
import { IsNumber, IsString, ValidateIf } from 'class-validator';
|
import { IsNumber, IsString, ValidateIf } from 'class-validator';
|
||||||
|
|
||||||
export class CreateAccountDto {
|
export class CreateAccountDto {
|
||||||
@ -9,7 +9,7 @@ export class CreateAccountDto {
|
|||||||
balance: number;
|
balance: number;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
currency: Currency;
|
currency: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { AccountType, Currency } from '@prisma/client';
|
import { AccountType } from '@prisma/client';
|
||||||
import { IsNumber, IsString, ValidateIf } from 'class-validator';
|
import { IsNumber, IsString, ValidateIf } from 'class-validator';
|
||||||
|
|
||||||
export class UpdateAccountDto {
|
export class UpdateAccountDto {
|
||||||
@ -9,7 +9,7 @@ export class UpdateAccountDto {
|
|||||||
balance: number;
|
balance: number;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
currency: Currency;
|
currency: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -3,9 +3,9 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration.ser
|
|||||||
import { DataGatheringService } from '@ghostfolio/api/services/data-gathering.service';
|
import { DataGatheringService } from '@ghostfolio/api/services/data-gathering.service';
|
||||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||||
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
||||||
|
import { baseCurrency } from '@ghostfolio/common/config';
|
||||||
import { AdminData } from '@ghostfolio/common/interfaces';
|
import { AdminData } from '@ghostfolio/common/interfaces';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
import { differenceInDays } from 'date-fns';
|
import { differenceInDays } from 'date-fns';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -20,53 +20,22 @@ export class AdminService {
|
|||||||
|
|
||||||
public async get(): Promise<AdminData> {
|
public async get(): Promise<AdminData> {
|
||||||
return {
|
return {
|
||||||
exchangeRates: [
|
exchangeRates: this.exchangeRateDataService
|
||||||
{
|
.getCurrencies()
|
||||||
label1: Currency.EUR,
|
.filter((currency) => {
|
||||||
label2: Currency.CHF,
|
return currency !== baseCurrency;
|
||||||
value: await this.exchangeRateDataService.toCurrency(
|
})
|
||||||
1,
|
.map((currency) => {
|
||||||
Currency.EUR,
|
return {
|
||||||
Currency.CHF
|
label1: baseCurrency,
|
||||||
)
|
label2: currency,
|
||||||
},
|
value: this.exchangeRateDataService.toCurrency(
|
||||||
{
|
1,
|
||||||
label1: Currency.GBP,
|
baseCurrency,
|
||||||
label2: Currency.CHF,
|
currency
|
||||||
value: await this.exchangeRateDataService.toCurrency(
|
)
|
||||||
1,
|
};
|
||||||
Currency.GBP,
|
}),
|
||||||
Currency.CHF
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label1: Currency.USD,
|
|
||||||
label2: Currency.CHF,
|
|
||||||
value: await this.exchangeRateDataService.toCurrency(
|
|
||||||
1,
|
|
||||||
Currency.USD,
|
|
||||||
Currency.CHF
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label1: Currency.USD,
|
|
||||||
label2: Currency.EUR,
|
|
||||||
value: await this.exchangeRateDataService.toCurrency(
|
|
||||||
1,
|
|
||||||
Currency.USD,
|
|
||||||
Currency.EUR
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label1: Currency.USD,
|
|
||||||
label2: Currency.GBP,
|
|
||||||
value: await this.exchangeRateDataService.toCurrency(
|
|
||||||
1,
|
|
||||||
Currency.USD,
|
|
||||||
Currency.GBP
|
|
||||||
)
|
|
||||||
}
|
|
||||||
],
|
|
||||||
lastDataGathering: await this.getLastDataGathering(),
|
lastDataGathering: await this.getLastDataGathering(),
|
||||||
transactionCount: await this.prismaService.order.count(),
|
transactionCount: await this.prismaService.order.count(),
|
||||||
userCount: await this.prismaService.user.count(),
|
userCount: await this.prismaService.user.count(),
|
||||||
|
3
apps/api/src/app/cache/cache.module.ts
vendored
3
apps/api/src/app/cache/cache.module.ts
vendored
@ -7,13 +7,14 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider/data
|
|||||||
import { GhostfolioScraperApiService } from '@ghostfolio/api/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service';
|
import { GhostfolioScraperApiService } from '@ghostfolio/api/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service';
|
||||||
import { RakutenRapidApiService } from '@ghostfolio/api/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service';
|
import { RakutenRapidApiService } from '@ghostfolio/api/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service';
|
||||||
import { YahooFinanceService } from '@ghostfolio/api/services/data-provider/yahoo-finance/yahoo-finance.service';
|
import { YahooFinanceService } from '@ghostfolio/api/services/data-provider/yahoo-finance/yahoo-finance.service';
|
||||||
|
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data.module';
|
||||||
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
import { CacheController } from './cache.controller';
|
import { CacheController } from './cache.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [RedisCacheModule],
|
imports: [ExchangeRateDataModule, RedisCacheModule],
|
||||||
controllers: [CacheController],
|
controllers: [CacheController],
|
||||||
providers: [
|
providers: [
|
||||||
AlphaVantageService,
|
AlphaVantageService,
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { Currency, Type } from '@prisma/client';
|
import { Type } from '@prisma/client';
|
||||||
import { IsISO8601, IsNumber, IsString, ValidateIf } from 'class-validator';
|
import { IsISO8601, IsNumber, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class CreateOrderDto {
|
export class CreateOrderDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
currency: Currency;
|
currency: string;
|
||||||
|
|
||||||
@IsISO8601()
|
@IsISO8601()
|
||||||
date: string;
|
date: string;
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { Currency } from '@prisma/client';
|
|
||||||
|
|
||||||
export interface Data {
|
export interface Data {
|
||||||
currency: Currency;
|
currency: string;
|
||||||
value: number;
|
value: number;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { CacheService } from '@ghostfolio/api/app/cache/cache.service';
|
|
||||||
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
|
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
|
||||||
import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module';
|
import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module';
|
||||||
import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering.module';
|
import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering.module';
|
||||||
@ -18,6 +17,6 @@ import { ExportService } from './export.service';
|
|||||||
RedisCacheModule
|
RedisCacheModule
|
||||||
],
|
],
|
||||||
controllers: [ExportController],
|
controllers: [ExportController],
|
||||||
providers: [CacheService, ExportService]
|
providers: [ExportService]
|
||||||
})
|
})
|
||||||
export class ExportModule {}
|
export class ExportModule {}
|
||||||
|
@ -5,6 +5,7 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider/data
|
|||||||
import { GhostfolioScraperApiService } from '@ghostfolio/api/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service';
|
import { GhostfolioScraperApiService } from '@ghostfolio/api/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service';
|
||||||
import { RakutenRapidApiService } from '@ghostfolio/api/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service';
|
import { RakutenRapidApiService } from '@ghostfolio/api/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service';
|
||||||
import { YahooFinanceService } from '@ghostfolio/api/services/data-provider/yahoo-finance/yahoo-finance.service';
|
import { YahooFinanceService } from '@ghostfolio/api/services/data-provider/yahoo-finance/yahoo-finance.service';
|
||||||
|
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data.module';
|
||||||
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { JwtModule } from '@nestjs/jwt';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
@ -14,6 +15,7 @@ import { InfoService } from './info.service';
|
|||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
ExchangeRateDataModule,
|
||||||
JwtModule.register({
|
JwtModule.register({
|
||||||
secret: process.env.JWT_SECRET_KEY,
|
secret: process.env.JWT_SECRET_KEY,
|
||||||
signOptions: { expiresIn: '30 days' }
|
signOptions: { expiresIn: '30 days' }
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
|
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
|
||||||
import { DataGatheringService } from '@ghostfolio/api/services/data-gathering.service';
|
import { DataGatheringService } from '@ghostfolio/api/services/data-gathering.service';
|
||||||
|
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||||
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
||||||
import { InfoItem } from '@ghostfolio/common/interfaces';
|
import { InfoItem } from '@ghostfolio/common/interfaces';
|
||||||
import { Subscription } from '@ghostfolio/common/interfaces/subscription.interface';
|
import { Subscription } from '@ghostfolio/common/interfaces/subscription.interface';
|
||||||
import { permissions } from '@ghostfolio/common/permissions';
|
import { permissions } from '@ghostfolio/common/permissions';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { JwtService } from '@nestjs/jwt';
|
import { JwtService } from '@nestjs/jwt';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
import * as bent from 'bent';
|
import * as bent from 'bent';
|
||||||
import { subDays } from 'date-fns';
|
import { subDays } from 'date-fns';
|
||||||
|
|
||||||
@ -16,6 +16,7 @@ export class InfoService {
|
|||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private readonly configurationService: ConfigurationService,
|
private readonly configurationService: ConfigurationService,
|
||||||
|
private readonly exchangeRateDataService: ExchangeRateDataService,
|
||||||
private readonly dataGatheringService: DataGatheringService,
|
private readonly dataGatheringService: DataGatheringService,
|
||||||
private readonly jwtService: JwtService,
|
private readonly jwtService: JwtService,
|
||||||
private readonly prismaService: PrismaService
|
private readonly prismaService: PrismaService
|
||||||
@ -56,7 +57,7 @@ export class InfoService {
|
|||||||
...info,
|
...info,
|
||||||
globalPermissions,
|
globalPermissions,
|
||||||
platforms,
|
platforms,
|
||||||
currencies: Object.values(Currency),
|
currencies: this.exchangeRateDataService.getCurrencies(),
|
||||||
demoAuthToken: this.getDemoAuthToken(),
|
demoAuthToken: this.getDemoAuthToken(),
|
||||||
lastDataGathering: await this.getLastDataGathering(),
|
lastDataGathering: await this.getLastDataGathering(),
|
||||||
statistics: await this.getStatistics(),
|
statistics: await this.getStatistics(),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Currency, DataSource, Type } from '@prisma/client';
|
import { DataSource, Type } from '@prisma/client';
|
||||||
import { IsISO8601, IsNumber, IsString } from 'class-validator';
|
import { IsISO8601, IsNumber, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class CreateOrderDto {
|
export class CreateOrderDto {
|
||||||
@ -6,7 +6,7 @@ export class CreateOrderDto {
|
|||||||
accountId: string;
|
accountId: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
currency: Currency;
|
currency: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { Currency, DataSource, Type } from '@prisma/client';
|
import { DataSource, Type } from '@prisma/client';
|
||||||
import { IsISO8601, IsNumber, IsString, ValidateIf } from 'class-validator';
|
import { IsISO8601, IsNumber, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class UpdateOrderDto {
|
export class UpdateOrderDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
accountId: string;
|
accountId: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
currency: Currency;
|
currency: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
|
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
|
||||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||||
import { Currency, DataSource, MarketData } from '@prisma/client';
|
import { DataSource, MarketData } from '@prisma/client';
|
||||||
|
|
||||||
import { CurrentRateService } from './current-rate.service';
|
import { CurrentRateService } from './current-rate.service';
|
||||||
import { MarketDataService } from './market-data.service';
|
import { MarketDataService } from './market-data.service';
|
||||||
@ -80,7 +80,7 @@ describe('CurrentRateService', () => {
|
|||||||
null,
|
null,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
exchangeRateDataService = new ExchangeRateDataService(null);
|
exchangeRateDataService = new ExchangeRateDataService(null, null);
|
||||||
marketDataService = new MarketDataService(null);
|
marketDataService = new MarketDataService(null);
|
||||||
|
|
||||||
await exchangeRateDataService.initialize();
|
await exchangeRateDataService.initialize();
|
||||||
@ -95,10 +95,10 @@ describe('CurrentRateService', () => {
|
|||||||
it('getValue', async () => {
|
it('getValue', async () => {
|
||||||
expect(
|
expect(
|
||||||
await currentRateService.getValue({
|
await currentRateService.getValue({
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
date: new Date(Date.UTC(2020, 0, 1, 0, 0, 0)),
|
date: new Date(Date.UTC(2020, 0, 1, 0, 0, 0)),
|
||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
userCurrency: Currency.CHF
|
userCurrency: 'CHF'
|
||||||
})
|
})
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
marketPrice: 1847.839966
|
marketPrice: 1847.839966
|
||||||
@ -108,13 +108,13 @@ describe('CurrentRateService', () => {
|
|||||||
it('getValues', async () => {
|
it('getValues', async () => {
|
||||||
expect(
|
expect(
|
||||||
await currentRateService.getValues({
|
await currentRateService.getValues({
|
||||||
currencies: { AMZN: Currency.USD },
|
currencies: { AMZN: 'USD' },
|
||||||
dataGatheringItems: [{ dataSource: DataSource.YAHOO, symbol: 'AMZN' }],
|
dataGatheringItems: [{ dataSource: DataSource.YAHOO, symbol: 'AMZN' }],
|
||||||
dateQuery: {
|
dateQuery: {
|
||||||
lt: new Date(Date.UTC(2020, 0, 2, 0, 0, 0)),
|
lt: new Date(Date.UTC(2020, 0, 2, 0, 0, 0)),
|
||||||
gte: new Date(Date.UTC(2020, 0, 1, 0, 0, 0))
|
gte: new Date(Date.UTC(2020, 0, 1, 0, 0, 0))
|
||||||
},
|
},
|
||||||
userCurrency: Currency.CHF
|
userCurrency: 'CHF'
|
||||||
})
|
})
|
||||||
).toMatchObject([
|
).toMatchObject([
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import { Currency } from '@prisma/client';
|
|
||||||
|
|
||||||
export interface GetValueParams {
|
export interface GetValueParams {
|
||||||
currency: Currency;
|
currency: string;
|
||||||
date: Date;
|
date: Date;
|
||||||
symbol: string;
|
symbol: string;
|
||||||
userCurrency: Currency;
|
userCurrency: string;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
|
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
|
|
||||||
import { DateQuery } from './date-query.interface';
|
import { DateQuery } from './date-query.interface';
|
||||||
|
|
||||||
export interface GetValuesParams {
|
export interface GetValuesParams {
|
||||||
currencies: { [symbol: string]: Currency };
|
currencies: { [symbol: string]: string };
|
||||||
dataGatheringItems: IDataGatheringItem[];
|
dataGatheringItems: IDataGatheringItem[];
|
||||||
dateQuery: DateQuery;
|
dateQuery: DateQuery;
|
||||||
userCurrency: Currency;
|
userCurrency: string;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { OrderType } from '@ghostfolio/api/models/order-type';
|
import { OrderType } from '@ghostfolio/api/models/order-type';
|
||||||
import { Currency, DataSource } from '@prisma/client';
|
import { DataSource } from '@prisma/client';
|
||||||
import Big from 'big.js';
|
import Big from 'big.js';
|
||||||
|
|
||||||
export interface PortfolioOrder {
|
export interface PortfolioOrder {
|
||||||
currency: Currency;
|
currency: string;
|
||||||
date: string;
|
date: string;
|
||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
fee: Big;
|
fee: Big;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import { Currency } from '@prisma/client';
|
|
||||||
|
|
||||||
export interface PortfolioPositionDetail {
|
export interface PortfolioPositionDetail {
|
||||||
averagePrice: number;
|
averagePrice: number;
|
||||||
currency: Currency;
|
currency: string;
|
||||||
firstBuyDate: string;
|
firstBuyDate: string;
|
||||||
grossPerformance: number;
|
grossPerformance: number;
|
||||||
grossPerformancePercent: number;
|
grossPerformancePercent: number;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Currency, DataSource } from '@prisma/client';
|
import { DataSource } from '@prisma/client';
|
||||||
import Big from 'big.js';
|
import Big from 'big.js';
|
||||||
|
|
||||||
export interface TransactionPointSymbol {
|
export interface TransactionPointSymbol {
|
||||||
currency: Currency;
|
currency: string;
|
||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
fee: Big;
|
fee: Big;
|
||||||
firstBuyDate: string;
|
firstBuyDate: string;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
|
|
||||||
import { OrderType } from '@ghostfolio/api/models/order-type';
|
import { OrderType } from '@ghostfolio/api/models/order-type';
|
||||||
import { parseDate, resetHours } from '@ghostfolio/common/helper';
|
import { parseDate, resetHours } from '@ghostfolio/common/helper';
|
||||||
import { Currency, DataSource } from '@prisma/client';
|
import { DataSource } from '@prisma/client';
|
||||||
import Big from 'big.js';
|
import Big from 'big.js';
|
||||||
import {
|
import {
|
||||||
addDays,
|
addDays,
|
||||||
@ -134,7 +133,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with orders of only one symbol', () => {
|
it('with orders of only one symbol', () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.computeTransactionPoints(ordersVTI);
|
portfolioCalculator.computeTransactionPoints(ordersVTI);
|
||||||
const portfolioItemsAtTransactionPoints =
|
const portfolioItemsAtTransactionPoints =
|
||||||
@ -148,7 +147,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with orders of only one symbol and a fee', () => {
|
it('with orders of only one symbol and a fee', () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
const orders: PortfolioOrder[] = [
|
const orders: PortfolioOrder[] = [
|
||||||
{
|
{
|
||||||
@ -158,7 +157,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
type: OrderType.Buy,
|
type: OrderType.Buy,
|
||||||
unitPrice: new Big('144.38'),
|
unitPrice: new Big('144.38'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big('5')
|
fee: new Big('5')
|
||||||
},
|
},
|
||||||
@ -169,7 +168,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
type: OrderType.Buy,
|
type: OrderType.Buy,
|
||||||
unitPrice: new Big('147.99'),
|
unitPrice: new Big('147.99'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big('10')
|
fee: new Big('10')
|
||||||
},
|
},
|
||||||
@ -180,7 +179,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
type: OrderType.Sell,
|
type: OrderType.Sell,
|
||||||
unitPrice: new Big('151.41'),
|
unitPrice: new Big('151.41'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big('5')
|
fee: new Big('5')
|
||||||
}
|
}
|
||||||
@ -198,7 +197,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('10'),
|
quantity: new Big('10'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('1443.8'),
|
investment: new Big('1443.8'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
transactionCount: 1,
|
transactionCount: 1,
|
||||||
fee: new Big('5')
|
fee: new Big('5')
|
||||||
@ -213,7 +212,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('20'),
|
quantity: new Big('20'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('2923.7'),
|
investment: new Big('2923.7'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
transactionCount: 2,
|
transactionCount: 2,
|
||||||
fee: new Big('15')
|
fee: new Big('15')
|
||||||
@ -228,7 +227,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('652.55'),
|
investment: new Big('652.55'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
transactionCount: 3,
|
transactionCount: 3,
|
||||||
fee: new Big('20')
|
fee: new Big('20')
|
||||||
@ -241,7 +240,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with orders of two different symbols and a fee', () => {
|
it('with orders of two different symbols and a fee', () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
const orders: PortfolioOrder[] = [
|
const orders: PortfolioOrder[] = [
|
||||||
{
|
{
|
||||||
@ -251,7 +250,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
type: OrderType.Buy,
|
type: OrderType.Buy,
|
||||||
unitPrice: new Big('144.38'),
|
unitPrice: new Big('144.38'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big('5')
|
fee: new Big('5')
|
||||||
},
|
},
|
||||||
@ -262,7 +261,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
symbol: 'VTX',
|
symbol: 'VTX',
|
||||||
type: OrderType.Buy,
|
type: OrderType.Buy,
|
||||||
unitPrice: new Big('147.99'),
|
unitPrice: new Big('147.99'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big('10')
|
fee: new Big('10')
|
||||||
},
|
},
|
||||||
@ -273,7 +272,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
type: OrderType.Sell,
|
type: OrderType.Sell,
|
||||||
unitPrice: new Big('151.41'),
|
unitPrice: new Big('151.41'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big('5')
|
fee: new Big('5')
|
||||||
}
|
}
|
||||||
@ -291,7 +290,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('10'),
|
quantity: new Big('10'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('1443.8'),
|
investment: new Big('1443.8'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
transactionCount: 1,
|
transactionCount: 1,
|
||||||
fee: new Big('5')
|
fee: new Big('5')
|
||||||
@ -306,7 +305,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('10'),
|
quantity: new Big('10'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('1443.8'),
|
investment: new Big('1443.8'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
transactionCount: 1,
|
transactionCount: 1,
|
||||||
fee: new Big('5')
|
fee: new Big('5')
|
||||||
@ -316,7 +315,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('10'),
|
quantity: new Big('10'),
|
||||||
symbol: 'VTX',
|
symbol: 'VTX',
|
||||||
investment: new Big('1479.9'),
|
investment: new Big('1479.9'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-08-03',
|
firstBuyDate: '2019-08-03',
|
||||||
transactionCount: 1,
|
transactionCount: 1,
|
||||||
fee: new Big('10')
|
fee: new Big('10')
|
||||||
@ -331,7 +330,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('686.75'),
|
investment: new Big('686.75'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
transactionCount: 2,
|
transactionCount: 2,
|
||||||
fee: new Big('10')
|
fee: new Big('10')
|
||||||
@ -341,7 +340,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('10'),
|
quantity: new Big('10'),
|
||||||
symbol: 'VTX',
|
symbol: 'VTX',
|
||||||
investment: new Big('1479.9'),
|
investment: new Big('1479.9'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-08-03',
|
firstBuyDate: '2019-08-03',
|
||||||
transactionCount: 1,
|
transactionCount: 1,
|
||||||
fee: new Big('10')
|
fee: new Big('10')
|
||||||
@ -355,7 +354,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
const orders: PortfolioOrder[] = [
|
const orders: PortfolioOrder[] = [
|
||||||
...ordersVTI,
|
...ordersVTI,
|
||||||
{
|
{
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
date: '2021-02-01',
|
date: '2021-02-01',
|
||||||
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
|
name: 'Vanguard Total Stock Market Index Fund ETF Shares',
|
||||||
@ -368,7 +367,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
];
|
];
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.computeTransactionPoints(orders);
|
portfolioCalculator.computeTransactionPoints(orders);
|
||||||
const portfolioItemsAtTransactionPoints =
|
const portfolioItemsAtTransactionPoints =
|
||||||
@ -379,7 +378,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
date: '2019-02-01',
|
date: '2019-02-01',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
investment: new Big('1443.8'),
|
investment: new Big('1443.8'),
|
||||||
@ -394,7 +393,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
date: '2019-08-03',
|
date: '2019-08-03',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
investment: new Big('2923.7'),
|
investment: new Big('2923.7'),
|
||||||
@ -409,7 +408,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
date: '2020-02-02',
|
date: '2020-02-02',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
investment: new Big('652.55'),
|
investment: new Big('652.55'),
|
||||||
@ -424,7 +423,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
date: '2021-02-01',
|
date: '2021-02-01',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
investment: new Big('6627.05'),
|
investment: new Big('6627.05'),
|
||||||
@ -439,7 +438,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
date: '2021-08-01',
|
date: '2021-08-01',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
investment: new Big('8403.95'),
|
investment: new Big('8403.95'),
|
||||||
@ -457,7 +456,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
const orders: PortfolioOrder[] = [
|
const orders: PortfolioOrder[] = [
|
||||||
...ordersVTI,
|
...ordersVTI,
|
||||||
{
|
{
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
date: '2019-09-01',
|
date: '2019-09-01',
|
||||||
name: 'Amazon.com, Inc.',
|
name: 'Amazon.com, Inc.',
|
||||||
@ -470,7 +469,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
];
|
];
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.computeTransactionPoints(orders);
|
portfolioCalculator.computeTransactionPoints(orders);
|
||||||
const portfolioItemsAtTransactionPoints =
|
const portfolioItemsAtTransactionPoints =
|
||||||
@ -485,7 +484,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('10'),
|
quantity: new Big('10'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('1443.8'),
|
investment: new Big('1443.8'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 1
|
transactionCount: 1
|
||||||
@ -500,7 +499,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('20'),
|
quantity: new Big('20'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('2923.7'),
|
investment: new Big('2923.7'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 2
|
transactionCount: 2
|
||||||
@ -515,7 +514,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
investment: new Big('10109.95'),
|
investment: new Big('10109.95'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-09-01',
|
firstBuyDate: '2019-09-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 1
|
transactionCount: 1
|
||||||
@ -525,7 +524,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('20'),
|
quantity: new Big('20'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('2923.7'),
|
investment: new Big('2923.7'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 2
|
transactionCount: 2
|
||||||
@ -540,7 +539,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
investment: new Big('10109.95'),
|
investment: new Big('10109.95'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-09-01',
|
firstBuyDate: '2019-09-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 1
|
transactionCount: 1
|
||||||
@ -550,7 +549,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('652.55'),
|
investment: new Big('652.55'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 3
|
transactionCount: 3
|
||||||
@ -565,7 +564,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
investment: new Big('10109.95'),
|
investment: new Big('10109.95'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-09-01',
|
firstBuyDate: '2019-09-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 1
|
transactionCount: 1
|
||||||
@ -575,7 +574,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('15'),
|
quantity: new Big('15'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('2684.05'),
|
investment: new Big('2684.05'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 4
|
transactionCount: 4
|
||||||
@ -590,7 +589,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
investment: new Big('10109.95'),
|
investment: new Big('10109.95'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-09-01',
|
firstBuyDate: '2019-09-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 1
|
transactionCount: 1
|
||||||
@ -600,7 +599,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('25'),
|
quantity: new Big('25'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('4460.95'),
|
investment: new Big('4460.95'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 5
|
transactionCount: 5
|
||||||
@ -620,7 +619,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
type: OrderType.Buy,
|
type: OrderType.Buy,
|
||||||
unitPrice: new Big('2021.99'),
|
unitPrice: new Big('2021.99'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big(0)
|
fee: new Big(0)
|
||||||
},
|
},
|
||||||
@ -631,14 +630,14 @@ describe('PortfolioCalculator', () => {
|
|||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
type: OrderType.Sell,
|
type: OrderType.Sell,
|
||||||
unitPrice: new Big('2412.23'),
|
unitPrice: new Big('2412.23'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big(0)
|
fee: new Big(0)
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.computeTransactionPoints(orders);
|
portfolioCalculator.computeTransactionPoints(orders);
|
||||||
const portfolioItemsAtTransactionPoints =
|
const portfolioItemsAtTransactionPoints =
|
||||||
@ -652,7 +651,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with mixed symbols', () => {
|
it('with mixed symbols', () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.computeTransactionPoints(ordersMixedSymbols);
|
portfolioCalculator.computeTransactionPoints(ordersMixedSymbols);
|
||||||
const portfolioItemsAtTransactionPoints =
|
const portfolioItemsAtTransactionPoints =
|
||||||
@ -667,7 +666,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('50'),
|
quantity: new Big('50'),
|
||||||
symbol: 'TSLA',
|
symbol: 'TSLA',
|
||||||
investment: new Big('2148.5'),
|
investment: new Big('2148.5'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2017-01-03',
|
firstBuyDate: '2017-01-03',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 1
|
transactionCount: 1
|
||||||
@ -682,7 +681,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('0.5614682'),
|
quantity: new Big('0.5614682'),
|
||||||
symbol: 'BTCUSD',
|
symbol: 'BTCUSD',
|
||||||
investment: new Big('1999.9999999999998659756'),
|
investment: new Big('1999.9999999999998659756'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2017-07-01',
|
firstBuyDate: '2017-07-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 1
|
transactionCount: 1
|
||||||
@ -692,7 +691,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('50'),
|
quantity: new Big('50'),
|
||||||
symbol: 'TSLA',
|
symbol: 'TSLA',
|
||||||
investment: new Big('2148.5'),
|
investment: new Big('2148.5'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2017-01-03',
|
firstBuyDate: '2017-01-03',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 1
|
transactionCount: 1
|
||||||
@ -707,7 +706,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
investment: new Big('10109.95'),
|
investment: new Big('10109.95'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2018-09-01',
|
firstBuyDate: '2018-09-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 1
|
transactionCount: 1
|
||||||
@ -717,7 +716,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('0.5614682'),
|
quantity: new Big('0.5614682'),
|
||||||
symbol: 'BTCUSD',
|
symbol: 'BTCUSD',
|
||||||
investment: new Big('1999.9999999999998659756'),
|
investment: new Big('1999.9999999999998659756'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2017-07-01',
|
firstBuyDate: '2017-07-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 1
|
transactionCount: 1
|
||||||
@ -727,7 +726,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('50'),
|
quantity: new Big('50'),
|
||||||
symbol: 'TSLA',
|
symbol: 'TSLA',
|
||||||
investment: new Big('2148.5'),
|
investment: new Big('2148.5'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
firstBuyDate: '2017-01-03',
|
firstBuyDate: '2017-01-03',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
transactionCount: 1
|
transactionCount: 1
|
||||||
@ -742,7 +741,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with single TSLA and early start', async () => {
|
it('with single TSLA and early start', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.setTransactionPoints(orderTslaTransactionPoint);
|
portfolioCalculator.setTransactionPoints(orderTslaTransactionPoint);
|
||||||
|
|
||||||
@ -782,7 +781,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with single TSLA and buy day start', async () => {
|
it('with single TSLA and buy day start', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.setTransactionPoints(orderTslaTransactionPoint);
|
portfolioCalculator.setTransactionPoints(orderTslaTransactionPoint);
|
||||||
|
|
||||||
@ -822,7 +821,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with single TSLA and late start', async () => {
|
it('with single TSLA and late start', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.setTransactionPoints(orderTslaTransactionPoint);
|
portfolioCalculator.setTransactionPoints(orderTslaTransactionPoint);
|
||||||
|
|
||||||
@ -862,7 +861,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with VTI only', async () => {
|
it('with VTI only', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints);
|
portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints);
|
||||||
|
|
||||||
@ -905,7 +904,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with buy and sell', async () => {
|
it('with buy and sell', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.setTransactionPoints(transactionPointsBuyAndSell);
|
portfolioCalculator.setTransactionPoints(transactionPointsBuyAndSell);
|
||||||
|
|
||||||
@ -959,7 +958,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with buy, sell, buy', async () => {
|
it('with buy, sell, buy', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.setTransactionPoints([
|
portfolioCalculator.setTransactionPoints([
|
||||||
{
|
{
|
||||||
@ -969,7 +968,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('805.9'),
|
investment: new Big('805.9'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-09-01',
|
firstBuyDate: '2019-09-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -984,7 +983,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('0'),
|
quantity: new Big('0'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('0'),
|
investment: new Big('0'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-09-01',
|
firstBuyDate: '2019-09-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -999,7 +998,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('1013.9'),
|
investment: new Big('1013.9'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-09-01',
|
firstBuyDate: '2019-09-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -1047,7 +1046,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with performance since Jan 1st, 2020', async () => {
|
it('with performance since Jan 1st, 2020', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
const transactionPoints: TransactionPoint[] = [
|
const transactionPoints: TransactionPoint[] = [
|
||||||
{
|
{
|
||||||
@ -1057,7 +1056,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('10'),
|
quantity: new Big('10'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('1443.8'),
|
investment: new Big('1443.8'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -1072,7 +1071,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('20'),
|
quantity: new Big('20'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('2923.7'),
|
investment: new Big('2923.7'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -1130,7 +1129,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with net performance since Jan 1st, 2020 - include fees', async () => {
|
it('with net performance since Jan 1st, 2020 - include fees', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
const transactionPoints: TransactionPoint[] = [
|
const transactionPoints: TransactionPoint[] = [
|
||||||
{
|
{
|
||||||
@ -1140,7 +1139,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('10'),
|
quantity: new Big('10'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('1443.8'),
|
investment: new Big('1443.8'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(50),
|
fee: new Big(50),
|
||||||
@ -1155,7 +1154,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('20'),
|
quantity: new Big('20'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('2923.7'),
|
investment: new Big('2923.7'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(100),
|
fee: new Big(100),
|
||||||
@ -1223,7 +1222,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with net performance since Feb 1st, 2019 - include fees', async () => {
|
it('with net performance since Feb 1st, 2019 - include fees', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
const transactionPoints: TransactionPoint[] = [
|
const transactionPoints: TransactionPoint[] = [
|
||||||
{
|
{
|
||||||
@ -1233,7 +1232,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('10'),
|
quantity: new Big('10'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('1443.8'),
|
investment: new Big('1443.8'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(50),
|
fee: new Big(50),
|
||||||
@ -1248,7 +1247,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('20'),
|
quantity: new Big('20'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('2923.7'),
|
investment: new Big('2923.7'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(100),
|
fee: new Big(100),
|
||||||
@ -1311,7 +1310,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with TWR example from Investopedia: Scenario 1', async () => {
|
it('with TWR example from Investopedia: Scenario 1', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.setTransactionPoints([
|
portfolioCalculator.setTransactionPoints([
|
||||||
{
|
{
|
||||||
@ -1321,7 +1320,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('1000000'), // 1 million
|
quantity: new Big('1000000'), // 1 million
|
||||||
symbol: 'MFA', // Mutual Fund A
|
symbol: 'MFA', // Mutual Fund A
|
||||||
investment: new Big('1000000'), // 1 million
|
investment: new Big('1000000'), // 1 million
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2010-12-31',
|
firstBuyDate: '2010-12-31',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -1336,7 +1335,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('1086022.689344541'), // 1,000,000 + 100,000 / 1.162484
|
quantity: new Big('1086022.689344541'), // 1,000,000 + 100,000 / 1.162484
|
||||||
symbol: 'MFA', // Mutual Fund A
|
symbol: 'MFA', // Mutual Fund A
|
||||||
investment: new Big('1100000'), // 1,000,000 + 100,000
|
investment: new Big('1100000'), // 1,000,000 + 100,000
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2010-12-31',
|
firstBuyDate: '2010-12-31',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -1388,7 +1387,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with example from chsoft.ch: Performance of a Combination of Investments', async () => {
|
it('with example from chsoft.ch: Performance of a Combination of Investments', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.CHF
|
'CHF'
|
||||||
);
|
);
|
||||||
portfolioCalculator.setTransactionPoints([
|
portfolioCalculator.setTransactionPoints([
|
||||||
{
|
{
|
||||||
@ -1398,7 +1397,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('200'),
|
quantity: new Big('200'),
|
||||||
symbol: 'SPA', // Sub Portfolio A
|
symbol: 'SPA', // Sub Portfolio A
|
||||||
investment: new Big('200'),
|
investment: new Big('200'),
|
||||||
currency: Currency.CHF,
|
currency: 'CHF',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2012-12-31',
|
firstBuyDate: '2012-12-31',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -1408,7 +1407,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('300'),
|
quantity: new Big('300'),
|
||||||
symbol: 'SPB', // Sub Portfolio B
|
symbol: 'SPB', // Sub Portfolio B
|
||||||
investment: new Big('300'),
|
investment: new Big('300'),
|
||||||
currency: Currency.CHF,
|
currency: 'CHF',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2012-12-31',
|
firstBuyDate: '2012-12-31',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -1423,7 +1422,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('200'),
|
quantity: new Big('200'),
|
||||||
symbol: 'SPA', // Sub Portfolio A
|
symbol: 'SPA', // Sub Portfolio A
|
||||||
investment: new Big('200'),
|
investment: new Big('200'),
|
||||||
currency: Currency.CHF,
|
currency: 'CHF',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2012-12-31',
|
firstBuyDate: '2012-12-31',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -1433,7 +1432,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('300'),
|
quantity: new Big('300'),
|
||||||
symbol: 'SPB', // Sub Portfolio B
|
symbol: 'SPB', // Sub Portfolio B
|
||||||
investment: new Big('300'),
|
investment: new Big('300'),
|
||||||
currency: Currency.CHF,
|
currency: 'CHF',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2012-12-31',
|
firstBuyDate: '2012-12-31',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -1494,7 +1493,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with yearly', async () => {
|
it('with yearly', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints);
|
portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints);
|
||||||
const timelineSpecification: TimelineSpecification[] = [
|
const timelineSpecification: TimelineSpecification[] = [
|
||||||
@ -1537,7 +1536,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with yearly and fees', async () => {
|
it('with yearly and fees', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
const transactionPoints: TransactionPoint[] = [
|
const transactionPoints: TransactionPoint[] = [
|
||||||
{
|
{
|
||||||
@ -1547,7 +1546,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('10'),
|
quantity: new Big('10'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('1443.8'),
|
investment: new Big('1443.8'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(50),
|
fee: new Big(50),
|
||||||
@ -1562,7 +1561,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('20'),
|
quantity: new Big('20'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('2923.7'),
|
investment: new Big('2923.7'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(100),
|
fee: new Big(100),
|
||||||
@ -1577,7 +1576,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('652.55'),
|
investment: new Big('652.55'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(150),
|
fee: new Big(150),
|
||||||
@ -1592,7 +1591,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('15'),
|
quantity: new Big('15'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('2684.05'),
|
investment: new Big('2684.05'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(200),
|
fee: new Big(200),
|
||||||
@ -1607,7 +1606,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('25'),
|
quantity: new Big('25'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('4460.95'),
|
investment: new Big('4460.95'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(250),
|
fee: new Big(250),
|
||||||
@ -1657,7 +1656,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with monthly', async () => {
|
it('with monthly', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints);
|
portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints);
|
||||||
const timelineSpecification: TimelineSpecification[] = [
|
const timelineSpecification: TimelineSpecification[] = [
|
||||||
@ -1889,7 +1888,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with yearly and monthly mixed', async () => {
|
it('with yearly and monthly mixed', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints);
|
portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints);
|
||||||
const timelineSpecification: TimelineSpecification[] = [
|
const timelineSpecification: TimelineSpecification[] = [
|
||||||
@ -1971,7 +1970,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with all mixed', async () => {
|
it('with all mixed', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints);
|
portfolioCalculator.setTransactionPoints(ordersVTITransactionPoints);
|
||||||
const timelineSpecification: TimelineSpecification[] = [
|
const timelineSpecification: TimelineSpecification[] = [
|
||||||
@ -2262,7 +2261,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
it('with mixed portfolio', async () => {
|
it('with mixed portfolio', async () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
portfolioCalculator.setTransactionPoints([
|
portfolioCalculator.setTransactionPoints([
|
||||||
{
|
{
|
||||||
@ -2272,7 +2271,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
investment: new Big('10109.95'),
|
investment: new Big('10109.95'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2282,7 +2281,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
quantity: new Big('10'),
|
quantity: new Big('10'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('1443.8'),
|
investment: new Big('1443.8'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2325,7 +2324,7 @@ describe('PortfolioCalculator', () => {
|
|||||||
describe('annualized performance percentage', () => {
|
describe('annualized performance percentage', () => {
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
currentRateService,
|
currentRateService,
|
||||||
Currency.USD
|
'USD'
|
||||||
);
|
);
|
||||||
|
|
||||||
it('Get annualized performance', async () => {
|
it('Get annualized performance', async () => {
|
||||||
@ -2391,7 +2390,7 @@ const ordersMixedSymbols: PortfolioOrder[] = [
|
|||||||
symbol: 'TSLA',
|
symbol: 'TSLA',
|
||||||
type: OrderType.Buy,
|
type: OrderType.Buy,
|
||||||
unitPrice: new Big('42.97'),
|
unitPrice: new Big('42.97'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big(0)
|
fee: new Big(0)
|
||||||
},
|
},
|
||||||
@ -2402,7 +2401,7 @@ const ordersMixedSymbols: PortfolioOrder[] = [
|
|||||||
symbol: 'BTCUSD',
|
symbol: 'BTCUSD',
|
||||||
type: OrderType.Buy,
|
type: OrderType.Buy,
|
||||||
unitPrice: new Big('3562.089535970158'),
|
unitPrice: new Big('3562.089535970158'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big(0)
|
fee: new Big(0)
|
||||||
},
|
},
|
||||||
@ -2413,7 +2412,7 @@ const ordersMixedSymbols: PortfolioOrder[] = [
|
|||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
type: OrderType.Buy,
|
type: OrderType.Buy,
|
||||||
unitPrice: new Big('2021.99'),
|
unitPrice: new Big('2021.99'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big(0)
|
fee: new Big(0)
|
||||||
}
|
}
|
||||||
@ -2427,7 +2426,7 @@ const ordersVTI: PortfolioOrder[] = [
|
|||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
type: OrderType.Buy,
|
type: OrderType.Buy,
|
||||||
unitPrice: new Big('144.38'),
|
unitPrice: new Big('144.38'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big(0)
|
fee: new Big(0)
|
||||||
},
|
},
|
||||||
@ -2438,7 +2437,7 @@ const ordersVTI: PortfolioOrder[] = [
|
|||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
type: OrderType.Buy,
|
type: OrderType.Buy,
|
||||||
unitPrice: new Big('147.99'),
|
unitPrice: new Big('147.99'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big(0)
|
fee: new Big(0)
|
||||||
},
|
},
|
||||||
@ -2449,7 +2448,7 @@ const ordersVTI: PortfolioOrder[] = [
|
|||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
type: OrderType.Sell,
|
type: OrderType.Sell,
|
||||||
unitPrice: new Big('151.41'),
|
unitPrice: new Big('151.41'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big(0)
|
fee: new Big(0)
|
||||||
},
|
},
|
||||||
@ -2460,7 +2459,7 @@ const ordersVTI: PortfolioOrder[] = [
|
|||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
type: OrderType.Buy,
|
type: OrderType.Buy,
|
||||||
unitPrice: new Big('177.69'),
|
unitPrice: new Big('177.69'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big(0)
|
fee: new Big(0)
|
||||||
},
|
},
|
||||||
@ -2471,7 +2470,7 @@ const ordersVTI: PortfolioOrder[] = [
|
|||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
type: OrderType.Buy,
|
type: OrderType.Buy,
|
||||||
unitPrice: new Big('203.15'),
|
unitPrice: new Big('203.15'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
fee: new Big(0)
|
fee: new Big(0)
|
||||||
}
|
}
|
||||||
@ -2485,7 +2484,7 @@ const orderTslaTransactionPoint: TransactionPoint[] = [
|
|||||||
quantity: new Big('1'),
|
quantity: new Big('1'),
|
||||||
symbol: 'TSLA',
|
symbol: 'TSLA',
|
||||||
investment: new Big('719.46'),
|
investment: new Big('719.46'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2021-01-01',
|
firstBuyDate: '2021-01-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2503,7 +2502,7 @@ const ordersVTITransactionPoints: TransactionPoint[] = [
|
|||||||
quantity: new Big('10'),
|
quantity: new Big('10'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('1443.8'),
|
investment: new Big('1443.8'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2518,7 +2517,7 @@ const ordersVTITransactionPoints: TransactionPoint[] = [
|
|||||||
quantity: new Big('20'),
|
quantity: new Big('20'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('2923.7'),
|
investment: new Big('2923.7'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2533,7 +2532,7 @@ const ordersVTITransactionPoints: TransactionPoint[] = [
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('652.55'),
|
investment: new Big('652.55'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2548,7 +2547,7 @@ const ordersVTITransactionPoints: TransactionPoint[] = [
|
|||||||
quantity: new Big('15'),
|
quantity: new Big('15'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('2684.05'),
|
investment: new Big('2684.05'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2563,7 +2562,7 @@ const ordersVTITransactionPoints: TransactionPoint[] = [
|
|||||||
quantity: new Big('25'),
|
quantity: new Big('25'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('4460.95'),
|
investment: new Big('4460.95'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2581,7 +2580,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [
|
|||||||
quantity: new Big('10'),
|
quantity: new Big('10'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('1443.8'),
|
investment: new Big('1443.8'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2596,7 +2595,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [
|
|||||||
quantity: new Big('20'),
|
quantity: new Big('20'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('2923.7'),
|
investment: new Big('2923.7'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2611,7 +2610,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
investment: new Big('10109.95'),
|
investment: new Big('10109.95'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-09-01',
|
firstBuyDate: '2019-09-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2621,7 +2620,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [
|
|||||||
quantity: new Big('20'),
|
quantity: new Big('20'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('2923.7'),
|
investment: new Big('2923.7'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2636,7 +2635,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
investment: new Big('10109.95'),
|
investment: new Big('10109.95'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-09-01',
|
firstBuyDate: '2019-09-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2646,7 +2645,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('652.55'),
|
investment: new Big('652.55'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2661,7 +2660,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [
|
|||||||
quantity: new Big('0'),
|
quantity: new Big('0'),
|
||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
investment: new Big('0'),
|
investment: new Big('0'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-09-01',
|
firstBuyDate: '2019-09-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2671,7 +2670,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [
|
|||||||
quantity: new Big('5'),
|
quantity: new Big('5'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('652.55'),
|
investment: new Big('652.55'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2686,7 +2685,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [
|
|||||||
quantity: new Big('0'),
|
quantity: new Big('0'),
|
||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
investment: new Big('0'),
|
investment: new Big('0'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-09-01',
|
firstBuyDate: '2019-09-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2696,7 +2695,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [
|
|||||||
quantity: new Big('15'),
|
quantity: new Big('15'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('2684.05'),
|
investment: new Big('2684.05'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2711,7 +2710,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [
|
|||||||
quantity: new Big('0'),
|
quantity: new Big('0'),
|
||||||
symbol: 'AMZN',
|
symbol: 'AMZN',
|
||||||
investment: new Big('0'),
|
investment: new Big('0'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-09-01',
|
firstBuyDate: '2019-09-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
@ -2721,7 +2720,7 @@ const transactionPointsBuyAndSell: TransactionPoint[] = [
|
|||||||
quantity: new Big('25'),
|
quantity: new Big('25'),
|
||||||
symbol: 'VTI',
|
symbol: 'VTI',
|
||||||
investment: new Big('4460.95'),
|
investment: new Big('4460.95'),
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
firstBuyDate: '2019-02-01',
|
firstBuyDate: '2019-02-01',
|
||||||
fee: new Big(0),
|
fee: new Big(0),
|
||||||
|
@ -2,7 +2,6 @@ import { OrderType } from '@ghostfolio/api/models/order-type';
|
|||||||
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
|
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
|
||||||
import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
|
import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
|
||||||
import { TimelinePosition } from '@ghostfolio/common/interfaces';
|
import { TimelinePosition } from '@ghostfolio/common/interfaces';
|
||||||
import { Currency, DataSource } from '@prisma/client';
|
|
||||||
import Big from 'big.js';
|
import Big from 'big.js';
|
||||||
import {
|
import {
|
||||||
addDays,
|
addDays,
|
||||||
@ -35,7 +34,7 @@ export class PortfolioCalculator {
|
|||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private currentRateService: CurrentRateService,
|
private currentRateService: CurrentRateService,
|
||||||
private currency: Currency
|
private currency: string
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public computeTransactionPoints(orders: PortfolioOrder[]) {
|
public computeTransactionPoints(orders: PortfolioOrder[]) {
|
||||||
@ -157,7 +156,7 @@ export class PortfolioCalculator {
|
|||||||
let firstIndex = this.transactionPoints.length;
|
let firstIndex = this.transactionPoints.length;
|
||||||
const dates = [];
|
const dates = [];
|
||||||
const dataGatheringItems: IDataGatheringItem[] = [];
|
const dataGatheringItems: IDataGatheringItem[] = [];
|
||||||
const currencies: { [symbol: string]: Currency } = {};
|
const currencies: { [symbol: string]: string } = {};
|
||||||
|
|
||||||
dates.push(resetHours(start));
|
dates.push(resetHours(start));
|
||||||
for (const item of this.transactionPoints[firstIndex - 1].items) {
|
for (const item of this.transactionPoints[firstIndex - 1].items) {
|
||||||
@ -521,7 +520,7 @@ export class PortfolioCalculator {
|
|||||||
[date: string]: { [symbol: string]: Big };
|
[date: string]: { [symbol: string]: Big };
|
||||||
} = {};
|
} = {};
|
||||||
if (j >= 0) {
|
if (j >= 0) {
|
||||||
const currencies: { [name: string]: Currency } = {};
|
const currencies: { [name: string]: string } = {};
|
||||||
const dataGatheringItems: IDataGatheringItem[] = [];
|
const dataGatheringItems: IDataGatheringItem[] = [];
|
||||||
|
|
||||||
for (const item of this.transactionPoints[j].items) {
|
for (const item of this.transactionPoints[j].items) {
|
||||||
|
@ -39,15 +39,9 @@ import type {
|
|||||||
} from '@ghostfolio/common/types';
|
} from '@ghostfolio/common/types';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { REQUEST } from '@nestjs/core';
|
import { REQUEST } from '@nestjs/core';
|
||||||
import {
|
import { AssetClass, DataSource, Type as TypeOfOrder } from '@prisma/client';
|
||||||
AssetClass,
|
|
||||||
Currency,
|
|
||||||
DataSource,
|
|
||||||
Type as TypeOfOrder
|
|
||||||
} from '@prisma/client';
|
|
||||||
import Big from 'big.js';
|
import Big from 'big.js';
|
||||||
import {
|
import {
|
||||||
differenceInDays,
|
|
||||||
endOfToday,
|
endOfToday,
|
||||||
format,
|
format,
|
||||||
isAfter,
|
isAfter,
|
||||||
@ -59,7 +53,7 @@ import {
|
|||||||
subDays,
|
subDays,
|
||||||
subYears
|
subYears
|
||||||
} from 'date-fns';
|
} from 'date-fns';
|
||||||
import { isEmpty, isNumber } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
HistoricalDataItem,
|
HistoricalDataItem,
|
||||||
@ -775,7 +769,7 @@ export class PortfolioService {
|
|||||||
assetClass: AssetClass.CASH,
|
assetClass: AssetClass.CASH,
|
||||||
assetSubClass: AssetClass.CASH,
|
assetSubClass: AssetClass.CASH,
|
||||||
countries: [],
|
countries: [],
|
||||||
currency: Currency.CHF,
|
currency: 'CHF',
|
||||||
grossPerformance: 0,
|
grossPerformance: 0,
|
||||||
grossPerformancePercent: 0,
|
grossPerformancePercent: 0,
|
||||||
investment: cashValue.toNumber(),
|
investment: cashValue.toNumber(),
|
||||||
@ -865,7 +859,7 @@ export class PortfolioService {
|
|||||||
private async getAccounts(
|
private async getAccounts(
|
||||||
orders: OrderWithAccount[],
|
orders: OrderWithAccount[],
|
||||||
portfolioItemsNow: { [p: string]: TimelinePosition },
|
portfolioItemsNow: { [p: string]: TimelinePosition },
|
||||||
userCurrency: Currency,
|
userCurrency: string,
|
||||||
userId: string
|
userId: string
|
||||||
) {
|
) {
|
||||||
const accounts: PortfolioDetails['accounts'] = {};
|
const accounts: PortfolioDetails['accounts'] = {};
|
||||||
@ -938,7 +932,7 @@ export class PortfolioService {
|
|||||||
|
|
||||||
private getTotalByType(
|
private getTotalByType(
|
||||||
orders: OrderWithAccount[],
|
orders: OrderWithAccount[],
|
||||||
currency: Currency,
|
currency: string,
|
||||||
type: TypeOfOrder
|
type: TypeOfOrder
|
||||||
) {
|
) {
|
||||||
return orders
|
return orders
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||||
import { Rule } from '@ghostfolio/api/models/rule';
|
import { Rule } from '@ghostfolio/api/models/rule';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RulesService {
|
export class RulesService {
|
||||||
@ -9,7 +8,7 @@ export class RulesService {
|
|||||||
|
|
||||||
public async evaluate<T extends RuleSettings>(
|
public async evaluate<T extends RuleSettings>(
|
||||||
aRules: Rule<T>[],
|
aRules: Rule<T>[],
|
||||||
aUserSettings: { baseCurrency: Currency }
|
aUserSettings: { baseCurrency: string }
|
||||||
) {
|
) {
|
||||||
return aRules
|
return aRules
|
||||||
.filter((rule) => {
|
.filter((rule) => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Currency, DataSource } from '@prisma/client';
|
import { DataSource } from '@prisma/client';
|
||||||
|
|
||||||
export interface LookupItem {
|
export interface LookupItem {
|
||||||
currency: Currency;
|
currency: string;
|
||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
name: string;
|
name: string;
|
||||||
symbol: string;
|
symbol: string;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Currency, DataSource } from '@prisma/client';
|
import { DataSource } from '@prisma/client';
|
||||||
|
|
||||||
export interface SymbolItem {
|
export interface SymbolItem {
|
||||||
currency: Currency;
|
currency: string;
|
||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
marketPrice: number;
|
marketPrice: number;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider/data
|
|||||||
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
|
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
|
||||||
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { Currency, DataSource } from '@prisma/client';
|
import { DataSource } from '@prisma/client';
|
||||||
|
|
||||||
import { LookupItem } from './interfaces/lookup-item.interface';
|
import { LookupItem } from './interfaces/lookup-item.interface';
|
||||||
import { SymbolItem } from './interfaces/symbol-item.interface';
|
import { SymbolItem } from './interfaces/symbol-item.interface';
|
||||||
@ -20,8 +20,8 @@ export class SymbolService {
|
|||||||
|
|
||||||
if (dataGatheringItem.dataSource && marketPrice) {
|
if (dataGatheringItem.dataSource && marketPrice) {
|
||||||
return {
|
return {
|
||||||
|
currency,
|
||||||
marketPrice,
|
marketPrice,
|
||||||
currency: <Currency>(<unknown>currency),
|
|
||||||
dataSource: dataGatheringItem.dataSource
|
dataSource: dataGatheringItem.dataSource
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Currency, ViewMode } from '@prisma/client';
|
import { ViewMode } from '@prisma/client';
|
||||||
|
|
||||||
export interface UserSettingsParams {
|
export interface UserSettingsParams {
|
||||||
currency?: Currency;
|
currency?: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
viewMode?: ViewMode;
|
viewMode?: ViewMode;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { Currency, ViewMode } from '@prisma/client';
|
import { ViewMode } from '@prisma/client';
|
||||||
import { IsString } from 'class-validator';
|
import { IsString } from 'class-validator';
|
||||||
|
|
||||||
export class UpdateUserSettingsDto {
|
export class UpdateUserSettingsDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
baseCurrency: Currency;
|
baseCurrency: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
viewMode: ViewMode;
|
viewMode: ViewMode;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { SubscriptionService } from '@ghostfolio/api/app/subscription/subscription.service';
|
import { SubscriptionService } from '@ghostfolio/api/app/subscription/subscription.service';
|
||||||
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
|
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
|
||||||
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
||||||
import { locale } from '@ghostfolio/common/config';
|
import { baseCurrency, locale } from '@ghostfolio/common/config';
|
||||||
import { User as IUser, UserWithSettings } from '@ghostfolio/common/interfaces';
|
import { User as IUser, UserWithSettings } from '@ghostfolio/common/interfaces';
|
||||||
import { getPermissions, permissions } from '@ghostfolio/common/permissions';
|
import { getPermissions, permissions } from '@ghostfolio/common/permissions';
|
||||||
import { SubscriptionType } from '@ghostfolio/common/types/subscription.type';
|
import { SubscriptionType } from '@ghostfolio/common/types/subscription.type';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { Currency, Prisma, Provider, User, ViewMode } from '@prisma/client';
|
import { Prisma, Provider, User, ViewMode } from '@prisma/client';
|
||||||
|
|
||||||
import { UserSettingsParams } from './interfaces/user-settings-params.interface';
|
import { UserSettingsParams } from './interfaces/user-settings-params.interface';
|
||||||
import { UserSettings } from './interfaces/user-settings.interface';
|
import { UserSettings } from './interfaces/user-settings.interface';
|
||||||
@ -15,7 +15,7 @@ const crypto = require('crypto');
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserService {
|
export class UserService {
|
||||||
public static DEFAULT_CURRENCY = Currency.USD;
|
public static DEFAULT_CURRENCY = 'USD';
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private readonly configurationService: ConfigurationService,
|
private readonly configurationService: ConfigurationService,
|
||||||
@ -144,9 +144,15 @@ export class UserService {
|
|||||||
...data,
|
...data,
|
||||||
Account: {
|
Account: {
|
||||||
create: {
|
create: {
|
||||||
|
currency: baseCurrency,
|
||||||
isDefault: true,
|
isDefault: true,
|
||||||
name: 'Default Account'
|
name: 'Default Account'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
Settings: {
|
||||||
|
create: {
|
||||||
|
currency: baseCurrency
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import { Currency } from '@prisma/client';
|
|
||||||
|
|
||||||
export interface UserSettings {
|
export interface UserSettings {
|
||||||
baseCurrency: Currency;
|
baseCurrency: string;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Account, Currency, SymbolProfile } from '@prisma/client';
|
import { Account, SymbolProfile } from '@prisma/client';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
import { IOrder } from '../services/interfaces/interfaces';
|
import { IOrder } from '../services/interfaces/interfaces';
|
||||||
@ -6,7 +6,7 @@ import { OrderType } from './order-type';
|
|||||||
|
|
||||||
export class Order {
|
export class Order {
|
||||||
private account: Account;
|
private account: Account;
|
||||||
private currency: Currency;
|
private currency: string;
|
||||||
private fee: number;
|
private fee: number;
|
||||||
private date: string;
|
private date: string;
|
||||||
private id: string;
|
private id: string;
|
||||||
|
@ -3,7 +3,6 @@ import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.in
|
|||||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||||
import { groupBy } from '@ghostfolio/common/helper';
|
import { groupBy } from '@ghostfolio/common/helper';
|
||||||
import { TimelinePosition } from '@ghostfolio/common/interfaces';
|
import { TimelinePosition } from '@ghostfolio/common/interfaces';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
|
|
||||||
import { EvaluationResult } from './interfaces/evaluation-result.interface';
|
import { EvaluationResult } from './interfaces/evaluation-result.interface';
|
||||||
import { RuleInterface } from './interfaces/rule.interface';
|
import { RuleInterface } from './interfaces/rule.interface';
|
||||||
@ -29,7 +28,7 @@ export abstract class Rule<T extends RuleSettings> implements RuleInterface<T> {
|
|||||||
public groupCurrentPositionsByAttribute(
|
public groupCurrentPositionsByAttribute(
|
||||||
positions: TimelinePosition[],
|
positions: TimelinePosition[],
|
||||||
attribute: keyof TimelinePosition,
|
attribute: keyof TimelinePosition,
|
||||||
baseCurrency: Currency
|
baseCurrency: string
|
||||||
) {
|
) {
|
||||||
return Array.from(groupBy(attribute, positions).entries()).map(
|
return Array.from(groupBy(attribute, positions).entries()).map(
|
||||||
([attributeValue, objs]) => ({
|
([attributeValue, objs]) => ({
|
||||||
|
@ -2,8 +2,6 @@ import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/curre
|
|||||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||||
import { PortfolioPosition } from '@ghostfolio/common/interfaces';
|
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
|
|
||||||
import { Rule } from '../../rule';
|
import { Rule } from '../../rule';
|
||||||
|
|
||||||
@ -69,5 +67,5 @@ export class CurrencyClusterRiskBaseCurrencyCurrentInvestment extends Rule<Setti
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Settings extends RuleSettings {
|
interface Settings extends RuleSettings {
|
||||||
baseCurrency: Currency;
|
baseCurrency: string;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface';
|
import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface';
|
||||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
import { ExchangeRateDataService } from 'apps/api/src/services/exchange-rate-data.service';
|
import { ExchangeRateDataService } from 'apps/api/src/services/exchange-rate-data.service';
|
||||||
|
|
||||||
import { Rule } from '../../rule';
|
import { Rule } from '../../rule';
|
||||||
@ -69,5 +68,5 @@ export class CurrencyClusterRiskBaseCurrencyInitialInvestment extends Rule<Setti
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Settings extends RuleSettings {
|
interface Settings extends RuleSettings {
|
||||||
baseCurrency: Currency;
|
baseCurrency: string;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface';
|
import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface';
|
||||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
import { ExchangeRateDataService } from 'apps/api/src/services/exchange-rate-data.service';
|
import { ExchangeRateDataService } from 'apps/api/src/services/exchange-rate-data.service';
|
||||||
|
|
||||||
import { Rule } from '../../rule';
|
import { Rule } from '../../rule';
|
||||||
@ -69,6 +68,6 @@ export class CurrencyClusterRiskCurrentInvestment extends Rule<Settings> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Settings extends RuleSettings {
|
interface Settings extends RuleSettings {
|
||||||
baseCurrency: Currency;
|
baseCurrency: string;
|
||||||
threshold: number;
|
threshold: number;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface';
|
import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface';
|
||||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
import { ExchangeRateDataService } from 'apps/api/src/services/exchange-rate-data.service';
|
import { ExchangeRateDataService } from 'apps/api/src/services/exchange-rate-data.service';
|
||||||
|
|
||||||
import { Rule } from '../../rule';
|
import { Rule } from '../../rule';
|
||||||
@ -69,6 +68,6 @@ export class CurrencyClusterRiskInitialInvestment extends Rule<Settings> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Settings extends RuleSettings {
|
interface Settings extends RuleSettings {
|
||||||
baseCurrency: Currency;
|
baseCurrency: string;
|
||||||
threshold: number;
|
threshold: number;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
import { ExchangeRateDataService } from 'apps/api/src/services/exchange-rate-data.service';
|
import { ExchangeRateDataService } from 'apps/api/src/services/exchange-rate-data.service';
|
||||||
|
|
||||||
import { Rule } from '../../rule';
|
import { Rule } from '../../rule';
|
||||||
@ -46,6 +45,6 @@ export class FeeRatioInitialInvestment extends Rule<Settings> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Settings extends RuleSettings {
|
interface Settings extends RuleSettings {
|
||||||
baseCurrency: Currency;
|
baseCurrency: string;
|
||||||
threshold: number;
|
threshold: number;
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,15 @@ import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-
|
|||||||
import { PrismaModule } from '@ghostfolio/api/services/prisma.module';
|
import { PrismaModule } from '@ghostfolio/api/services/prisma.module';
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { ExchangeRateDataModule } from './exchange-rate-data.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigurationModule, DataProviderModule, PrismaModule],
|
imports: [
|
||||||
|
ConfigurationModule,
|
||||||
|
DataProviderModule,
|
||||||
|
ExchangeRateDataModule,
|
||||||
|
PrismaModule
|
||||||
|
],
|
||||||
providers: [DataGatheringService],
|
providers: [DataGatheringService],
|
||||||
exports: [DataGatheringService]
|
exports: [DataGatheringService]
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
benchmarks,
|
benchmarks,
|
||||||
currencyPairs,
|
|
||||||
ghostfolioFearAndGreedIndexSymbol
|
ghostfolioFearAndGreedIndexSymbol
|
||||||
} from '@ghostfolio/common/config';
|
} from '@ghostfolio/common/config';
|
||||||
import { DATE_FORMAT, getUtc, resetHours } from '@ghostfolio/common/helper';
|
import { DATE_FORMAT, getUtc, resetHours } from '@ghostfolio/common/helper';
|
||||||
@ -19,6 +18,7 @@ import {
|
|||||||
import { ConfigurationService } from './configuration.service';
|
import { ConfigurationService } from './configuration.service';
|
||||||
import { DataProviderService } from './data-provider/data-provider.service';
|
import { DataProviderService } from './data-provider/data-provider.service';
|
||||||
import { GhostfolioScraperApiService } from './data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service';
|
import { GhostfolioScraperApiService } from './data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service';
|
||||||
|
import { ExchangeRateDataService } from './exchange-rate-data.service';
|
||||||
import { IDataGatheringItem } from './interfaces/interfaces';
|
import { IDataGatheringItem } from './interfaces/interfaces';
|
||||||
import { PrismaService } from './prisma.service';
|
import { PrismaService } from './prisma.service';
|
||||||
|
|
||||||
@ -27,6 +27,7 @@ export class DataGatheringService {
|
|||||||
public constructor(
|
public constructor(
|
||||||
private readonly configurationService: ConfigurationService,
|
private readonly configurationService: ConfigurationService,
|
||||||
private readonly dataProviderService: DataProviderService,
|
private readonly dataProviderService: DataProviderService,
|
||||||
|
private readonly exchangeRateDataService: ExchangeRateDataService,
|
||||||
private readonly ghostfolioScraperApi: GhostfolioScraperApiService,
|
private readonly ghostfolioScraperApi: GhostfolioScraperApiService,
|
||||||
private readonly prismaService: PrismaService
|
private readonly prismaService: PrismaService
|
||||||
) {}
|
) {}
|
||||||
@ -230,6 +231,8 @@ export class DataGatheringService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.exchangeRateDataService.initialize();
|
||||||
|
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
throw '';
|
throw '';
|
||||||
}
|
}
|
||||||
@ -316,15 +319,15 @@ export class DataGatheringService {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const currencyPairsToGather = currencyPairs.map(
|
const currencyPairsToGather = this.exchangeRateDataService
|
||||||
({ dataSource, symbol }) => {
|
.getCurrencyPairs()
|
||||||
|
.map(({ dataSource, symbol }) => {
|
||||||
return {
|
return {
|
||||||
dataSource,
|
dataSource,
|
||||||
symbol,
|
symbol,
|
||||||
date: startDate
|
date: startDate
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const customSymbolsToGather =
|
const customSymbolsToGather =
|
||||||
await this.ghostfolioScraperApi.getCustomSymbolsToGather(startDate);
|
await this.ghostfolioScraperApi.getCustomSymbolsToGather(startDate);
|
||||||
@ -343,15 +346,15 @@ export class DataGatheringService {
|
|||||||
const customSymbolsToGather =
|
const customSymbolsToGather =
|
||||||
await this.ghostfolioScraperApi.getCustomSymbolsToGather(startDate);
|
await this.ghostfolioScraperApi.getCustomSymbolsToGather(startDate);
|
||||||
|
|
||||||
const currencyPairsToGather = currencyPairs.map(
|
const currencyPairsToGather = this.exchangeRateDataService
|
||||||
({ dataSource, symbol }) => {
|
.getCurrencyPairs()
|
||||||
|
.map(({ dataSource, symbol }) => {
|
||||||
return {
|
return {
|
||||||
dataSource,
|
dataSource,
|
||||||
symbol,
|
symbol,
|
||||||
date: startDate
|
date: startDate
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const symbolProfilesToGather =
|
const symbolProfilesToGather =
|
||||||
await this.prismaService.symbolProfile.findMany({
|
await this.prismaService.symbolProfile.findMany({
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import { Currency } from '@prisma/client';
|
|
||||||
|
|
||||||
export interface ScraperConfig {
|
export interface ScraperConfig {
|
||||||
currency: Currency;
|
currency: string;
|
||||||
selector: string;
|
selector: string;
|
||||||
symbol: string;
|
symbol: string;
|
||||||
url: string;
|
url: string;
|
||||||
|
@ -1,19 +1,9 @@
|
|||||||
import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface';
|
import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface';
|
||||||
import { UNKNOWN_KEY } from '@ghostfolio/common/config';
|
import { UNKNOWN_KEY } from '@ghostfolio/common/config';
|
||||||
import {
|
import { DATE_FORMAT, isCrypto, isCurrency } from '@ghostfolio/common/helper';
|
||||||
DATE_FORMAT,
|
|
||||||
isCrypto,
|
|
||||||
isCurrency,
|
|
||||||
parseCurrency
|
|
||||||
} from '@ghostfolio/common/helper';
|
|
||||||
import { Granularity } from '@ghostfolio/common/types';
|
import { Granularity } from '@ghostfolio/common/types';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import {
|
import { AssetClass, AssetSubClass, DataSource } from '@prisma/client';
|
||||||
AssetClass,
|
|
||||||
AssetSubClass,
|
|
||||||
Currency,
|
|
||||||
DataSource
|
|
||||||
} from '@prisma/client';
|
|
||||||
import * as bent from 'bent';
|
import * as bent from 'bent';
|
||||||
import Big from 'big.js';
|
import Big from 'big.js';
|
||||||
import { countries } from 'countries-list';
|
import { countries } from 'countries-list';
|
||||||
@ -68,7 +58,7 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
response[symbol] = {
|
response[symbol] = {
|
||||||
assetClass,
|
assetClass,
|
||||||
assetSubClass,
|
assetSubClass,
|
||||||
currency: parseCurrency(value.price?.currency),
|
currency: value.price?.currency,
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
exchange: this.parseExchange(value.price?.exchangeName),
|
exchange: this.parseExchange(value.price?.exchangeName),
|
||||||
marketState:
|
marketState:
|
||||||
@ -81,7 +71,7 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
|
|
||||||
if (value.price?.currency === 'GBp') {
|
if (value.price?.currency === 'GBp') {
|
||||||
// Convert GBp (pence) to GBP
|
// Convert GBp (pence) to GBP
|
||||||
response[symbol].currency = Currency.GBP;
|
response[symbol].currency = 'GBP';
|
||||||
response[symbol].marketPrice = new Big(
|
response[symbol].marketPrice = new Big(
|
||||||
value.price?.regularMarketPrice ?? 0
|
value.price?.regularMarketPrice ?? 0
|
||||||
)
|
)
|
||||||
@ -200,7 +190,7 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
.filter(({ quoteType, symbol }) => {
|
.filter(({ quoteType, symbol }) => {
|
||||||
if (quoteType === 'CRYPTOCURRENCY') {
|
if (quoteType === 'CRYPTOCURRENCY') {
|
||||||
// Only allow cryptocurrencies in USD
|
// Only allow cryptocurrencies in USD
|
||||||
return symbol.includes(Currency.USD);
|
return symbol.includes('USD');
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -2,8 +2,10 @@ import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-
|
|||||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { PrismaModule } from './prisma.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [DataProviderModule],
|
imports: [DataProviderModule, PrismaModule],
|
||||||
providers: [ExchangeRateDataService],
|
providers: [ExchangeRateDataService],
|
||||||
exports: [ExchangeRateDataService]
|
exports: [ExchangeRateDataService]
|
||||||
})
|
})
|
||||||
|
@ -1,27 +1,45 @@
|
|||||||
import { currencyPairs } from '@ghostfolio/common/config';
|
import { baseCurrency } from '@ghostfolio/common/config';
|
||||||
import { DATE_FORMAT, getYesterday } from '@ghostfolio/common/helper';
|
import { DATE_FORMAT, getYesterday } from '@ghostfolio/common/helper';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { Currency, DataSource } from '@prisma/client';
|
import { DataSource } from '@prisma/client';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import { isEmpty, isNumber } from 'lodash';
|
import { isEmpty, isNumber, uniq } from 'lodash';
|
||||||
|
|
||||||
import { DataProviderService } from './data-provider/data-provider.service';
|
import { DataProviderService } from './data-provider/data-provider.service';
|
||||||
import { IDataGatheringItem } from './interfaces/interfaces';
|
import { IDataGatheringItem } from './interfaces/interfaces';
|
||||||
|
import { PrismaService } from './prisma.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ExchangeRateDataService {
|
export class ExchangeRateDataService {
|
||||||
|
private currencies: string[] = [];
|
||||||
private currencyPairs: IDataGatheringItem[] = [];
|
private currencyPairs: IDataGatheringItem[] = [];
|
||||||
private exchangeRates: { [currencyPair: string]: number } = {};
|
private exchangeRates: { [currencyPair: string]: number } = {};
|
||||||
|
|
||||||
public constructor(private dataProviderService: DataProviderService) {
|
public constructor(
|
||||||
|
private readonly dataProviderService: DataProviderService,
|
||||||
|
private readonly prismaService: PrismaService
|
||||||
|
) {
|
||||||
this.initialize();
|
this.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getCurrencies() {
|
||||||
|
return this.currencies?.length > 0 ? this.currencies : [baseCurrency];
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCurrencyPairs() {
|
||||||
|
return this.currencyPairs;
|
||||||
|
}
|
||||||
|
|
||||||
public async initialize() {
|
public async initialize() {
|
||||||
|
this.currencies = await this.prepareCurrencies();
|
||||||
this.currencyPairs = [];
|
this.currencyPairs = [];
|
||||||
this.exchangeRates = {};
|
this.exchangeRates = {};
|
||||||
|
|
||||||
for (const { currency1, currency2, dataSource } of currencyPairs) {
|
for (const {
|
||||||
|
currency1,
|
||||||
|
currency2,
|
||||||
|
dataSource
|
||||||
|
} of this.prepareCurrencyPairs(this.currencies)) {
|
||||||
this.addCurrencyPairs({ currency1, currency2, dataSource });
|
this.addCurrencyPairs({ currency1, currency2, dataSource });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,8 +95,8 @@ export class ExchangeRateDataService {
|
|||||||
if (!this.exchangeRates[symbol]) {
|
if (!this.exchangeRates[symbol]) {
|
||||||
// Not found, calculate indirectly via USD
|
// Not found, calculate indirectly via USD
|
||||||
this.exchangeRates[symbol] =
|
this.exchangeRates[symbol] =
|
||||||
resultExtended[`${currency1}${Currency.USD}`]?.[date]?.marketPrice *
|
resultExtended[`${currency1}${'USD'}`]?.[date]?.marketPrice *
|
||||||
resultExtended[`${Currency.USD}${currency2}`]?.[date]?.marketPrice;
|
resultExtended[`${'USD'}${currency2}`]?.[date]?.marketPrice;
|
||||||
|
|
||||||
// Calculate the opposite direction
|
// Calculate the opposite direction
|
||||||
this.exchangeRates[`${currency2}${currency1}`] =
|
this.exchangeRates[`${currency2}${currency1}`] =
|
||||||
@ -89,10 +107,14 @@ export class ExchangeRateDataService {
|
|||||||
|
|
||||||
public toCurrency(
|
public toCurrency(
|
||||||
aValue: number,
|
aValue: number,
|
||||||
aFromCurrency: Currency,
|
aFromCurrency: string,
|
||||||
aToCurrency: Currency
|
aToCurrency: string
|
||||||
) {
|
) {
|
||||||
if (isNaN(this.exchangeRates[`${Currency.USD}${Currency.CHF}`])) {
|
const hasNaN = Object.values(this.exchangeRates).some((exchangeRate) => {
|
||||||
|
return isNaN(exchangeRate);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hasNaN) {
|
||||||
// Reinitialize if data is not loaded correctly
|
// Reinitialize if data is not loaded correctly
|
||||||
this.initialize();
|
this.initialize();
|
||||||
}
|
}
|
||||||
@ -104,8 +126,8 @@ export class ExchangeRateDataService {
|
|||||||
factor = this.exchangeRates[`${aFromCurrency}${aToCurrency}`];
|
factor = this.exchangeRates[`${aFromCurrency}${aToCurrency}`];
|
||||||
} else {
|
} else {
|
||||||
// Calculate indirectly via USD
|
// Calculate indirectly via USD
|
||||||
const factor1 = this.exchangeRates[`${aFromCurrency}${Currency.USD}`];
|
const factor1 = this.exchangeRates[`${aFromCurrency}${'USD'}`];
|
||||||
const factor2 = this.exchangeRates[`${Currency.USD}${aToCurrency}`];
|
const factor2 = this.exchangeRates[`${'USD'}${aToCurrency}`];
|
||||||
|
|
||||||
factor = factor1 * factor2;
|
factor = factor1 * factor2;
|
||||||
|
|
||||||
@ -129,8 +151,8 @@ export class ExchangeRateDataService {
|
|||||||
currency2,
|
currency2,
|
||||||
dataSource
|
dataSource
|
||||||
}: {
|
}: {
|
||||||
currency1: Currency;
|
currency1: string;
|
||||||
currency2: Currency;
|
currency2: string;
|
||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
}) {
|
}) {
|
||||||
this.currencyPairs.push({
|
this.currencyPairs.push({
|
||||||
@ -142,4 +164,49 @@ export class ExchangeRateDataService {
|
|||||||
symbol: `${currency2}${currency1}`
|
symbol: `${currency2}${currency1}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async prepareCurrencies(): Promise<string[]> {
|
||||||
|
const currencies: string[] = [];
|
||||||
|
|
||||||
|
const settings = await this.prismaService.settings.findMany({
|
||||||
|
distinct: ['currency'],
|
||||||
|
orderBy: [{ currency: 'asc' }],
|
||||||
|
select: { currency: true }
|
||||||
|
});
|
||||||
|
|
||||||
|
settings.forEach((settingsItem) => {
|
||||||
|
if (settingsItem.currency) {
|
||||||
|
currencies.push(settingsItem.currency);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const symbolProfiles = await this.prismaService.symbolProfile.findMany({
|
||||||
|
distinct: ['currency'],
|
||||||
|
orderBy: [{ currency: 'asc' }],
|
||||||
|
select: { currency: true }
|
||||||
|
});
|
||||||
|
|
||||||
|
symbolProfiles.forEach((symbolProfile) => {
|
||||||
|
if (symbolProfile.currency) {
|
||||||
|
currencies.push(symbolProfile.currency);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return uniq(currencies).sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
private prepareCurrencyPairs(aCurrencies: string[]) {
|
||||||
|
return aCurrencies
|
||||||
|
.filter((currency) => {
|
||||||
|
return currency !== baseCurrency;
|
||||||
|
})
|
||||||
|
.map((currency) => {
|
||||||
|
return {
|
||||||
|
currency1: baseCurrency,
|
||||||
|
currency2: currency,
|
||||||
|
dataSource: DataSource.YAHOO,
|
||||||
|
symbol: `${baseCurrency}${currency}`
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ import {
|
|||||||
Account,
|
Account,
|
||||||
AssetClass,
|
AssetClass,
|
||||||
AssetSubClass,
|
AssetSubClass,
|
||||||
Currency,
|
|
||||||
DataSource,
|
DataSource,
|
||||||
SymbolProfile
|
SymbolProfile
|
||||||
} from '@prisma/client';
|
} from '@prisma/client';
|
||||||
@ -17,7 +16,7 @@ export const MarketState = {
|
|||||||
|
|
||||||
export interface IOrder {
|
export interface IOrder {
|
||||||
account: Account;
|
account: Account;
|
||||||
currency: Currency;
|
currency: string;
|
||||||
date: string;
|
date: string;
|
||||||
fee: number;
|
fee: number;
|
||||||
id?: string;
|
id?: string;
|
||||||
@ -38,7 +37,7 @@ export interface IDataProviderResponse {
|
|||||||
assetClass?: AssetClass;
|
assetClass?: AssetClass;
|
||||||
assetSubClass?: AssetSubClass;
|
assetSubClass?: AssetSubClass;
|
||||||
countries?: { code: string; weight: number }[];
|
countries?: { code: string; weight: number }[];
|
||||||
currency: Currency;
|
currency: string;
|
||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
exchange?: string;
|
exchange?: string;
|
||||||
marketChange?: number;
|
marketChange?: number;
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
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 { Sector } from '@ghostfolio/common/interfaces/sector.interface';
|
||||||
import {
|
import { AssetClass, AssetSubClass, DataSource } from '@prisma/client';
|
||||||
AssetClass,
|
|
||||||
AssetSubClass,
|
|
||||||
Currency,
|
|
||||||
DataSource
|
|
||||||
} from '@prisma/client';
|
|
||||||
|
|
||||||
export interface EnhancedSymbolProfile {
|
export interface EnhancedSymbolProfile {
|
||||||
assetClass: AssetClass;
|
assetClass: AssetClass;
|
||||||
assetSubClass: AssetSubClass;
|
assetSubClass: AssetSubClass;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
currency: Currency | null;
|
currency: string | null;
|
||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
id: string;
|
id: string;
|
||||||
name: string | null;
|
name: string | null;
|
||||||
|
@ -8,7 +8,6 @@ import {
|
|||||||
ViewChild
|
ViewChild
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { PortfolioPerformance } from '@ghostfolio/common/interfaces';
|
import { PortfolioPerformance } from '@ghostfolio/common/interfaces';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
import { CountUp } from 'countup.js';
|
import { CountUp } from 'countup.js';
|
||||||
import { isNumber } from 'lodash';
|
import { isNumber } from 'lodash';
|
||||||
|
|
||||||
@ -19,7 +18,7 @@ import { isNumber } from 'lodash';
|
|||||||
styleUrls: ['./portfolio-performance.component.scss']
|
styleUrls: ['./portfolio-performance.component.scss']
|
||||||
})
|
})
|
||||||
export class PortfolioPerformanceComponent implements OnChanges, OnInit {
|
export class PortfolioPerformanceComponent implements OnChanges, OnInit {
|
||||||
@Input() baseCurrency: Currency;
|
@Input() baseCurrency: string;
|
||||||
@Input() isLoading: boolean;
|
@Input() isLoading: boolean;
|
||||||
@Input() locale: string;
|
@Input() locale: string;
|
||||||
@Input() performance: PortfolioPerformance;
|
@Input() performance: PortfolioPerformance;
|
||||||
|
@ -6,7 +6,6 @@ import {
|
|||||||
OnInit
|
OnInit
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { PortfolioSummary } from '@ghostfolio/common/interfaces';
|
import { PortfolioSummary } from '@ghostfolio/common/interfaces';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
import { formatDistanceToNow } from 'date-fns';
|
import { formatDistanceToNow } from 'date-fns';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -16,7 +15,7 @@ import { formatDistanceToNow } from 'date-fns';
|
|||||||
styleUrls: ['./portfolio-summary.component.scss']
|
styleUrls: ['./portfolio-summary.component.scss']
|
||||||
})
|
})
|
||||||
export class PortfolioSummaryComponent implements OnChanges, OnInit {
|
export class PortfolioSummaryComponent implements OnChanges, OnInit {
|
||||||
@Input() baseCurrency: Currency;
|
@Input() baseCurrency: string;
|
||||||
@Input() isLoading: boolean;
|
@Input() isLoading: boolean;
|
||||||
@Input() locale: string;
|
@Input() locale: string;
|
||||||
@Input() summary: PortfolioSummary;
|
@Input() summary: PortfolioSummary;
|
||||||
|
@ -7,7 +7,6 @@ import {
|
|||||||
OnDestroy,
|
OnDestroy,
|
||||||
OnInit
|
OnInit
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
import svgMap from 'svgmap';
|
import svgMap from 'svgmap';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -17,7 +16,7 @@ import svgMap from 'svgmap';
|
|||||||
styleUrls: ['./world-map-chart.component.scss']
|
styleUrls: ['./world-map-chart.component.scss']
|
||||||
})
|
})
|
||||||
export class WorldMapChartComponent implements OnChanges, OnDestroy, OnInit {
|
export class WorldMapChartComponent implements OnChanges, OnDestroy, OnInit {
|
||||||
@Input() baseCurrency: Currency;
|
@Input() baseCurrency: string;
|
||||||
@Input() countries: { [code: string]: { name: string; value: number } };
|
@Input() countries: { [code: string]: { name: string; value: number } };
|
||||||
|
|
||||||
public isLoading = true;
|
public isLoading = true;
|
||||||
|
@ -15,7 +15,6 @@ import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service';
|
|||||||
import { DEFAULT_DATE_FORMAT, baseCurrency } from '@ghostfolio/common/config';
|
import { DEFAULT_DATE_FORMAT, baseCurrency } from '@ghostfolio/common/config';
|
||||||
import { Access, User } from '@ghostfolio/common/interfaces';
|
import { Access, User } from '@ghostfolio/common/interfaces';
|
||||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
import { StripeService } from 'ngx-stripe';
|
import { StripeService } from 'ngx-stripe';
|
||||||
import { EMPTY, Subject } from 'rxjs';
|
import { EMPTY, Subject } from 'rxjs';
|
||||||
import { catchError, switchMap, takeUntil } from 'rxjs/operators';
|
import { catchError, switchMap, takeUntil } from 'rxjs/operators';
|
||||||
@ -33,7 +32,7 @@ export class AccountPageComponent implements OnDestroy, OnInit {
|
|||||||
public baseCurrency = baseCurrency;
|
public baseCurrency = baseCurrency;
|
||||||
public coupon: number;
|
public coupon: number;
|
||||||
public couponId: string;
|
public couponId: string;
|
||||||
public currencies: Currency[] = [];
|
public currencies: string[] = [];
|
||||||
public defaultDateFormat = DEFAULT_DATE_FORMAT;
|
public defaultDateFormat = DEFAULT_DATE_FORMAT;
|
||||||
public hasPermissionForSubscription: boolean;
|
public hasPermissionForSubscription: boolean;
|
||||||
public hasPermissionToUpdateViewMode: boolean;
|
public hasPermissionToUpdateViewMode: boolean;
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
ChangeDetectorRef,
|
|
||||||
Component,
|
Component,
|
||||||
Inject,
|
Inject,
|
||||||
OnDestroy
|
OnDestroy
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
import { DataService } from '../../../services/data.service';
|
import { DataService } from '../../../services/data.service';
|
||||||
@ -20,13 +18,12 @@ import { CreateOrUpdateAccountDialogParams } from './interfaces/interfaces';
|
|||||||
templateUrl: 'create-or-update-account-dialog.html'
|
templateUrl: 'create-or-update-account-dialog.html'
|
||||||
})
|
})
|
||||||
export class CreateOrUpdateAccountDialog implements OnDestroy {
|
export class CreateOrUpdateAccountDialog implements OnDestroy {
|
||||||
public currencies: Currency[] = [];
|
public currencies: string[] = [];
|
||||||
public platforms: { id: string; name: string }[];
|
public platforms: { id: string; name: string }[];
|
||||||
|
|
||||||
private unsubscribeSubject = new Subject<void>();
|
private unsubscribeSubject = new Subject<void>();
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
|
||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
public dialogRef: MatDialogRef<CreateOrUpdateAccountDialog>,
|
public dialogRef: MatDialogRef<CreateOrUpdateAccountDialog>,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: CreateOrUpdateAccountDialogParams
|
@Inject(MAT_DIALOG_DATA) public data: CreateOrUpdateAccountDialogParams
|
||||||
|
@ -11,7 +11,6 @@ import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
|
|||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface';
|
import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface';
|
||||||
import { DataService } from '@ghostfolio/client/services/data.service';
|
import { DataService } from '@ghostfolio/client/services/data.service';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
import { isString } from 'lodash';
|
import { isString } from 'lodash';
|
||||||
import { EMPTY, Observable, Subject } from 'rxjs';
|
import { EMPTY, Observable, Subject } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
@ -35,7 +34,7 @@ import { CreateOrUpdateTransactionDialogParams } from './interfaces/interfaces';
|
|||||||
export class CreateOrUpdateTransactionDialog implements OnDestroy {
|
export class CreateOrUpdateTransactionDialog implements OnDestroy {
|
||||||
@ViewChild('autocomplete') autocomplete;
|
@ViewChild('autocomplete') autocomplete;
|
||||||
|
|
||||||
public currencies: Currency[] = [];
|
public currencies: string[] = [];
|
||||||
public currentMarketPrice = null;
|
public currentMarketPrice = null;
|
||||||
public filteredLookupItems: LookupItem[];
|
public filteredLookupItems: LookupItem[];
|
||||||
public filteredLookupItemsObservable: Observable<LookupItem[]>;
|
public filteredLookupItemsObservable: Observable<LookupItem[]>;
|
||||||
|
@ -1,31 +1,12 @@
|
|||||||
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
|
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
import { DataSource } from '@prisma/client';
|
import { DataSource } from '@prisma/client';
|
||||||
|
|
||||||
export const baseCurrency = Currency.USD;
|
export const baseCurrency = 'USD';
|
||||||
|
|
||||||
export const benchmarks: Partial<IDataGatheringItem>[] = [
|
export const benchmarks: Partial<IDataGatheringItem>[] = [
|
||||||
{ dataSource: DataSource.YAHOO, symbol: 'VOO' }
|
{ dataSource: DataSource.YAHOO, symbol: 'VOO' }
|
||||||
];
|
];
|
||||||
|
|
||||||
export const currencyPairs: Partial<
|
|
||||||
IDataGatheringItem & {
|
|
||||||
currency1: Currency;
|
|
||||||
currency2: Currency;
|
|
||||||
}
|
|
||||||
>[] = (Object.keys(Currency) as Array<keyof typeof Currency>)
|
|
||||||
.filter((currency) => {
|
|
||||||
return currency !== Currency.USD;
|
|
||||||
})
|
|
||||||
.map((currency) => {
|
|
||||||
return {
|
|
||||||
currency1: Currency.USD,
|
|
||||||
currency2: Currency[currency],
|
|
||||||
dataSource: DataSource.YAHOO,
|
|
||||||
symbol: `${Currency.USD}${Currency[currency]}`
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export const ghostfolioScraperApiSymbolPrefix = '_GF_';
|
export const ghostfolioScraperApiSymbolPrefix = '_GF_';
|
||||||
export const ghostfolioCashSymbol = `${ghostfolioScraperApiSymbolPrefix}CASH`;
|
export const ghostfolioCashSymbol = `${ghostfolioScraperApiSymbolPrefix}CASH`;
|
||||||
export const ghostfolioFearAndGreedIndexSymbol = `${ghostfolioScraperApiSymbolPrefix}FEAR_AND_GREED_INDEX`;
|
export const ghostfolioFearAndGreedIndexSymbol = `${ghostfolioScraperApiSymbolPrefix}FEAR_AND_GREED_INDEX`;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { Currency } from '@prisma/client';
|
|
||||||
import { getDate, getMonth, getYear, parse, subDays } from 'date-fns';
|
import { getDate, getMonth, getYear, parse, subDays } from 'date-fns';
|
||||||
|
|
||||||
import { ghostfolioScraperApiSymbolPrefix } from './config';
|
import { ghostfolioScraperApiSymbolPrefix } from './config';
|
||||||
@ -87,9 +86,9 @@ export function isCrypto(aSymbol = '') {
|
|||||||
|
|
||||||
export function isCurrency(aSymbol = '') {
|
export function isCurrency(aSymbol = '') {
|
||||||
return (
|
return (
|
||||||
(aSymbol.includes(Currency.CHF) ||
|
(aSymbol.includes('CHF') ||
|
||||||
aSymbol.includes(Currency.EUR) ||
|
aSymbol.includes('EUR') ||
|
||||||
aSymbol.includes(Currency.USD)) &&
|
aSymbol.includes('USD')) &&
|
||||||
aSymbol.length >= 6
|
aSymbol.length >= 6
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -102,10 +101,6 @@ export function isRakutenRapidApiSymbol(aSymbol = '') {
|
|||||||
return aSymbol === 'GF.FEAR_AND_GREED_INDEX';
|
return aSymbol === 'GF.FEAR_AND_GREED_INDEX';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseCurrency(aCurrency: string): Currency {
|
|
||||||
return Currency[aCurrency];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resetHours(aDate: Date) {
|
export function resetHours(aDate: Date) {
|
||||||
const year = getYear(aDate);
|
const year = getYear(aDate);
|
||||||
const month = getMonth(aDate);
|
const month = getMonth(aDate);
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import { Currency } from '@prisma/client';
|
|
||||||
|
|
||||||
import { Statistics } from './statistics.interface';
|
import { Statistics } from './statistics.interface';
|
||||||
import { Subscription } from './subscription.interface';
|
import { Subscription } from './subscription.interface';
|
||||||
|
|
||||||
export interface InfoItem {
|
export interface InfoItem {
|
||||||
currencies: Currency[];
|
currencies: string[];
|
||||||
demoAuthToken: string;
|
demoAuthToken: string;
|
||||||
globalPermissions: string[];
|
globalPermissions: string[];
|
||||||
lastDataGathering?: Date;
|
lastDataGathering?: Date;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces';
|
import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces';
|
||||||
import { AssetClass, AssetSubClass, Currency } from '@prisma/client';
|
import { AssetClass, AssetSubClass } from '@prisma/client';
|
||||||
|
|
||||||
import { Country } from './country.interface';
|
import { Country } from './country.interface';
|
||||||
import { Sector } from './sector.interface';
|
import { Sector } from './sector.interface';
|
||||||
@ -10,7 +10,7 @@ export interface PortfolioPosition {
|
|||||||
assetClass?: AssetClass;
|
assetClass?: AssetClass;
|
||||||
assetSubClass?: AssetSubClass | 'CASH';
|
assetSubClass?: AssetSubClass | 'CASH';
|
||||||
countries: Country[];
|
countries: Country[];
|
||||||
currency: Currency;
|
currency: string;
|
||||||
exchange?: string;
|
exchange?: string;
|
||||||
grossPerformance: number;
|
grossPerformance: number;
|
||||||
grossPerformancePercent: number;
|
grossPerformancePercent: number;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces';
|
import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces';
|
||||||
import { AssetClass, Currency } from '@prisma/client';
|
import { AssetClass } from '@prisma/client';
|
||||||
|
|
||||||
export interface Position {
|
export interface Position {
|
||||||
assetClass: AssetClass;
|
assetClass: AssetClass;
|
||||||
averagePrice: number;
|
averagePrice: number;
|
||||||
currency: Currency;
|
currency: string;
|
||||||
firstBuyDate: string;
|
firstBuyDate: string;
|
||||||
grossPerformance?: number;
|
grossPerformance?: number;
|
||||||
grossPerformancePercentage?: number;
|
grossPerformancePercentage?: number;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { Currency, DataSource } from '@prisma/client';
|
import { DataSource } from '@prisma/client';
|
||||||
import Big from 'big.js';
|
import Big from 'big.js';
|
||||||
|
|
||||||
export interface TimelinePosition {
|
export interface TimelinePosition {
|
||||||
averagePrice: Big;
|
averagePrice: Big;
|
||||||
currency: Currency;
|
currency: string;
|
||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
firstBuyDate: string;
|
firstBuyDate: string;
|
||||||
grossPerformance: Big;
|
grossPerformance: Big;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Currency, ViewMode } from '@prisma/client';
|
import { ViewMode } from '@prisma/client';
|
||||||
|
|
||||||
export interface UserSettings {
|
export interface UserSettings {
|
||||||
baseCurrency?: Currency;
|
baseCurrency?: string;
|
||||||
isRestrictedView?: boolean;
|
isRestrictedView?: boolean;
|
||||||
locale: string;
|
locale: string;
|
||||||
viewMode?: ViewMode;
|
viewMode?: ViewMode;
|
||||||
|
@ -11,7 +11,6 @@ import {
|
|||||||
import { UNKNOWN_KEY } from '@ghostfolio/common/config';
|
import { UNKNOWN_KEY } from '@ghostfolio/common/config';
|
||||||
import { getTextColor } from '@ghostfolio/common/helper';
|
import { getTextColor } from '@ghostfolio/common/helper';
|
||||||
import { PortfolioPosition } from '@ghostfolio/common/interfaces';
|
import { PortfolioPosition } from '@ghostfolio/common/interfaces';
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
import { Tooltip } from 'chart.js';
|
import { Tooltip } from 'chart.js';
|
||||||
import { LinearScale } from 'chart.js';
|
import { LinearScale } from 'chart.js';
|
||||||
import { ArcElement } from 'chart.js';
|
import { ArcElement } from 'chart.js';
|
||||||
@ -29,7 +28,7 @@ import * as Color from 'color';
|
|||||||
export class PortfolioProportionChartComponent
|
export class PortfolioProportionChartComponent
|
||||||
implements AfterViewInit, OnChanges, OnDestroy
|
implements AfterViewInit, OnChanges, OnDestroy
|
||||||
{
|
{
|
||||||
@Input() baseCurrency: Currency;
|
@Input() baseCurrency: string;
|
||||||
@Input() isInPercent = false;
|
@Input() isInPercent = false;
|
||||||
@Input() keys: string[] = [];
|
@Input() keys: string[] = [];
|
||||||
@Input() locale = '';
|
@Input() locale = '';
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Account" ALTER COLUMN "currency" TYPE TEXT;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Order" ALTER COLUMN "currency" TYPE TEXT;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Settings" ALTER COLUMN "currency" TYPE TEXT;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "SymbolProfile" ALTER COLUMN "currency" TYPE TEXT;
|
||||||
|
|
||||||
|
-- DropEnum
|
||||||
|
DROP TYPE "Currency" CASCADE;
|
@ -28,7 +28,7 @@ model Account {
|
|||||||
accountType AccountType @default(SECURITIES)
|
accountType AccountType @default(SECURITIES)
|
||||||
balance Float @default(0)
|
balance Float @default(0)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
currency Currency @default(USD)
|
currency String?
|
||||||
id String @default(uuid())
|
id String @default(uuid())
|
||||||
isDefault Boolean @default(false)
|
isDefault Boolean @default(false)
|
||||||
name String?
|
name String?
|
||||||
@ -77,7 +77,7 @@ model Order {
|
|||||||
accountId String?
|
accountId String?
|
||||||
accountUserId String?
|
accountUserId String?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
currency Currency?
|
currency String?
|
||||||
dataSource DataSource
|
dataSource DataSource
|
||||||
date DateTime
|
date DateTime
|
||||||
fee Float
|
fee Float
|
||||||
@ -109,7 +109,7 @@ model Property {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model Settings {
|
model Settings {
|
||||||
currency Currency?
|
currency String?
|
||||||
settings Json?
|
settings Json?
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
viewMode ViewMode?
|
viewMode ViewMode?
|
||||||
@ -122,7 +122,7 @@ model SymbolProfile {
|
|||||||
assetSubClass AssetSubClass?
|
assetSubClass AssetSubClass?
|
||||||
countries Json?
|
countries Json?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
currency Currency?
|
currency String?
|
||||||
dataSource DataSource
|
dataSource DataSource
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
name String?
|
name String?
|
||||||
@ -182,13 +182,6 @@ enum AssetSubClass {
|
|||||||
STOCK
|
STOCK
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Currency {
|
|
||||||
CHF
|
|
||||||
EUR
|
|
||||||
GBP
|
|
||||||
USD
|
|
||||||
}
|
|
||||||
|
|
||||||
enum DataSource {
|
enum DataSource {
|
||||||
ALPHA_VANTAGE
|
ALPHA_VANTAGE
|
||||||
GHOSTFOLIO
|
GHOSTFOLIO
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
AccountType,
|
AccountType,
|
||||||
Currency,
|
|
||||||
DataSource,
|
DataSource,
|
||||||
PrismaClient,
|
PrismaClient,
|
||||||
Role,
|
Role,
|
||||||
@ -88,7 +87,7 @@ async function main() {
|
|||||||
{
|
{
|
||||||
accountType: AccountType.SECURITIES,
|
accountType: AccountType.SECURITIES,
|
||||||
balance: 0,
|
balance: 0,
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
id: 'f4425b66-9ba9-4ac4-93d7-fdf9a145e8cb',
|
id: 'f4425b66-9ba9-4ac4-93d7-fdf9a145e8cb',
|
||||||
isDefault: true,
|
isDefault: true,
|
||||||
name: 'Default Account'
|
name: 'Default Account'
|
||||||
@ -112,7 +111,7 @@ async function main() {
|
|||||||
{
|
{
|
||||||
accountType: AccountType.SECURITIES,
|
accountType: AccountType.SECURITIES,
|
||||||
balance: 0,
|
balance: 0,
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
id: 'd804de69-0429-42dc-b6ca-b308fd7dd926',
|
id: 'd804de69-0429-42dc-b6ca-b308fd7dd926',
|
||||||
name: 'Coinbase Account',
|
name: 'Coinbase Account',
|
||||||
platformId: platformCoinbase.id
|
platformId: platformCoinbase.id
|
||||||
@ -120,7 +119,7 @@ async function main() {
|
|||||||
{
|
{
|
||||||
accountType: AccountType.SECURITIES,
|
accountType: AccountType.SECURITIES,
|
||||||
balance: 0,
|
balance: 0,
|
||||||
currency: Currency.EUR,
|
currency: 'EUR',
|
||||||
id: '65cfb79d-b6c7-4591-9d46-73426bc62094',
|
id: '65cfb79d-b6c7-4591-9d46-73426bc62094',
|
||||||
name: 'DEGIRO Account',
|
name: 'DEGIRO Account',
|
||||||
platformId: platformDegiro.id
|
platformId: platformDegiro.id
|
||||||
@ -128,7 +127,7 @@ async function main() {
|
|||||||
{
|
{
|
||||||
accountType: AccountType.SECURITIES,
|
accountType: AccountType.SECURITIES,
|
||||||
balance: 0,
|
balance: 0,
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
id: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c',
|
id: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c',
|
||||||
isDefault: true,
|
isDefault: true,
|
||||||
name: 'Interactive Brokers Account',
|
name: 'Interactive Brokers Account',
|
||||||
@ -201,7 +200,7 @@ async function main() {
|
|||||||
{
|
{
|
||||||
accountId: '65cfb79d-b6c7-4591-9d46-73426bc62094',
|
accountId: '65cfb79d-b6c7-4591-9d46-73426bc62094',
|
||||||
accountUserId: userDemo.id,
|
accountUserId: userDemo.id,
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
date: new Date(Date.UTC(2017, 0, 3, 0, 0, 0)),
|
date: new Date(Date.UTC(2017, 0, 3, 0, 0, 0)),
|
||||||
fee: 30,
|
fee: 30,
|
||||||
@ -216,7 +215,7 @@ async function main() {
|
|||||||
{
|
{
|
||||||
accountId: 'd804de69-0429-42dc-b6ca-b308fd7dd926',
|
accountId: 'd804de69-0429-42dc-b6ca-b308fd7dd926',
|
||||||
accountUserId: userDemo.id,
|
accountUserId: userDemo.id,
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
date: new Date(Date.UTC(2017, 7, 16, 0, 0, 0)),
|
date: new Date(Date.UTC(2017, 7, 16, 0, 0, 0)),
|
||||||
fee: 29.9,
|
fee: 29.9,
|
||||||
@ -231,7 +230,7 @@ async function main() {
|
|||||||
{
|
{
|
||||||
accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c',
|
accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c',
|
||||||
accountUserId: userDemo.id,
|
accountUserId: userDemo.id,
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
date: new Date(Date.UTC(2018, 9, 1, 0, 0, 0)),
|
date: new Date(Date.UTC(2018, 9, 1, 0, 0, 0)),
|
||||||
fee: 80.79,
|
fee: 80.79,
|
||||||
@ -246,7 +245,7 @@ async function main() {
|
|||||||
{
|
{
|
||||||
accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c',
|
accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c',
|
||||||
accountUserId: userDemo.id,
|
accountUserId: userDemo.id,
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
date: new Date(Date.UTC(2019, 2, 1, 0, 0, 0)),
|
date: new Date(Date.UTC(2019, 2, 1, 0, 0, 0)),
|
||||||
fee: 19.9,
|
fee: 19.9,
|
||||||
@ -261,7 +260,7 @@ async function main() {
|
|||||||
{
|
{
|
||||||
accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c',
|
accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c',
|
||||||
accountUserId: userDemo.id,
|
accountUserId: userDemo.id,
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
date: new Date(Date.UTC(2019, 8, 3, 0, 0, 0)),
|
date: new Date(Date.UTC(2019, 8, 3, 0, 0, 0)),
|
||||||
fee: 19.9,
|
fee: 19.9,
|
||||||
@ -276,7 +275,7 @@ async function main() {
|
|||||||
{
|
{
|
||||||
accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c',
|
accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c',
|
||||||
accountUserId: userDemo.id,
|
accountUserId: userDemo.id,
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
date: new Date(Date.UTC(2020, 2, 2, 0, 0, 0)),
|
date: new Date(Date.UTC(2020, 2, 2, 0, 0, 0)),
|
||||||
fee: 19.9,
|
fee: 19.9,
|
||||||
@ -291,7 +290,7 @@ async function main() {
|
|||||||
{
|
{
|
||||||
accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c',
|
accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c',
|
||||||
accountUserId: userDemo.id,
|
accountUserId: userDemo.id,
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
date: new Date(Date.UTC(2020, 8, 1, 0, 0, 0)),
|
date: new Date(Date.UTC(2020, 8, 1, 0, 0, 0)),
|
||||||
fee: 19.9,
|
fee: 19.9,
|
||||||
@ -306,7 +305,7 @@ async function main() {
|
|||||||
{
|
{
|
||||||
accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c',
|
accountId: '480269ce-e12a-4fd1-ac88-c4b0ff3f899c',
|
||||||
accountUserId: userDemo.id,
|
accountUserId: userDemo.id,
|
||||||
currency: Currency.USD,
|
currency: 'USD',
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
date: new Date(Date.UTC(2020, 2, 1, 0, 0, 0)),
|
date: new Date(Date.UTC(2020, 2, 1, 0, 0, 0)),
|
||||||
fee: 19.9,
|
fee: 19.9,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user