public PortfolioWork Adjust(PortfolioWork portfolio) { var port = portfolio.Portfolio; var ret = portfolio.ReturnData; var pl = 0M.AsMoney(); foreach (var invest in port.ComputedInvestments()) { var investmentPercentage = invest.Value; if (investmentPercentage > 1) { investmentPercentage *= .01M; } var weightedReturn = (decimal)ret.NameToPercentageReturn[invest.Key] * investmentPercentage; var amt = port.InvestmentAmount.GetClone(); //Perhaps the best way to handle this is to note if you have 0 or less invested, then the performance ultimately should be 0. if (port.InvestmentAmount <= 0) { amt = 0M.AsMoney(); } var investmentReturn = weightedReturn * amt; pl += investmentReturn; portfolio.Returns.Returns.Add(invest.Key, investmentReturn); } portfolio.Returns.MonthProfitOrLoss = pl; port.InvestmentAmount += pl; return(portfolio); }
public void Init(PortfolioWork portfolio) { if (!portfolio.ReturnData.NameToCape.ContainsKey(from)) { throw new Exception($"Unable to find '{from}' in DisplayNameOfCapeMeasureToHeader. Given current configuration would allow from to be: '{string.Join("','", portfolio.ReturnData.NameToCape.Keys)}'."); } }
public PortfolioWork Adjust(PortfolioWork portfolio) { var maxCapeToDoNothing = maxCapeBeforeAdjustment; var percentageAdjustment = percentageAdjusted; var amountOfAdditionalCapePerAdjustment = additionalAdjustmentPerCapeExcess; var cape = portfolio.ReturnData.NameToCape[from]; if (cape == null || !cape.HasValue) { return(portfolio); } if (cape <= maxCapeToDoNothing) { return(portfolio); } var equity = portfolio.Portfolio.ComputedInvestments()[from]; if (equity <= 0) { return(portfolio); //no equity to remove... } var capeOverage = cape - maxCapeToDoNothing; var actualAdjustment = (decimal)(capeOverage / amountOfAdditionalCapePerAdjustment) * percentageAdjustment; if (equity < actualAdjustment) { actualAdjustment = equity; } portfolio.Portfolio.TemporaryInvestmentAdjustments.Upsert(from, -1 * actualAdjustment); portfolio.Portfolio.TemporaryInvestmentAdjustments.Upsert(to, actualAdjustment); return(portfolio); }
public Outcome CalculateMonthReturn(PortfolioWork portfolio) { var outcome = new Outcome { PreviousPortfolio = portfolio.CopyOfPortfolio(), NewPortfolio = adjuster.UpdatePortfolio(portfolio).CopyOfPortfolio(), PeriodNumber = portfolio.MonthProcessed, ReturnDataDate = new DateTime((int)portfolio.ReturnData.Year, (int)portfolio.ReturnData.Month, 1), Returns = portfolio.Returns, TotalIncomeAndExpenses = portfolio.TotalIncomeAndExpenses, }; return(outcome); }
public PortfolioWork Adjust(PortfolioWork portfolio) { foreach (var item in Offsets) { if (item.StartMonth > portfolio.MonthProcessed) { continue; } if (item.EndMonth != null && item.EndMonth < portfolio.MonthProcessed) { continue; } portfolio.TotalIncomeAndExpenses += item.OffsetAmount; portfolio.Portfolio.InvestmentAmount += item.OffsetAmount; } return(portfolio); }
public PortfolioWork Adjust(PortfolioWork portfolio) { return(portfolio); }
public void Init(PortfolioWork portfolio) { }
public PortfolioWork Adjust(PortfolioWork portfolio) { if (callCount++ > 20) { return(portfolio); } var reprocess = false; if (max != null) { foreach (var item in max) { var currentVal = portfolio.Portfolio.Investments[item.Key]; var maxVal = item.Value; if (currentVal > maxVal) { var overage = currentVal - maxVal; reprocess = true; portfolio.Portfolio.Investments[item.Key] = maxVal; var portList = portfolio.Portfolio.Investments.GetClone().Where(a => a.Key != item.Key).ToList(); //Warning: This could end up with rounding errors in the 10th decimal place--probably doesn't matter. foreach (var otherInvestments in portList) { portfolio.Portfolio.Investments[otherInvestments.Key] = otherInvestments.Value + (decimal)(overage / portList.Count()); } } } } //TODO: This can be defeated by Temporary changes like CAPE adjustments. if (min != null) { foreach (var item in min) { var currentVal = portfolio.Portfolio.Investments[item.Key]; var minVal = item.Value; if (currentVal < minVal) { var underage = minVal - currentVal; reprocess = true; portfolio.Portfolio.Investments[item.Key] = minVal; var portList = portfolio.Portfolio.Investments.GetClone().Where(a => a.Key != item.Key).ToList(); var additionalOffset = 0M; do { var newOffset = additionalOffset; additionalOffset = 0M; //Warning: This could end up with rounding errors in the 10th decimal place--probably doesn't matter. foreach (var otherInvestments in portList) { var valueAdjustment = otherInvestments.Value - (decimal)((underage + newOffset) / portList.Count()); if (min.ContainsKey(otherInvestments.Key)) { if (min[otherInvestments.Key] > valueAdjustment) { additionalOffset += min[otherInvestments.Key] - valueAdjustment; valueAdjustment = min[otherInvestments.Key]; } } portfolio.Portfolio.Investments[otherInvestments.Key] = valueAdjustment; } if (additionalOffset != 0) { portList = portList.Where(a => portfolio.Portfolio.Investments[a.Key] != min.GetValueOrDefault(a.Key)).ToList(); } underage = 0; } while (additionalOffset != 0); } } } if (reprocess) { return(Adjust(portfolio)); } return(portfolio); }
public void Init(PortfolioWork portfolio) { callCount = 0; }