Ejemplo n.º 1
0
        public IEnumerable<Dividend> CalculateDividends(int year, Deposit deposit, IEnumerable<GeneralMeeting> generalMeetings)
        {
            Guard.AgainstNull(() => deposit, () => generalMeetings);

            var generalMeetingsInYear = 
                generalMeetings.Where(p => p.MeetingDate.Year == year && p.DividendRate > 0);

            foreach (var generalMeeting in generalMeetingsInYear)
            {
                var position = _stockPositionCalculator.GetStockPosition(
                    deposit, generalMeeting.Stock.Splitted.Id, generalMeeting.MeetingDate);

                var quantity = position.Quantity;

                if (quantity > 0)
                {
                    var createdDividend = deposit.GetDividendForGeneralMeeting(generalMeeting.Id);

                    bool isCreated = false;
                    bool isDifferent = false;

                    if (createdDividend != null)
                    {
                        isCreated = true;
                        isDifferent = createdDividend.Quantity != quantity;
                    }

                    var dividend = new Dividend(0, quantity, generalMeeting.Id, deposit.Id, generalMeeting, isCreated, isDifferent);
                    yield return dividend;
                }
            }
        }
        public IEnumerable<StockPosition> GetStockPositions(Deposit deposit)
        {
            var stockPositions =
                from trade in deposit.Trades
                group trade by trade.Stock.Splitted.Id into g
                let quantity = g.Sum(t => t.QuantitySignedSplitted())
                where quantity > 0
                select new StockPosition(g.Key, quantity);

            return stockPositions;
        }
        public StockPosition GetStockPosition(Deposit deposit, int stockId, DateTime date)
        {
            Guard.AgainstNull(() => deposit);

            var quantity = 
                deposit.Trades
                .Where(p => p.TradeDate.Date <= date.Date && p.Stock.Splitted.Id == stockId)
                .Sum(t => t.QuantitySignedSplitted(date));

            return new StockPosition(stockId, quantity);
        }
Ejemplo n.º 4
0
        public void UpdateDeposit(Deposit deposit)
        {
            Guard.AgainstNull(() => deposit);

            deposit.Validate();

            using (var uow = _uowFactory.Create())
            {
                uow.Repo<IDepositRepository>().Update(deposit);
                uow.SaveChanges();
            }
        }
Ejemplo n.º 5
0
        public Deposit CreateDeposit(Deposit deposit)
        {
            Guard.AgainstNull(() => deposit);

            deposit.Validate();

            using (var uow = _uowFactory.Create())
            {
                uow.Repo<IDepositRepository>().Add(deposit);
                uow.SaveChanges();
                return deposit;
            }
        }
Ejemplo n.º 6
0
 public Trade(int id, bool isBuy, int quantity, decimal price, decimal commission, DateTime tradeDate, 
     int depositId, int stockId, Deposit deposit, Stock stock)
 {
     Id = id;
     IsBuy = isBuy;
     Quantity = quantity;
     Price = price;
     Commission = commission;
     TradeDate = tradeDate;
     DepositId = depositId;
     StockId = stockId;
     Deposit = deposit;
     Stock = stock;
 }
