Add test case for BUY and SELL (partially) (#826)

* Add test case for BUY and SELL (partially)

* Fix investment calculation for sell activities

* Do not show total value if sell activity

* Update changelog
pull/831/head
Thomas Kaul 2 years ago committed by GitHub
parent 65e062ad26
commit ba7c98d325
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Migrated the search functionality to `yahoo-finance2`
### Fixed
- Fixed an issue in the average price / investment calculation for sell activities
## 1.136.0 - 13.04.2022
### Changed

@ -20,6 +20,13 @@ function mockGetValue(symbol: string, date: Date) {
return { marketPrice: 0 };
case 'NOVN.SW':
if (isSameDay(parseDate('2022-04-11'), date)) {
return { marketPrice: 87.8 };
}
return { marketPrice: 0 };
default:
return { marketPrice: 0 };
}

@ -0,0 +1,96 @@
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
import { parseDate } from '@ghostfolio/common/helper';
import Big from 'big.js';
import { CurrentRateServiceMock } from './current-rate.service.mock';
import { PortfolioCalculator } from './portfolio-calculator';
jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => {
return {
// eslint-disable-next-line @typescript-eslint/naming-convention
CurrentRateService: jest.fn().mockImplementation(() => {
return CurrentRateServiceMock;
})
};
});
describe('PortfolioCalculator', () => {
let currentRateService: CurrentRateService;
beforeEach(() => {
currentRateService = new CurrentRateService(null, null, null);
});
describe('get current positions', () => {
it.only('with BALN.SW buy and sell', async () => {
const portfolioCalculator = new PortfolioCalculator({
currentRateService,
currency: 'CHF',
orders: [
{
currency: 'CHF',
date: '2022-03-07',
dataSource: 'YAHOO',
fee: new Big(1.3),
name: 'Novartis AG',
quantity: new Big(2),
symbol: 'NOVN.SW',
type: 'BUY',
unitPrice: new Big(75.8)
},
{
currency: 'CHF',
date: '2022-04-08',
dataSource: 'YAHOO',
fee: new Big(2.95),
name: 'Novartis AG',
quantity: new Big(1),
symbol: 'NOVN.SW',
type: 'SELL',
unitPrice: new Big(85.73)
}
]
});
portfolioCalculator.computeTransactionPoints();
const spy = jest
.spyOn(Date, 'now')
.mockImplementation(() => parseDate('2022-04-11').getTime());
const currentPositions = await portfolioCalculator.getCurrentPositions(
parseDate('2022-03-07')
);
spy.mockRestore();
expect(currentPositions).toEqual({
currentValue: new Big('87.8'),
errors: [],
grossPerformance: new Big('21.93'),
grossPerformancePercentage: new Big('0.14465699208443271768'),
hasErrors: false,
netPerformance: new Big('17.68'),
netPerformancePercentage: new Big('0.11662269129287598945'),
positions: [
{
averagePrice: new Big('75.80'),
currency: 'CHF',
dataSource: 'YAHOO',
firstBuyDate: '2022-03-07',
grossPerformance: new Big('21.93'),
grossPerformancePercentage: new Big('0.14465699208443271768'),
investment: new Big('75.80'),
netPerformance: new Big('17.68'),
netPerformancePercentage: new Big('0.11662269129287598945'),
marketPrice: 87.8,
quantity: new Big('1'),
symbol: 'NOVN.SW',
transactionCount: 2
}
],
totalInvestment: new Big('75.80')
});
});
});
});

@ -77,17 +77,30 @@ export class PortfolioCalculator {
const newQuantity = order.quantity
.mul(factor)
.plus(oldAccumulatedSymbol.quantity);
let investment = new Big(0);
if (newQuantity.gt(0)) {
if (order.type === 'BUY') {
investment = oldAccumulatedSymbol.investment.plus(
order.quantity.mul(unitPrice)
);
} else if (order.type === 'SELL') {
const averagePrice = oldAccumulatedSymbol.investment.div(
oldAccumulatedSymbol.quantity
);
investment = oldAccumulatedSymbol.investment.minus(
order.quantity.mul(averagePrice)
);
}
}
currentTransactionPointItem = {
investment,
currency: order.currency,
dataSource: order.dataSource,
fee: order.fee.plus(oldAccumulatedSymbol.fee),
firstBuyDate: oldAccumulatedSymbol.firstBuyDate,
investment: newQuantity.eq(0)
? new Big(0)
: unitPrice
.mul(order.quantity)
.mul(factor)
.plus(oldAccumulatedSymbol.investment),
quantity: newQuantity,
symbol: order.symbol,
transactionCount: oldAccumulatedSymbol.transactionCount + 1

@ -271,6 +271,7 @@
<td *matFooterCellDef class="d-none d-lg-table-cell px-1" mat-footer-cell>
<div class="d-flex justify-content-end">
<gf-value
*ngIf="totalValue !== null"
[isAbsolute]="true"
[isCurrency]="true"
[locale]="locale"
@ -302,6 +303,7 @@
<td *matFooterCellDef class="d-lg-none d-xl-none px-1" mat-footer-cell>
<div class="d-flex justify-content-end">
<gf-value
*ngIf="totalValue !== null"
[isAbsolute]="true"
[isCurrency]="true"
[locale]="locale"

@ -325,7 +325,7 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy {
if (activity.type === 'BUY' || activity.type === 'ITEM') {
totalValue = totalValue.plus(activity.valueInBaseCurrency);
} else if (activity.type === 'SELL') {
totalValue = totalValue.minus(activity.valueInBaseCurrency);
return null;
}
} else {
return null;

Loading…
Cancel
Save