예제 #1
0
        public async Task GetPerformance()
        {
            var mockRepository = new MockRepository(MockBehavior.Strict);

            var portfolioId = Guid.NewGuid();
            var dateRange   = new DateRange(new Date(2001, 02, 03), new Date(2008, 06, 30));
            var response    = new PortfolioPerformanceResponse()
            {
                ChangeInMarketValue = 1000.00m
            };

            var messageHandler = mockRepository.Create <IRestClientMessageHandler>();

            messageHandler.SetupProperty(x => x.Portfolio, portfolioId);
            messageHandler.Setup(x => x.GetAsync <PortfolioPerformanceResponse>(It.Is <string>(x => x == "portfolio/" + portfolioId + "/performance?fromdate=2001-02-03&todate=2008-06-30")))
            .Returns(Task <PortfolioPerformanceResponse> .FromResult(response))
            .Verifiable();

            var resource = new PortfolioResource(messageHandler.Object);

            var result = await resource.GetPerformance(dateRange);

            result.Should().Be(response);

            mockRepository.Verify();
        }
예제 #2
0
        public void GetPerformanceStartDateOnly()
        {
            var mockRepository = new MockRepository(MockBehavior.Strict);

            var response = new PortfolioPerformanceResponse();

            var service = mockRepository.Create <IPortfolioPerformanceService>();

            service.Setup(x => x.GetPerformance(new DateRange(new Date(2000, 01, 01), new Date(2000, 12, 31)))).Returns(ServiceResult <PortfolioPerformanceResponse> .Ok(response)).Verifiable();

            var controller = new PortfolioController();
            var result     = controller.GetPerformance(service.Object, new DateTime(2000, 01, 01), null);

            result.Result.Should().BeOkObjectResult().Value.Should().Be(response);

            mockRepository.VerifyAll();
        }