Ejemplo n.º 7
0
        public TradeInfoDto CalculateTradeInfo(bool isBuy, decimal tradePrice, int quantity, int stockId, Deposit deposit)
        {
            Guard.AgainstNull(() => deposit);

            //TODO: Modtag som parameter når vi har realtime-kurser.
            var realtimePrice = 150m;

            var stockQuantity = 0;
            var depositValue = 0m;
            var originalTradeValue = _stockPositionCalculator.CalculateMarketValue(quantity, tradePrice);
            var currentTradeValue = _stockPositionCalculator.CalculateMarketValue(quantity, realtimePrice);
            var stockValueInDeposit = (isBuy ? currentTradeValue : -currentTradeValue);
            var depositPositions = _stockPositionCalculator.GetStockPositions(deposit).ToArray();

            if (depositPositions.Any())
            {
                //TODO: Use real price when the system supports up-to-date prices.
                var fakePrice = 200;

                var existingPosition = depositPositions.SingleOrDefault(p => p.StockId == stockId);

                if (existingPosition != null)
                {
                    stockQuantity = existingPosition.Quantity;
                    stockValueInDeposit += _stockPositionCalculator.CalculateMarketValue(existingPosition.Quantity, fakePrice); //existingPosition.Value;
                }

                depositValue += depositPositions.Sum(p => _stockPositionCalculator.CalculateMarketValue(p.Quantity, fakePrice));// p.Value);
            }

            // Ved køb skal værdien på den nye handel lægges til den eksisterende værdi fordi vi er interesserede i
            // at finde ud af hvordan depotet vil komme til at se ud efter handlen er lavet.
            if (isBuy)
                depositValue += currentTradeValue;

            var tradeShareInDeposit = 0m;
            var stockShareInDeposit = 0m;

            if (depositValue > 0)
            {
                tradeShareInDeposit = BeregnPctAndel(currentTradeValue, depositValue);
                stockShareInDeposit = BeregnPctAndel(stockValueInDeposit, depositValue);
            }

            return new TradeInfoDto(
                stockQuantity, originalTradeValue, currentTradeValue,
                stockValueInDeposit, tradeShareInDeposit, stockShareInDeposit);
        }
Ejemplo n.º 8
0
        private DepositInfoDTO GetDepositInfo(Deposit deposit)
        {
            var stockPositions = _stockPositionCalculator.GetStockPositions(deposit).ToArray();
            var sellableStockIds = stockPositions.Select(p => p.StockId).ToArray();

            return new DepositInfoDTO(deposit, sellableStockIds, stockPositions);
        }
Ejemplo n.º 9
0
 // TODO: Skal nok have andet navn. Kaldes når ny handel er oprettet og depotet skal opdateres pga. det.
 public DepositInfoDTO Refresh(Deposit deposit, Trade trade)
 {
     deposit.AddTrade(trade);
     return GetDepositInfo(deposit);
 }
Ejemplo n.º 10
0
        private Tuple<decimal, decimal, decimal, List<YearlyReportDividendDTO>> GetReportDividendData(int year, Deposit deposit)
        {
            var reportDividends = new List<YearlyReportDividendDTO>();

            decimal dividendDanishStocks = 0;
            decimal dividendForeignStocks = 0;
            decimal dividendInvestmentFonds = 0;

            var dividends =
                from dividend in deposit.Dividends
                where dividend.GeneralMeeting.MeetingDate.Year == year
                select dividend;

            foreach (var dividend in dividends)
            {
                var dividendPayment = dividend.DividendPayment;

                //TODO: Settings med skattesatser..
                var taxPayment = dividendPayment * 0.27m;


                //TODO: Refactor conditional to polymorphism?
                string stockType = "??";

                switch (dividend.GeneralMeeting.Stock.StockType)
                {
                    case StockTypes.Aktie:
                        stockType = "Dansk aktie";
                        dividendDanishStocks += dividendPayment;
                        break;

                    case StockTypes.UdenlandskAktie:
                        stockType = "Udl. aktie";
                        dividendForeignStocks += dividendPayment;
                        break;

                    case StockTypes.Investeringsbevis:
                        stockType = "Inv. bevis";
                        dividendInvestmentFonds += dividendPayment;
                        break;

                    case StockTypes.TegningsretAktie:
                        stockType = "Tegningsret"; break;
                }

                var reportDividend = new YearlyReportDividendDTO
                (
                    date: dividend.GeneralMeeting.MeetingDate,
                    description: dividend.GeneralMeeting.Stock.Name,
                    stockType: stockType,
                    quantity: dividend.Quantity,
                    dividendRate: dividend.GeneralMeeting.DividendRate,
                    grossDividendPayment: dividendPayment,
                    taxPayment: taxPayment,
                    netDividendPayment: dividendPayment - taxPayment
                );

                reportDividends.Add(reportDividend);
            }

            return Tuple.Create(dividendDanishStocks, dividendForeignStocks, dividendInvestmentFonds, reportDividends);
        }
