Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
86a1589834 | |||
9f67993c03 | |||
32fb3551dc | |||
30411b1502 | |||
eb0444603b | |||
6e582fe505 | |||
402d73a12c | |||
4826a51199 | |||
5356bf568e | |||
d8da574ae4 | |||
e769fabbae | |||
5a369f29d4 | |||
122ba9046f |
37
CHANGELOG.md
37
CHANGELOG.md
@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## 1.128.0 - 19.03.2022
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added the attribute `defaultMarketPrice` to the scraper configuration to improve the support for bonds
|
||||||
|
- Added a hover effect to the table style
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed an issue with the user currency of the public page
|
||||||
|
- Fixed an issue of the performance calculation with recent activities in the new calculation engine
|
||||||
|
|
||||||
|
## 1.127.0 - 16.03.2022
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Improved the error handling in the scraper configuration
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed the support for multiple symbols of the data source `GHOSTFOLIO`
|
||||||
|
|
||||||
|
## 1.126.0 - 14.03.2022
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added support for bonds
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Restructured the portfolio summary tab on the home page
|
||||||
|
- Improved the tooltips in the portfolio proportion chart component by introducing multilines
|
||||||
|
|
||||||
|
### Todo
|
||||||
|
|
||||||
|
- Apply data migration (`yarn database:migrate`)
|
||||||
|
|
||||||
## 1.125.0 - 12.03.2022
|
## 1.125.0 - 12.03.2022
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -37,6 +37,9 @@ import { TransactionPointSymbol } from './interfaces/transaction-point-symbol.in
|
|||||||
import { TransactionPoint } from './interfaces/transaction-point.interface';
|
import { TransactionPoint } from './interfaces/transaction-point.interface';
|
||||||
|
|
||||||
export class PortfolioCalculatorNew {
|
export class PortfolioCalculatorNew {
|
||||||
|
private static readonly CALCULATE_PERCENTAGE_PERFORMANCE_WITH_MAX_INVESTMENT =
|
||||||
|
true;
|
||||||
|
|
||||||
private static readonly ENABLE_LOGGING = false;
|
private static readonly ENABLE_LOGGING = false;
|
||||||
|
|
||||||
private currency: string;
|
private currency: string;
|
||||||
@ -688,6 +691,7 @@ export class PortfolioCalculatorNew {
|
|||||||
let grossPerformanceAtStartDate = new Big(0);
|
let grossPerformanceAtStartDate = new Big(0);
|
||||||
let grossPerformanceFromSells = new Big(0);
|
let grossPerformanceFromSells = new Big(0);
|
||||||
let initialValue: Big;
|
let initialValue: Big;
|
||||||
|
let investmentAtStartDate: Big;
|
||||||
let lastAveragePrice = new Big(0);
|
let lastAveragePrice = new Big(0);
|
||||||
let lastTransactionInvestment = new Big(0);
|
let lastTransactionInvestment = new Big(0);
|
||||||
let lastValueOfInvestmentBeforeTransaction = new Big(0);
|
let lastValueOfInvestmentBeforeTransaction = new Big(0);
|
||||||
@ -697,6 +701,7 @@ export class PortfolioCalculatorNew {
|
|||||||
let totalInvestment = new Big(0);
|
let totalInvestment = new Big(0);
|
||||||
let totalInvestmentWithGrossPerformanceFromSell = new Big(0);
|
let totalInvestmentWithGrossPerformanceFromSell = new Big(0);
|
||||||
let totalUnits = new Big(0);
|
let totalUnits = new Big(0);
|
||||||
|
let valueAtStartDate: Big;
|
||||||
|
|
||||||
// Add a synthetic order at the start and the end date
|
// Add a synthetic order at the start and the end date
|
||||||
orders.push({
|
orders.push({
|
||||||
@ -774,13 +779,18 @@ export class PortfolioCalculatorNew {
|
|||||||
order.unitPrice
|
order.unitPrice
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!investmentAtStartDate && i >= indexOfStartOrder) {
|
||||||
|
investmentAtStartDate = totalInvestment ?? new Big(0);
|
||||||
|
valueAtStartDate = valueOfInvestmentBeforeTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
const transactionInvestment = order.quantity
|
const transactionInvestment = order.quantity
|
||||||
.mul(order.unitPrice)
|
.mul(order.unitPrice)
|
||||||
.mul(this.getFactor(order.type));
|
.mul(this.getFactor(order.type));
|
||||||
|
|
||||||
totalInvestment = totalInvestment.plus(transactionInvestment);
|
totalInvestment = totalInvestment.plus(transactionInvestment);
|
||||||
|
|
||||||
if (totalInvestment.gt(maxTotalInvestment)) {
|
if (i >= indexOfStartOrder && totalInvestment.gt(maxTotalInvestment)) {
|
||||||
maxTotalInvestment = totalInvestment;
|
maxTotalInvestment = totalInvestment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -898,12 +908,22 @@ export class PortfolioCalculatorNew {
|
|||||||
.minus(grossPerformanceAtStartDate)
|
.minus(grossPerformanceAtStartDate)
|
||||||
.minus(fees.minus(feesAtStartDate));
|
.minus(fees.minus(feesAtStartDate));
|
||||||
|
|
||||||
|
const maxInvestmentBetweenStartAndEndDate = valueAtStartDate.plus(
|
||||||
|
maxTotalInvestment.minus(investmentAtStartDate)
|
||||||
|
);
|
||||||
|
|
||||||
const grossPerformancePercentage =
|
const grossPerformancePercentage =
|
||||||
|
PortfolioCalculatorNew.CALCULATE_PERCENTAGE_PERFORMANCE_WITH_MAX_INVESTMENT ||
|
||||||
averagePriceAtStartDate.eq(0) ||
|
averagePriceAtStartDate.eq(0) ||
|
||||||
averagePriceAtEndDate.eq(0) ||
|
averagePriceAtEndDate.eq(0) ||
|
||||||
orders[indexOfStartOrder].unitPrice.eq(0)
|
orders[indexOfStartOrder].unitPrice.eq(0)
|
||||||
? totalGrossPerformance.div(maxTotalInvestment)
|
? maxInvestmentBetweenStartAndEndDate.gt(0)
|
||||||
: unitPriceAtEndDate
|
? totalGrossPerformance.div(maxInvestmentBetweenStartAndEndDate)
|
||||||
|
: new Big(0)
|
||||||
|
: // This formula has the issue that buying more units with a price
|
||||||
|
// lower than the average buying price results in a positive
|
||||||
|
// performance even if the market price stays constant
|
||||||
|
unitPriceAtEndDate
|
||||||
.div(averagePriceAtEndDate)
|
.div(averagePriceAtEndDate)
|
||||||
.div(
|
.div(
|
||||||
orders[indexOfStartOrder].unitPrice.div(averagePriceAtStartDate)
|
orders[indexOfStartOrder].unitPrice.div(averagePriceAtStartDate)
|
||||||
@ -915,11 +935,17 @@ export class PortfolioCalculatorNew {
|
|||||||
: new Big(0);
|
: new Big(0);
|
||||||
|
|
||||||
const netPerformancePercentage =
|
const netPerformancePercentage =
|
||||||
|
PortfolioCalculatorNew.CALCULATE_PERCENTAGE_PERFORMANCE_WITH_MAX_INVESTMENT ||
|
||||||
averagePriceAtStartDate.eq(0) ||
|
averagePriceAtStartDate.eq(0) ||
|
||||||
averagePriceAtEndDate.eq(0) ||
|
averagePriceAtEndDate.eq(0) ||
|
||||||
orders[indexOfStartOrder].unitPrice.eq(0)
|
orders[indexOfStartOrder].unitPrice.eq(0)
|
||||||
? totalNetPerformance.div(maxTotalInvestment)
|
? maxInvestmentBetweenStartAndEndDate.gt(0)
|
||||||
: unitPriceAtEndDate
|
? totalNetPerformance.div(maxInvestmentBetweenStartAndEndDate)
|
||||||
|
: new Big(0)
|
||||||
|
: // This formula has the issue that buying more units with a price
|
||||||
|
// lower than the average buying price results in a positive
|
||||||
|
// performance even if the market price stays constant
|
||||||
|
unitPriceAtEndDate
|
||||||
.minus(feesPerUnit)
|
.minus(feesPerUnit)
|
||||||
.div(averagePriceAtEndDate)
|
.div(averagePriceAtEndDate)
|
||||||
.div(
|
.div(
|
||||||
|
@ -307,7 +307,10 @@ export class PortfolioServiceNew {
|
|||||||
const emergencyFund = new Big(
|
const emergencyFund = new Big(
|
||||||
(user.Settings?.settings as UserSettings)?.emergencyFund ?? 0
|
(user.Settings?.settings as UserSettings)?.emergencyFund ?? 0
|
||||||
);
|
);
|
||||||
const userCurrency = this.request.user?.Settings?.currency ?? baseCurrency;
|
const userCurrency =
|
||||||
|
this.request.user?.Settings?.currency ??
|
||||||
|
user.Settings?.currency ??
|
||||||
|
baseCurrency;
|
||||||
|
|
||||||
const { orders, portfolioOrders, transactionPoints } =
|
const { orders, portfolioOrders, transactionPoints } =
|
||||||
await this.getTransactionPoints({
|
await this.getTransactionPoints({
|
||||||
|
@ -298,7 +298,10 @@ export class PortfolioService {
|
|||||||
const emergencyFund = new Big(
|
const emergencyFund = new Big(
|
||||||
(user.Settings?.settings as UserSettings)?.emergencyFund ?? 0
|
(user.Settings?.settings as UserSettings)?.emergencyFund ?? 0
|
||||||
);
|
);
|
||||||
const userCurrency = this.request.user?.Settings?.currency ?? baseCurrency;
|
const userCurrency =
|
||||||
|
this.request.user?.Settings?.currency ??
|
||||||
|
user.Settings?.currency ??
|
||||||
|
baseCurrency;
|
||||||
const portfolioCalculator = new PortfolioCalculator(
|
const portfolioCalculator = new PortfolioCalculator(
|
||||||
this.currentRateService,
|
this.currentRateService,
|
||||||
userCurrency
|
userCurrency
|
||||||
|
@ -13,7 +13,7 @@ import { Injectable, Logger } from '@nestjs/common';
|
|||||||
import { DataSource, SymbolProfile } from '@prisma/client';
|
import { DataSource, SymbolProfile } from '@prisma/client';
|
||||||
import * as bent from 'bent';
|
import * as bent from 'bent';
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
import { format } from 'date-fns';
|
import { addDays, format, isBefore } from 'date-fns';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GhostfolioScraperApiService implements DataProviderInterface {
|
export class GhostfolioScraperApiService implements DataProviderInterface {
|
||||||
@ -50,16 +50,36 @@ export class GhostfolioScraperApiService implements DataProviderInterface {
|
|||||||
const [symbolProfile] = await this.symbolProfileService.getSymbolProfiles(
|
const [symbolProfile] = await this.symbolProfileService.getSymbolProfiles(
|
||||||
[symbol]
|
[symbol]
|
||||||
);
|
);
|
||||||
const scraperConfiguration = symbolProfile?.scraperConfiguration;
|
const { defaultMarketPrice, selector, url } =
|
||||||
|
symbolProfile.scraperConfiguration;
|
||||||
|
|
||||||
const get = bent(scraperConfiguration?.url, 'GET', 'string', 200, {});
|
if (defaultMarketPrice) {
|
||||||
|
const historical: {
|
||||||
|
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse };
|
||||||
|
} = {
|
||||||
|
[symbol]: {}
|
||||||
|
};
|
||||||
|
let date = from;
|
||||||
|
|
||||||
|
while (isBefore(date, to)) {
|
||||||
|
historical[symbol][format(date, DATE_FORMAT)] = {
|
||||||
|
marketPrice: defaultMarketPrice
|
||||||
|
};
|
||||||
|
|
||||||
|
date = addDays(date, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return historical;
|
||||||
|
} else if (selector === undefined || url === undefined) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const get = bent(url, 'GET', 'string', 200, {});
|
||||||
|
|
||||||
const html = await get();
|
const html = await get();
|
||||||
const $ = cheerio.load(html);
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
const value = this.extractNumberFromString(
|
const value = this.extractNumberFromString($(selector).text());
|
||||||
$(scraperConfiguration?.selector).text()
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
[symbol]: {
|
[symbol]: {
|
||||||
@ -82,33 +102,42 @@ export class GhostfolioScraperApiService implements DataProviderInterface {
|
|||||||
public async getQuotes(
|
public async getQuotes(
|
||||||
aSymbols: string[]
|
aSymbols: string[]
|
||||||
): Promise<{ [symbol: string]: IDataProviderResponse }> {
|
): Promise<{ [symbol: string]: IDataProviderResponse }> {
|
||||||
|
const response: { [symbol: string]: IDataProviderResponse } = {};
|
||||||
|
|
||||||
if (aSymbols.length <= 0) {
|
if (aSymbols.length <= 0) {
|
||||||
return {};
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [symbol] = aSymbols;
|
const symbolProfiles = await this.symbolProfileService.getSymbolProfiles(
|
||||||
const [symbolProfile] = await this.symbolProfileService.getSymbolProfiles(
|
aSymbols
|
||||||
[symbol]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const { marketPrice } = await this.prismaService.marketData.findFirst({
|
const marketData = await this.prismaService.marketData.findMany({
|
||||||
|
distinct: ['symbol'],
|
||||||
orderBy: {
|
orderBy: {
|
||||||
date: 'desc'
|
date: 'desc'
|
||||||
},
|
},
|
||||||
|
take: aSymbols.length,
|
||||||
where: {
|
where: {
|
||||||
symbol
|
symbol: {
|
||||||
|
in: aSymbols
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
for (const symbolProfile of symbolProfiles) {
|
||||||
[symbol]: {
|
response[symbolProfile.symbol] = {
|
||||||
marketPrice,
|
currency: symbolProfile.currency,
|
||||||
currency: symbolProfile?.currency,
|
|
||||||
dataSource: this.getName(),
|
dataSource: this.getName(),
|
||||||
|
marketPrice: marketData.find((marketDataItem) => {
|
||||||
|
return marketDataItem.symbol === symbolProfile.symbol;
|
||||||
|
}).marketPrice,
|
||||||
marketState: MarketState.delayed
|
marketState: MarketState.delayed
|
||||||
}
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.error(error, 'GhostfolioScraperApiService');
|
Logger.error(error, 'GhostfolioScraperApiService');
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export interface ScraperConfiguration {
|
export interface ScraperConfiguration {
|
||||||
|
defaultMarketPrice?: number;
|
||||||
selector: string;
|
selector: string;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import Big from 'big.js';
|
|||||||
import { countries } from 'countries-list';
|
import { countries } from 'countries-list';
|
||||||
import { addDays, format, isSameDay } from 'date-fns';
|
import { addDays, format, isSameDay } from 'date-fns';
|
||||||
import yahooFinance from 'yahoo-finance2';
|
import yahooFinance from 'yahoo-finance2';
|
||||||
|
import type { Price } from 'yahoo-finance2/dist/esm/src/modules/quoteSummary-iface';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class YahooFinanceService implements DataProviderInterface {
|
export class YahooFinanceService implements DataProviderInterface {
|
||||||
@ -303,7 +304,7 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
return { items };
|
return { items };
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseAssetClass(aPrice: any): {
|
private parseAssetClass(aPrice: Price): {
|
||||||
assetClass: AssetClass;
|
assetClass: AssetClass;
|
||||||
assetSubClass: AssetSubClass;
|
assetSubClass: AssetSubClass;
|
||||||
} {
|
} {
|
||||||
|
@ -79,6 +79,7 @@ export class SymbolProfileService {
|
|||||||
|
|
||||||
if (scraperConfiguration) {
|
if (scraperConfiguration) {
|
||||||
return {
|
return {
|
||||||
|
defaultMarketPrice: scraperConfiguration.defaultMarketPrice as number,
|
||||||
selector: scraperConfiguration.selector as string,
|
selector: scraperConfiguration.selector as string,
|
||||||
url: scraperConfiguration.url as string
|
url: scraperConfiguration.url as string
|
||||||
};
|
};
|
||||||
|
@ -119,7 +119,7 @@
|
|||||||
<div class="col"><hr /></div>
|
<div class="col"><hr /></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row px-3 py-1">
|
<div class="row px-3 py-1">
|
||||||
<div class="d-flex flex-grow-1" i18n>Value</div>
|
<div class="d-flex flex-grow-1" i18n>Total</div>
|
||||||
<div class="d-flex flex-column flex-wrap justify-content-end">
|
<div class="d-flex flex-column flex-wrap justify-content-end">
|
||||||
<gf-value
|
<gf-value
|
||||||
class="justify-content-end"
|
class="justify-content-end"
|
||||||
@ -130,6 +130,17 @@
|
|||||||
></gf-value>
|
></gf-value>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row px-3 py-1">
|
||||||
|
<div class="d-flex flex-grow-1" i18n>Valuables</div>
|
||||||
|
<div class="d-flex justify-content-end">
|
||||||
|
<gf-value
|
||||||
|
class="justify-content-end"
|
||||||
|
[currency]="baseCurrency"
|
||||||
|
[locale]="locale"
|
||||||
|
[value]="isLoading ? undefined : summary?.items"
|
||||||
|
></gf-value>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row px-3 py-1">
|
<div class="row px-3 py-1">
|
||||||
<div class="d-flex flex-grow-1" i18n>Emergency Fund</div>
|
<div class="d-flex flex-grow-1" i18n>Emergency Fund</div>
|
||||||
<div
|
<div
|
||||||
@ -151,7 +162,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row px-3 py-1">
|
<div class="row px-3 py-1">
|
||||||
<div class="d-flex flex-grow-1" i18n>Cash (Buying Power)</div>
|
<div class="d-flex flex-grow-1" i18n>Buying Power</div>
|
||||||
<div class="d-flex justify-content-end">
|
<div class="d-flex justify-content-end">
|
||||||
<gf-value
|
<gf-value
|
||||||
class="justify-content-end"
|
class="justify-content-end"
|
||||||
@ -161,17 +172,6 @@
|
|||||||
></gf-value>
|
></gf-value>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row px-3 py-1">
|
|
||||||
<div class="d-flex flex-grow-1" i18n>Items</div>
|
|
||||||
<div class="d-flex justify-content-end">
|
|
||||||
<gf-value
|
|
||||||
class="justify-content-end"
|
|
||||||
[currency]="baseCurrency"
|
|
||||||
[locale]="locale"
|
|
||||||
[value]="isLoading ? undefined : summary?.items"
|
|
||||||
></gf-value>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col"><hr /></div>
|
<div class="col"><hr /></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,20 +11,22 @@
|
|||||||
|
|
||||||
.mat-row {
|
.mat-row {
|
||||||
&:nth-child(even) {
|
&:nth-child(even) {
|
||||||
background-color: rgba(
|
background-color: rgba(var(--palette-foreground-base), 0.02);
|
||||||
var(--palette-foreground-base),
|
}
|
||||||
var(--palette-background-hover-alpha)
|
|
||||||
);
|
&:hover {
|
||||||
|
background-color: rgba(var(--palette-foreground-base), 0.05);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@if $darkTheme {
|
@if $darkTheme {
|
||||||
.mat-row {
|
.mat-row {
|
||||||
&:nth-child(even) {
|
&:nth-child(even) {
|
||||||
background-color: rgba(
|
background-color: rgba(var(--palette-foreground-base-dark), 0.02);
|
||||||
var(--palette-foreground-base-dark),
|
}
|
||||||
var(--palette-background-hover-alpha)
|
|
||||||
);
|
&:hover {
|
||||||
|
background-color: rgba(var(--palette-foreground-base-dark), 0.05);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,16 +324,16 @@ export class PortfolioProportionChartComponent
|
|||||||
const percentage = (context.parsed * 100) / sum;
|
const percentage = (context.parsed * 100) / sum;
|
||||||
|
|
||||||
if (this.isInPercent) {
|
if (this.isInPercent) {
|
||||||
return `${name ?? symbol} (${percentage.toFixed(2)}%)`;
|
return [`${name ?? symbol}`, `${percentage.toFixed(2)}%`];
|
||||||
} else {
|
} else {
|
||||||
const value = <number>context.raw;
|
const value = <number>context.raw;
|
||||||
return `${name ?? symbol}: ${value.toLocaleString(
|
return [
|
||||||
this.locale,
|
`${name ?? symbol}`,
|
||||||
{
|
`${value.toLocaleString(this.locale, {
|
||||||
maximumFractionDigits: 2,
|
maximumFractionDigits: 2,
|
||||||
minimumFractionDigits: 2
|
minimumFractionDigits: 2
|
||||||
}
|
})} ${this.baseCurrency} (${percentage.toFixed(2)}%)`
|
||||||
)} ${this.baseCurrency} (${percentage.toFixed(2)}%)`;
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ghostfolio",
|
"name": "ghostfolio",
|
||||||
"version": "1.125.0",
|
"version": "1.128.0",
|
||||||
"homepage": "https://ghostfol.io",
|
"homepage": "https://ghostfol.io",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterEnum
|
||||||
|
ALTER TYPE "AssetClass" ADD VALUE 'FIXED_INCOME';
|
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterEnum
|
||||||
|
ALTER TYPE "AssetSubClass" ADD VALUE 'BOND';
|
@ -171,9 +171,11 @@ enum AssetClass {
|
|||||||
CASH
|
CASH
|
||||||
COMMODITY
|
COMMODITY
|
||||||
EQUITY
|
EQUITY
|
||||||
|
FIXED_INCOME
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AssetSubClass {
|
enum AssetSubClass {
|
||||||
|
BOND
|
||||||
CRYPTOCURRENCY
|
CRYPTOCURRENCY
|
||||||
ETF
|
ETF
|
||||||
MUTUALFUND
|
MUTUALFUND
|
||||||
|
Reference in New Issue
Block a user