public DataFrame GetPortfolioHPR(int?portfolioId, string userId) { List <Trade> allTrades = _repo.GetAllUserTrades(portfolioId, userId); //Creating flows for each trade at a position level. // Flows and Cash if (allTrades.Count == 0) { return(null); } DataFrame flowFrame = CreateFlowTable(allTrades); //distinct tickers; string portfolioName = _repo.GetPortfolioName(portfolioId); PortfolioData userPortfolio = GetPortfolioData(portfolioName, allTrades); //####### DataFrame portfolioValuation = userPortfolio.GetValuation(); int pvSize = portfolioValuation.Rows.Count(); PrimitiveDataFrameColumn <decimal> cashCol2 = new PrimitiveDataFrameColumn <decimal>("cash", pvSize); PrimitiveDataFrameColumn <decimal> inflowCol2 = new PrimitiveDataFrameColumn <decimal>("inflow", pvSize); portfolioValuation.Columns.Add(cashCol2); portfolioValuation.Columns.Add(inflowCol2); //populate with flowFrame data int secondaryRow = 0; int valueIndex = portfolioValuation.Columns.Count - 3; int cashIndex = portfolioValuation.Columns.Count - 2; int inflowIndex = portfolioValuation.Columns.Count - 1; for (int row = 0; row < pvSize; row++) { if (secondaryRow == flowFrame.Rows.Count) { break; } if (secondaryRow < flowFrame.Rows.Count) { if (portfolioValuation[row, 0].Equals(flowFrame[secondaryRow, 0])) { // if the dates match portfolioValuation[row, cashIndex] = flowFrame[secondaryRow, 1]; portfolioValuation[row, inflowIndex] = flowFrame[secondaryRow, 2]; secondaryRow++; } } else { portfolioValuation[row, cashIndex] = Decimal.Zero; portfolioValuation[row, inflowIndex] = Decimal.Zero; } } //forwardfill cashcolumn then replace null with Decimal.Zero bool toFill = false; decimal prevCash = decimal.Zero; for (int row = 0; row < pvSize; row++) { if (((portfolioValuation[row, cashIndex] != null && (decimal?)portfolioValuation[row, cashIndex] != Decimal.Zero) && !toFill) || ((portfolioValuation[row, cashIndex] != null && (decimal?)portfolioValuation[row, cashIndex] != Decimal.Zero) && toFill)) { toFill = true; prevCash = (decimal)portfolioValuation[row, cashIndex]; } else if ((portfolioValuation[row, cashIndex] == null || (decimal?)portfolioValuation[row, cashIndex] == Decimal.Zero) && toFill) { portfolioValuation[row, cashIndex] = prevCash; } } portfolioValuation.Columns.GetPrimitiveColumn <decimal>("cash").FillNulls(Decimal.Zero, true); portfolioValuation.Columns.GetPrimitiveColumn <decimal>("inflow").FillNulls(Decimal.Zero, true); // get total portfolio value // PrimitiveDataFrameColumn <decimal> PortfolioVal = new PrimitiveDataFrameColumn <decimal>("PortfolioValue", pvSize); portfolioValuation.Columns.Add(PortfolioVal); int PortfolioValIndex = portfolioValuation.Columns.Count - 1; for (int row = 0; row < pvSize; row++) { portfolioValuation[row, PortfolioValIndex] = (decimal)portfolioValuation[row, cashIndex] + (decimal)portfolioValuation[row, valueIndex]; } PrimitiveDataFrameColumn <decimal> HPRcol = new PrimitiveDataFrameColumn <decimal>("Holding Period Return", pvSize); portfolioValuation.Columns.Add(HPRcol); int hprIndex = portfolioValuation.Columns.Count - 1; for (int row = 1; row < pvSize; row++) { int prevRow = row - 1; decimal HPR = (((decimal)portfolioValuation[row, PortfolioValIndex]) / ((decimal)portfolioValuation[prevRow, PortfolioValIndex] + (decimal)portfolioValuation[row, inflowIndex]) - 1) * 100; portfolioValuation[row, hprIndex] = Math.Round(HPR, 3); } // This is HPR performance indexed PrimitiveDataFrameColumn <decimal> HPRindexed = new PrimitiveDataFrameColumn <decimal>("Holding Period Return Indexed", pvSize); portfolioValuation.Columns.Add(HPRindexed); int HPRi = portfolioValuation.Columns.Count - 1; portfolioValuation[0, HPRi] = 100m; //initial index. for (int row = 1; row < pvSize; row++) { int prevRow = row - 1; decimal HPRx = (decimal)portfolioValuation[prevRow, HPRi] * (((decimal)portfolioValuation[row, hprIndex] / 100) + 1); portfolioValuation[row, HPRi] = Math.Round(HPRx, 3); } System.Diagnostics.Debug.WriteLine(portfolioValuation); return(portfolioValuation); }