Ejemplo n.º 11
0
        private IEnumerable<YearlyReportStockGroupDTO> GetReportStockGroups(int year, Deposit deposit)
        {
            if (!deposit.Trades.Any())
                yield break;

            var tradeGroups =
                from trade in deposit.Trades
                where trade.TradeDate.Year <= year
                group trade by trade.Stock.Splitted into grp
                select new
                {
                    StockName = grp.Key.Name,
                    Trades = grp.OrderBy(p => p.TradeDate)
                };

            foreach (var tradeGroup in tradeGroups)
            {
                var stockGroupItems = new List<YearlyReportStockGroupItemDTO>();

                int buyQuantitySum = 0;
                decimal buyMarketvalueSum = 0;

                int taxFreeBuyQuantitySum = 0;
                decimal taxFreeBuyMarketvalueSum = 0;

                foreach (var trade in tradeGroup.Trades)
                {
                    decimal marketvalue = trade.MarketvalueInclCommission;
                    int quantity = trade.QuantitySplitted();

                    decimal buyValue = 0;
                    decimal sellValue = 0;
                    decimal tradeProfitLoss = 0;

                    if (trade.IsBuy)
                    {
                        if (trade.TradeDate.Year < 2006)
                        {
                            // Aktier købt inden 2006 sælges skattefrit, så beregner den skattefrie beholdning.
                            taxFreeBuyQuantitySum += quantity;
                            taxFreeBuyMarketvalueSum += marketvalue;
                        }
                        else
                        {
                            buyQuantitySum += quantity;
                            buyMarketvalueSum += marketvalue;
                        }

                        buyValue = marketvalue;
                    }
                    else
                    {
                        decimal salesPrice = marketvalue / quantity;
                        Tuple<decimal, decimal> tradeProfitLossItem = null;

                        // Skattefri gevinst bruges ikke til noget pt.
                        // Den burde nok indgå i total indkomst, men ikke i skatteberegningerne.
                        Tuple<decimal, decimal> tradeTaxFreeProfitLossItem = null;

                        if (taxFreeBuyQuantitySum > 0)
                        {
                            int taxedQuantity = quantity - taxFreeBuyQuantitySum;

                            if (taxedQuantity > 0)
                            {
                                // Delvist skattefrit salg. Har både en skattefri og en skattepligtig gevinst.
                                tradeTaxFreeProfitLossItem =
                                    CalculateProfitLoss(ref taxFreeBuyMarketvalueSum, ref taxFreeBuyQuantitySum, taxFreeBuyQuantitySum, salesPrice);

                                tradeProfitLossItem =
                                    CalculateProfitLoss(ref buyMarketvalueSum, ref buyQuantitySum, taxedQuantity, salesPrice);
                            }
                            else
                            {
                                // Fuldt skattefrit salg. Har kun en skattefri gevinst.
                                tradeTaxFreeProfitLossItem =
                                    CalculateProfitLoss(ref taxFreeBuyMarketvalueSum, ref taxFreeBuyQuantitySum, quantity, salesPrice);
                            }
                        }
                        else
                        {
                            // Fuldt skattepligtigt salg.
                            tradeProfitLossItem =
                                CalculateProfitLoss(ref buyMarketvalueSum, ref buyQuantitySum, quantity, salesPrice);
                        }

                        sellValue = marketvalue;
                        buyValue = tradeProfitLossItem.Item1;
                        tradeProfitLoss = tradeProfitLossItem.Item2;
                    }

                    if (trade.TradeDate.Year == year)
                    {
                        var stockGroupItem = new YearlyReportStockGroupItemDTO
                        (
                            description: trade.IsBuy ? "Køb" : "Salg",
                            date: trade.TradeDate.Date,
                            quantity: trade.Quantity,
                            sellValue: sellValue,
                            buyValue: buyValue,
                            profitLoss: tradeProfitLoss,
                            isProfit: tradeProfitLoss >= 0,
                            isSale: !trade.IsBuy
                        );

                        stockGroupItems.Add(stockGroupItem);
                    }
                }

                if (stockGroupItems.Any())
                {
                    var stockProfitLoss = stockGroupItems.Sum(p => p.ProfitLoss);

                    var stockGroup = new YearlyReportStockGroupDTO(
                        header: tradeGroup.StockName,
                        profitLoss: stockProfitLoss,
                        isProfit: stockProfitLoss >= 0,
                        items: stockGroupItems);

                    yield return stockGroup;
                }
            }
        }
