parent
b932bac9aa
commit
4ab3f81384
@ -19,7 +19,7 @@ import {
|
||||
Order,
|
||||
Prisma,
|
||||
Tag,
|
||||
Type as TypeOfOrder
|
||||
Type as ActivityType
|
||||
} from '@prisma/client';
|
||||
import Big from 'big.js';
|
||||
import { endOfToday, isAfter } from 'date-fns';
|
||||
@ -229,7 +229,7 @@ export class OrderService {
|
||||
sortColumn?: string;
|
||||
sortDirection?: Prisma.SortOrder;
|
||||
take?: number;
|
||||
types?: TypeOfOrder[];
|
||||
types?: ActivityType[];
|
||||
userCurrency: string;
|
||||
userId: string;
|
||||
withExcludedAccounts?: boolean;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { DataSource, Tag, Type as TypeOfOrder } from '@prisma/client';
|
||||
import { DataSource, Tag, Type as ActivityType } from '@prisma/client';
|
||||
import Big from 'big.js';
|
||||
|
||||
export interface PortfolioOrder {
|
||||
@ -10,6 +10,6 @@ export interface PortfolioOrder {
|
||||
quantity: Big;
|
||||
symbol: string;
|
||||
tags?: Tag[];
|
||||
type: TypeOfOrder;
|
||||
type: ActivityType;
|
||||
unitPrice: Big;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { getFactor } from '@ghostfolio/api/helper/portfolio.helper';
|
||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
|
||||
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
|
||||
import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
|
||||
@ -12,7 +13,6 @@ import {
|
||||
import { GroupBy } from '@ghostfolio/common/types';
|
||||
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { Type as TypeOfOrder } from '@prisma/client';
|
||||
import Big from 'big.js';
|
||||
import {
|
||||
addDays,
|
||||
@ -76,7 +76,7 @@ export class PortfolioCalculator {
|
||||
let currentTransactionPointItem: TransactionPointSymbol;
|
||||
const oldAccumulatedSymbol = symbols[order.symbol];
|
||||
|
||||
const factor = this.getFactor(order.type);
|
||||
const factor = getFactor(order.type);
|
||||
const unitPrice = new Big(order.unitPrice);
|
||||
if (oldAccumulatedSymbol) {
|
||||
const newQuantity = order.quantity
|
||||
@ -820,25 +820,6 @@ export class PortfolioCalculator {
|
||||
};
|
||||
}
|
||||
|
||||
private getFactor(type: TypeOfOrder) {
|
||||
let factor: number;
|
||||
|
||||
switch (type) {
|
||||
case 'BUY':
|
||||
case 'ITEM':
|
||||
factor = 1;
|
||||
break;
|
||||
case 'SELL':
|
||||
factor = -1;
|
||||
break;
|
||||
default:
|
||||
factor = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return factor;
|
||||
}
|
||||
|
||||
private getSymbolMetrics({
|
||||
end,
|
||||
exchangeRates,
|
||||
@ -989,7 +970,7 @@ export class PortfolioCalculator {
|
||||
itemType: 'start',
|
||||
name: '',
|
||||
quantity: new Big(0),
|
||||
type: TypeOfOrder.BUY,
|
||||
type: 'BUY',
|
||||
unitPrice: unitPriceAtStartDate
|
||||
});
|
||||
|
||||
@ -1003,7 +984,7 @@ export class PortfolioCalculator {
|
||||
itemType: 'end',
|
||||
name: '',
|
||||
quantity: new Big(0),
|
||||
type: TypeOfOrder.BUY,
|
||||
type: 'BUY',
|
||||
unitPrice: unitPriceAtEndDate
|
||||
});
|
||||
|
||||
@ -1030,7 +1011,7 @@ export class PortfolioCalculator {
|
||||
feeInBaseCurrency: new Big(0),
|
||||
name: '',
|
||||
quantity: new Big(0),
|
||||
type: TypeOfOrder.BUY,
|
||||
type: 'BUY',
|
||||
unitPrice:
|
||||
marketSymbolMap[format(day, DATE_FORMAT)]?.[symbol] ??
|
||||
lastUnitPrice
|
||||
@ -1131,24 +1112,24 @@ export class PortfolioCalculator {
|
||||
order.type === 'BUY'
|
||||
? order.quantity
|
||||
.mul(order.unitPriceInBaseCurrency)
|
||||
.mul(this.getFactor(order.type))
|
||||
.mul(getFactor(order.type))
|
||||
: totalUnits.gt(0)
|
||||
? totalInvestment
|
||||
.div(totalUnits)
|
||||
.mul(order.quantity)
|
||||
.mul(this.getFactor(order.type))
|
||||
.mul(getFactor(order.type))
|
||||
: new Big(0);
|
||||
|
||||
const transactionInvestmentWithCurrencyEffect =
|
||||
order.type === 'BUY'
|
||||
? order.quantity
|
||||
.mul(order.unitPriceInBaseCurrencyWithCurrencyEffect)
|
||||
.mul(this.getFactor(order.type))
|
||||
.mul(getFactor(order.type))
|
||||
: totalUnits.gt(0)
|
||||
? totalInvestmentWithCurrencyEffect
|
||||
.div(totalUnits)
|
||||
.mul(order.quantity)
|
||||
.mul(this.getFactor(order.type))
|
||||
.mul(getFactor(order.type))
|
||||
: new Big(0);
|
||||
|
||||
if (PortfolioCalculator.ENABLE_LOGGING) {
|
||||
@ -1203,9 +1184,7 @@ export class PortfolioCalculator {
|
||||
order.feeInBaseCurrencyWithCurrencyEffect ?? 0
|
||||
);
|
||||
|
||||
totalUnits = totalUnits.plus(
|
||||
order.quantity.mul(this.getFactor(order.type))
|
||||
);
|
||||
totalUnits = totalUnits.plus(order.quantity.mul(getFactor(order.type)));
|
||||
|
||||
const valueOfInvestment = totalUnits.mul(order.unitPriceInBaseCurrency);
|
||||
|
||||
@ -1214,14 +1193,14 @@ export class PortfolioCalculator {
|
||||
);
|
||||
|
||||
const grossPerformanceFromSell =
|
||||
order.type === TypeOfOrder.SELL
|
||||
order.type === 'SELL'
|
||||
? order.unitPriceInBaseCurrency
|
||||
.minus(lastAveragePrice)
|
||||
.mul(order.quantity)
|
||||
: new Big(0);
|
||||
|
||||
const grossPerformanceFromSellWithCurrencyEffect =
|
||||
order.type === TypeOfOrder.SELL
|
||||
order.type === 'SELL'
|
||||
? order.unitPriceInBaseCurrencyWithCurrencyEffect
|
||||
.minus(lastAveragePriceWithCurrencyEffect)
|
||||
.mul(order.quantity)
|
||||
|
@ -7,6 +7,7 @@ import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.s
|
||||
import { PortfolioOrder } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-order.interface';
|
||||
import { TransactionPoint } from '@ghostfolio/api/app/portfolio/interfaces/transaction-point.interface';
|
||||
import { UserService } from '@ghostfolio/api/app/user/user.service';
|
||||
import { getFactor } from '@ghostfolio/api/helper/portfolio.helper';
|
||||
import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/current-investment';
|
||||
import { AccountClusterRiskSingleAccount } from '@ghostfolio/api/models/rules/account-cluster-risk/single-account';
|
||||
import { CurrencyClusterRiskBaseCurrencyCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/base-currency-current-investment';
|
||||
@ -2131,7 +2132,7 @@ export class PortfolioService {
|
||||
?.marketPriceInBaseCurrency ?? 0;
|
||||
|
||||
if (['LIABILITY', 'SELL'].includes(type)) {
|
||||
currentValueOfSymbolInBaseCurrency *= -1;
|
||||
currentValueOfSymbolInBaseCurrency *= getFactor(type);
|
||||
}
|
||||
|
||||
if (accounts[Account?.id || UNKNOWN_KEY]?.valueInBaseCurrency) {
|
||||
|
21
apps/api/src/helper/portfolio.helper.ts
Normal file
21
apps/api/src/helper/portfolio.helper.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { Type as ActivityType } from '@prisma/client';
|
||||
|
||||
export function getFactor(activityType: ActivityType) {
|
||||
let factor: number;
|
||||
|
||||
switch (activityType) {
|
||||
case 'BUY':
|
||||
case 'ITEM':
|
||||
factor = 1;
|
||||
break;
|
||||
case 'LIABILITY':
|
||||
case 'SELL':
|
||||
factor = -1;
|
||||
break;
|
||||
default:
|
||||
factor = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return factor;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { IOrder } from '@ghostfolio/api/services/interfaces/interfaces';
|
||||
|
||||
import { Account, SymbolProfile, Type as TypeOfOrder } from '@prisma/client';
|
||||
import { Account, SymbolProfile, Type as ActivityType } from '@prisma/client';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
export class Order {
|
||||
@ -14,7 +14,7 @@ export class Order {
|
||||
private symbol: string;
|
||||
private symbolProfile: SymbolProfile;
|
||||
private total: number;
|
||||
private type: TypeOfOrder;
|
||||
private type: ActivityType;
|
||||
private unitPrice: number;
|
||||
|
||||
public constructor(data: IOrder) {
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
Account,
|
||||
DataSource,
|
||||
SymbolProfile,
|
||||
Type as TypeOfOrder
|
||||
Type as ActivityType
|
||||
} from '@prisma/client';
|
||||
|
||||
export interface IOrder {
|
||||
@ -18,7 +18,7 @@ export interface IOrder {
|
||||
quantity: number;
|
||||
symbol: string;
|
||||
symbolProfile: SymbolProfile;
|
||||
type: TypeOfOrder;
|
||||
type: ActivityType;
|
||||
unitPrice: number;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import { parseDate as parseDateHelper } from '@ghostfolio/common/helper';
|
||||
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Account, DataSource, Type } from '@prisma/client';
|
||||
import { Account, DataSource, Type as ActivityType } from '@prisma/client';
|
||||
import { isFinite } from 'lodash';
|
||||
import { parse as csvToJson } from 'papaparse';
|
||||
import { EMPTY } from 'rxjs';
|
||||
@ -328,26 +328,26 @@ export class ImportActivitiesService {
|
||||
content: any[];
|
||||
index: number;
|
||||
item: any;
|
||||
}) {
|
||||
}): ActivityType {
|
||||
item = this.lowercaseKeys(item);
|
||||
|
||||
for (const key of ImportActivitiesService.TYPE_KEYS) {
|
||||
if (item[key]) {
|
||||
switch (item[key].toLowerCase()) {
|
||||
case 'buy':
|
||||
return Type.BUY;
|
||||
return 'BUY';
|
||||
case 'dividend':
|
||||
return Type.DIVIDEND;
|
||||
return 'DIVIDEND';
|
||||
case 'fee':
|
||||
return Type.FEE;
|
||||
return 'FEE';
|
||||
case 'interest':
|
||||
return Type.INTEREST;
|
||||
return 'INTEREST';
|
||||
case 'item':
|
||||
return Type.ITEM;
|
||||
return 'ITEM';
|
||||
case 'liability':
|
||||
return Type.LIABILITY;
|
||||
return 'LIABILITY';
|
||||
case 'sell':
|
||||
return Type.SELL;
|
||||
return 'SELL';
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user