예제 #3
0
        public void GetPerformanceNoDates()
        {
            var mockRepository = new MockRepository(MockBehavior.Strict);

            var response = new PortfolioPerformanceResponse();

            var service = mockRepository.Create <IPortfolioPerformanceService>();

            service.Setup(x => x.GetPerformance(new DateRange(Date.Today.AddYears(-1).AddDays(1), Date.Today))).Returns(ServiceResult <PortfolioPerformanceResponse> .Ok(response)).Verifiable();

            var controller = new PortfolioController();
            var result     = controller.GetPerformance(service.Object, null, null);

            result.Result.Should().BeOkObjectResult().Value.Should().Be(response);

            mockRepository.VerifyAll();
        }
        public ServiceResult <PortfolioPerformanceResponse> GetPerformance(DateRange dateRange)
        {
            if (_Portfolio == null)
            {
                return(ServiceResult <PortfolioPerformanceResponse> .NotFound());
            }

            var response = new PortfolioPerformanceResponse();

            var dateRangeExcludingFirstDay = new DateRange(dateRange.FromDate.AddDays(1), dateRange.ToDate);

            var openingHoldings = _Portfolio.Holdings.All(dateRange.FromDate);
            var closingHoldings = _Portfolio.Holdings.All(dateRange.ToDate);


            var workingList = new List <HoldingPerformanceWorkItem>();

            HoldingPerformanceWorkItem workItem;

            // Add opening holdings
            foreach (var holding in openingHoldings)
            {
                workItem = new HoldingPerformanceWorkItem(holding.Stock.ToSummaryResponse(dateRange.FromDate));

                var value = holding.Value(dateRange.FromDate);

                workItem.HoldingPerformance.OpeningBalance = value;
                workItem.StartDate    = dateRange.FromDate;
                workItem.InitialValue = value;

                workingList.Add(workItem);
            }

            // Process transactions during the period
            var transactions = _Portfolio.Transactions.InDateRange(dateRangeExcludingFirstDay);

            foreach (var transaction in transactions)
            {
                if ((transaction is Aquisition) ||
                    (transaction is OpeningBalance) ||
                    (transaction is Disposal) ||
                    (transaction is IncomeReceived))
                {
                    var newItem = false;

                    workItem = workingList.FirstOrDefault(x => x.HoldingPerformance.Stock.Id == transaction.Stock.Id);
                    if (workItem == null)
                    {
                        newItem  = true;
                        workItem = new HoldingPerformanceWorkItem(transaction.Stock.ToSummaryResponse(dateRange.FromDate));
                        workItem.HoldingPerformance.OpeningBalance = 0.00m;
                        workingList.Add(workItem);
                    }

                    if (transaction is Aquisition aquisition)
                    {
                        var value = aquisition.Units * aquisition.AveragePrice;

                        workItem.HoldingPerformance.Purchases += value;
                        if (newItem)
                        {
                            workItem.StartDate    = aquisition.Date;
                            workItem.InitialValue = value;
                        }
                        else
                        {
                            workItem.CashFlows.Add(aquisition.Date, -value);
                        }
                    }
                    else if (transaction is OpeningBalance openingBalance)
                    {
                        workItem.HoldingPerformance.Purchases += openingBalance.CostBase;

                        if (newItem)
                        {
                            workItem.StartDate    = openingBalance.Date;
                            workItem.InitialValue = openingBalance.CostBase;
                        }
                        else
                        {
                            workItem.CashFlows.Add(openingBalance.Date, -openingBalance.CostBase);
                        }
                    }
                    else if (transaction is Disposal disposal)
                    {
                        var value = disposal.Units * disposal.AveragePrice;

                        workItem.HoldingPerformance.Sales += value;
                        workItem.CashFlows.Add(disposal.Date, value);
                    }
                    else if (transaction is IncomeReceived income)
                    {
                        workItem.HoldingPerformance.Dividends += income.CashIncome;
                        workItem.CashFlows.Add(income.Date, income.CashIncome);
                    }
                }
            }

            // Populate HoldingPerformance from work list
            foreach (var item in workingList)
            {
                //    var holding = closingHoldings.FirstOrDefault(x => x.Stock.Id == item.HoldingPerformance.Stock.Id);
                var holding = _Portfolio.Holdings[item.HoldingPerformance.Stock.Id];

                if (holding.EffectivePeriod.ToDate < dateRange.ToDate)
                {
                    // Holding sold before period ended
                    item.HoldingPerformance.ClosingBalance = 0.00m;
                    item.EndDate    = holding.EffectivePeriod.ToDate;
                    item.FinalValue = 0.00m;
                    item.HoldingPerformance.DrpCashBalance = 0.00m;
                }
                else
                {
                    // Holding still held at period end
                    var value = holding.Value(dateRange.ToDate);
                    item.HoldingPerformance.ClosingBalance = value;

                    item.EndDate    = dateRange.ToDate;
                    item.FinalValue = value;

                    item.HoldingPerformance.DrpCashBalance = holding.DrpAccount.Balance(dateRange.ToDate);
                }

                item.HoldingPerformance.CapitalGain = item.HoldingPerformance.ClosingBalance - (item.HoldingPerformance.OpeningBalance + item.HoldingPerformance.Purchases - item.HoldingPerformance.Sales);
                item.HoldingPerformance.TotalReturn = item.HoldingPerformance.CapitalGain + item.HoldingPerformance.Dividends;

                var irr = IrrCalculator.CalculateIrr(item.StartDate, item.InitialValue, item.EndDate, item.FinalValue, item.CashFlows);
                if (double.IsNaN(irr) || double.IsInfinity(irr))
                {
                    item.HoldingPerformance.Irr = 0.00M;
                }
                else
                {
                    item.HoldingPerformance.Irr = (decimal)Math.Round(irr, 5);
                }

                response.HoldingPerformance.Add(item.HoldingPerformance);
            }

            var cashTransactions = _Portfolio.CashAccount.Transactions.InDateRange(dateRangeExcludingFirstDay);

            response.OpeningCashBalance = _Portfolio.CashAccount.Balance(dateRange.FromDate);
            response.Deposits           = cashTransactions.Where(x => x.Type == BankAccountTransactionType.Deposit).Sum(x => x.Amount);
            response.Withdrawls         = cashTransactions.Where(x => x.Type == BankAccountTransactionType.Withdrawl).Sum(x => x.Amount);
            response.Interest           = cashTransactions.Where(x => x.Type == BankAccountTransactionType.Interest).Sum(x => x.Amount);
            response.Fees = cashTransactions.Where(x => x.Type == BankAccountTransactionType.Fee).Sum(x => x.Amount);
            response.ClosingCashBalance = _Portfolio.CashAccount.Balance(dateRange.ToDate);

            response.OpeningBalance       = openingHoldings.Sum(x => x.Value(dateRange.FromDate));
            response.Dividends            = response.HoldingPerformance.Sum(x => x.Dividends);
            response.ChangeInMarketValue  = response.HoldingPerformance.Sum(x => x.CapitalGain);
            response.OutstandingDRPAmount = -response.HoldingPerformance.Sum(x => x.DrpCashBalance);
            response.ClosingBalance       = closingHoldings.Sum(x => x.Value(dateRange.ToDate));


            return(ServiceResult <PortfolioPerformanceResponse> .Ok(response));
        }