Ejemplo n.º 12
0
        public YearlyReportDTO GetYearlyReport(int year, bool isMarried, Deposit deposit)
        {
            // Gevinst og tab
            var reportStockGroups = GetReportStockGroups(year, deposit);

            Func<Func<YearlyReportStockGroupDTO, bool>, decimal> sumProfitLoss =
                p => reportStockGroups.Where(p).Sum(o => o.ProfitLoss);

            decimal totalProfit = sumProfitLoss(p => p.ProfitLoss > 0);
            decimal totalLoss = sumProfitLoss(p => p.ProfitLoss < 0);
            decimal totalProfitLoss = totalProfit + totalLoss;

            // Udbytte
            var reportDividendData = GetReportDividendData(year, deposit);
            decimal dividendDanishStocks = reportDividendData.Item1;
            decimal dividendForeignStocks = reportDividendData.Item2;
            decimal dividendInvestmentFonds = reportDividendData.Item3;
            IEnumerable<YearlyReportDividendDTO> reportDividends = reportDividendData.Item4;

            // Total
            decimal grossReturnNoLossDeduction = totalProfit + dividendDanishStocks + dividendForeignStocks;
            decimal grossReturn = grossReturnNoLossDeduction + totalLoss;
            string grossReturnDescription = $"{totalProfitLoss:N2} + {dividendDanishStocks:N2} + {dividendForeignStocks:N2}";

            // Tax. If correct settings are not available don't calculate anything.
            decimal taxPayment = -1;
            string taxPaymentDescription = string.Empty;
            decimal netReturn = -1;
            decimal taxPaymentNoLossDeduction = -1;
            decimal lossDeduction = -1;
            bool isMissingTaxValueSettings = false;

            TaxValues taxValues = null;

            if (_settingsProvider.Instance.YearlyTaxValues?.TryGetValue(year, out taxValues) == true)
            {
                var taxInfo = CalculateTax(grossReturn, isMarried, taxValues);
                taxPayment = taxInfo.Item1;
                taxPaymentDescription = taxInfo.Item2;
                netReturn = grossReturn - taxPayment;
                taxPaymentNoLossDeduction = CalculateTax(grossReturnNoLossDeduction, isMarried, taxValues).Item1;
                lossDeduction = taxPaymentNoLossDeduction - taxPayment;
            }
            else
            {
                isMissingTaxValueSettings = true;
            }

            return new YearlyReportDTO
            (
                profit: totalProfit,
                loss: totalLoss,
                profitLoss: totalProfitLoss,
                isProfit: totalProfitLoss >= 0,
                dividendDanishStocks: dividendDanishStocks,
                dividendForeignStocks: dividendForeignStocks,
                dividendInvestmentFonds: dividendInvestmentFonds,
                grossReturn: grossReturn,
                grossReturnDescription: grossReturnDescription,
                taxPayment: taxPayment,
                taxPaymentDescription: taxPaymentDescription,
                netReturn: netReturn,
                isPositiveReturn: netReturn >= 0,
                lossDeduction: lossDeduction,
                isMissingTaxValueSettings: isMissingTaxValueSettings,
                stockGroups: reportStockGroups,
                dividends: reportDividends
            );
        }
Ejemplo n.º 13
0
 public DepositInfoDTO(Deposit deposit,  IEnumerable<int> sellableStockIds, IEnumerable<StockPosition> stockPositions)
 {
     Deposit = deposit;
     SellableStockIds = sellableStockIds;
     StockPositions = stockPositions;
 }
 private DepositViewModel GetDepositViewModel(Deposit deposit)
 {
     return new DepositViewModel
     {
         Id = deposit.Id,
         Description = deposit.Description,
         IdentityNumber = deposit.IdentityNumber,
         DepositType = deposit.DepositType
     };
 }