mirror of https://github.com/ghostfolio/ghostfolio
				
				
			
			
			
				Browse Source
			
			
			
			
				
		* Fix average price calculation by only considering buy transactions * Update changelogpull/3126/head^2
							committed by
							
								
								GitHub
							
						
					
				
				 3 changed files with 199 additions and 33 deletions
			
			
		@ -0,0 +1,166 @@ | 
				
			|||||
 | 
					import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; | 
				
			||||
 | 
					import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.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; | 
				
			||||
 | 
					  let exchangeRateDataService: ExchangeRateDataService; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  beforeEach(() => { | 
				
			||||
 | 
					    currentRateService = new CurrentRateService(null, null, null, null); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    exchangeRateDataService = new ExchangeRateDataService( | 
				
			||||
 | 
					      null, | 
				
			||||
 | 
					      null, | 
				
			||||
 | 
					      null, | 
				
			||||
 | 
					      null | 
				
			||||
 | 
					    ); | 
				
			||||
 | 
					  }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  describe('get current positions', () => { | 
				
			||||
 | 
					    it.only('with BALN.SW buy and sell in two activities', async () => { | 
				
			||||
 | 
					      const portfolioCalculator = new PortfolioCalculator({ | 
				
			||||
 | 
					        currentRateService, | 
				
			||||
 | 
					        exchangeRateDataService, | 
				
			||||
 | 
					        currency: 'CHF', | 
				
			||||
 | 
					        orders: [ | 
				
			||||
 | 
					          { | 
				
			||||
 | 
					            currency: 'CHF', | 
				
			||||
 | 
					            date: '2021-11-22', | 
				
			||||
 | 
					            dataSource: 'YAHOO', | 
				
			||||
 | 
					            fee: new Big(1.55), | 
				
			||||
 | 
					            name: 'Bâloise Holding AG', | 
				
			||||
 | 
					            quantity: new Big(2), | 
				
			||||
 | 
					            symbol: 'BALN.SW', | 
				
			||||
 | 
					            type: 'BUY', | 
				
			||||
 | 
					            unitPrice: new Big(142.9) | 
				
			||||
 | 
					          }, | 
				
			||||
 | 
					          { | 
				
			||||
 | 
					            currency: 'CHF', | 
				
			||||
 | 
					            date: '2021-11-30', | 
				
			||||
 | 
					            dataSource: 'YAHOO', | 
				
			||||
 | 
					            fee: new Big(1.65), | 
				
			||||
 | 
					            name: 'Bâloise Holding AG', | 
				
			||||
 | 
					            quantity: new Big(1), | 
				
			||||
 | 
					            symbol: 'BALN.SW', | 
				
			||||
 | 
					            type: 'SELL', | 
				
			||||
 | 
					            unitPrice: new Big(136.6) | 
				
			||||
 | 
					          }, | 
				
			||||
 | 
					          { | 
				
			||||
 | 
					            currency: 'CHF', | 
				
			||||
 | 
					            date: '2021-11-30', | 
				
			||||
 | 
					            dataSource: 'YAHOO', | 
				
			||||
 | 
					            fee: new Big(0), | 
				
			||||
 | 
					            name: 'Bâloise Holding AG', | 
				
			||||
 | 
					            quantity: new Big(1), | 
				
			||||
 | 
					            symbol: 'BALN.SW', | 
				
			||||
 | 
					            type: 'SELL', | 
				
			||||
 | 
					            unitPrice: new Big(136.6) | 
				
			||||
 | 
					          } | 
				
			||||
 | 
					        ] | 
				
			||||
 | 
					      }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      portfolioCalculator.computeTransactionPoints(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      const spy = jest | 
				
			||||
 | 
					        .spyOn(Date, 'now') | 
				
			||||
 | 
					        .mockImplementation(() => parseDate('2021-12-18').getTime()); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      const chartData = await portfolioCalculator.getChartData({ | 
				
			||||
 | 
					        start: parseDate('2021-11-22') | 
				
			||||
 | 
					      }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      const currentPositions = await portfolioCalculator.getCurrentPositions( | 
				
			||||
 | 
					        parseDate('2021-11-22') | 
				
			||||
 | 
					      ); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      const investments = portfolioCalculator.getInvestments(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      const investmentsByMonth = portfolioCalculator.getInvestmentsByGroup({ | 
				
			||||
 | 
					        data: chartData, | 
				
			||||
 | 
					        groupBy: 'month' | 
				
			||||
 | 
					      }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      spy.mockRestore(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      expect(currentPositions).toEqual({ | 
				
			||||
 | 
					        currentValueInBaseCurrency: new Big('0'), | 
				
			||||
 | 
					        errors: [], | 
				
			||||
 | 
					        grossPerformance: new Big('-12.6'), | 
				
			||||
 | 
					        grossPerformancePercentage: new Big('-0.04408677396780965649'), | 
				
			||||
 | 
					        grossPerformancePercentageWithCurrencyEffect: new Big( | 
				
			||||
 | 
					          '-0.04408677396780965649' | 
				
			||||
 | 
					        ), | 
				
			||||
 | 
					        grossPerformanceWithCurrencyEffect: new Big('-12.6'), | 
				
			||||
 | 
					        hasErrors: false, | 
				
			||||
 | 
					        netPerformance: new Big('-15.8'), | 
				
			||||
 | 
					        netPerformancePercentage: new Big('-0.05528341497550734703'), | 
				
			||||
 | 
					        netPerformancePercentageWithCurrencyEffect: new Big( | 
				
			||||
 | 
					          '-0.05528341497550734703' | 
				
			||||
 | 
					        ), | 
				
			||||
 | 
					        netPerformanceWithCurrencyEffect: new Big('-15.8'), | 
				
			||||
 | 
					        positions: [ | 
				
			||||
 | 
					          { | 
				
			||||
 | 
					            averagePrice: new Big('0'), | 
				
			||||
 | 
					            currency: 'CHF', | 
				
			||||
 | 
					            dataSource: 'YAHOO', | 
				
			||||
 | 
					            dividend: new Big('0'), | 
				
			||||
 | 
					            dividendInBaseCurrency: new Big('0'), | 
				
			||||
 | 
					            fee: new Big('3.2'), | 
				
			||||
 | 
					            firstBuyDate: '2021-11-22', | 
				
			||||
 | 
					            grossPerformance: new Big('-12.6'), | 
				
			||||
 | 
					            grossPerformancePercentage: new Big('-0.04408677396780965649'), | 
				
			||||
 | 
					            grossPerformancePercentageWithCurrencyEffect: new Big( | 
				
			||||
 | 
					              '-0.04408677396780965649' | 
				
			||||
 | 
					            ), | 
				
			||||
 | 
					            grossPerformanceWithCurrencyEffect: new Big('-12.6'), | 
				
			||||
 | 
					            investment: new Big('0'), | 
				
			||||
 | 
					            investmentWithCurrencyEffect: new Big('0'), | 
				
			||||
 | 
					            netPerformance: new Big('-15.8'), | 
				
			||||
 | 
					            netPerformancePercentage: new Big('-0.05528341497550734703'), | 
				
			||||
 | 
					            netPerformancePercentageWithCurrencyEffect: new Big( | 
				
			||||
 | 
					              '-0.05528341497550734703' | 
				
			||||
 | 
					            ), | 
				
			||||
 | 
					            netPerformanceWithCurrencyEffect: new Big('-15.8'), | 
				
			||||
 | 
					            marketPrice: 148.9, | 
				
			||||
 | 
					            marketPriceInBaseCurrency: 148.9, | 
				
			||||
 | 
					            quantity: new Big('0'), | 
				
			||||
 | 
					            symbol: 'BALN.SW', | 
				
			||||
 | 
					            timeWeightedInvestment: new Big('285.80000000000000396627'), | 
				
			||||
 | 
					            timeWeightedInvestmentWithCurrencyEffect: new Big( | 
				
			||||
 | 
					              '285.80000000000000396627' | 
				
			||||
 | 
					            ), | 
				
			||||
 | 
					            transactionCount: 3, | 
				
			||||
 | 
					            valueInBaseCurrency: new Big('0') | 
				
			||||
 | 
					          } | 
				
			||||
 | 
					        ], | 
				
			||||
 | 
					        totalInvestment: new Big('0'), | 
				
			||||
 | 
					        totalInvestmentWithCurrencyEffect: new Big('0') | 
				
			||||
 | 
					      }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      expect(investments).toEqual([ | 
				
			||||
 | 
					        { date: '2021-11-22', investment: new Big('285.8') }, | 
				
			||||
 | 
					        { date: '2021-11-30', investment: new Big('0') } | 
				
			||||
 | 
					      ]); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      expect(investmentsByMonth).toEqual([ | 
				
			||||
 | 
					        { date: '2021-11-01', investment: 0 }, | 
				
			||||
 | 
					        { date: '2021-12-01', investment: 0 } | 
				
			||||
 | 
					      ]); | 
				
			||||
 | 
					    }); | 
				
			||||
 | 
					  }); | 
				
			||||
 | 
					}); | 
				
			||||
					Loading…
					
					
				
		Reference in new issue