public async Task Optimize() { //Portfolio 1: 5d80d0587d2d4657d8e1fe8f //Portfolio 2: 5d83dbda7d2d4604505722e5 var portfolio = await _portfolioDataAccess.GetPortfolio("5d83dbda7d2d4604505722e5"); portfolio.Categories = portfolio.Categories.Where(c => !c.Name.Contains("Risk")).ToList(); var symbols = portfolio.AllStocks.Select(p => p.Symbol).ToList(); var getHistory = _alphaClient.GetPortfolioHistory(symbols); var result = await OptimizeCategory(portfolio); var portfolioSummary = string.Join("\n", result.AllStocks.Select(s => $"{s.Symbol}: {s.DesiredAmount}%")); Console.WriteLine(portfolioSummary); var finalSet = new RunScenarioDataSet { InitialInvestment = 10000, CashInfluxAmount = 150, CashInfluxCadence = CadenceTypeEnum.Weekly, Portfolios = new List <Portfolio> { result }, History = await getHistory }; var finalResult = await _rebalanceLogic.Simulate(finalSet); var simulationResult = finalResult.First(); var percents = simulationResult.Results.Select(r => Math.Round(r.PercentIncrease, 2) * 100).OrderBy(r => r).ToList(); var min = percents[0]; var percentile25 = percents[(int)(.25 * percents.Count)]; var percentile50 = percents[(int)(.50 * percents.Count)]; var percentile75 = percents[(int)(.75 * percents.Count)]; var max = percents.Last(); string percentilesString = $"{min}%, {percentile25}%, {percentile50}%, {percentile75}%, {max}%"; var firstScenario = simulationResult.Results.First(); var averagePercent = Math.Round(percents.Average(), 2); //var maxPercent = Math.Round(simulationResult.Results.Max(r => r.PercentIncrease), 2); //var minPercent = Math.Round(simulationResult.Results.Min(r => r.PercentIncrease), 2); //Console.WriteLine($"Portfolio {result.IndexOf(simulationResult)} experienced growth between {minPercent * 100}% and {maxPercent * 100}% with an average of {averagePercent * 100}% from {firstScenario.StartDate.Date.ToShortDateString()} to {firstScenario.EndDate.Date.ToShortDateString()}"); Console.WriteLine($"Optimal portfolio experienced an average growth of {averagePercent}% from {firstScenario.StartDate.Date.ToShortDateString()} to {firstScenario.EndDate.Date.ToShortDateString()} with the following percentiles: {percentilesString}."); }
public async Task <List <ScenarioResult> > RunScenario(RunScenarioDataSet dataSet) { if (dataSet.CashInfluxCadence != CadenceTypeEnum.Weekly) { throw new Exception($"{dataSet.CashInfluxCadence} cadence not yet supported."); } ConcurrentQueue <ScenarioResult> results = new ConcurrentQueue <ScenarioResult>(); await Task.WhenAll(dataSet.Portfolios.Select(p => Task.Run(() => { var portfolio = p.Copy(); var symbols = portfolio.AllStocks.Select(a => a.Symbol).ToList(); var currentAllocations = symbols.Select(s => new StockAllocation { Symbol = s, DesiredAmount = 0, DesiredAmountType = AllocationTypeEnum.StockAmount }).ToList(); decimal cashOnHand = dataSet.InitialInvestment; foreach (var period in dataSet.History) { var quotes = period.Stocks.Select(s => new Quote { Symbol = s.Symbol, Price = s.PeriodData.AdjustedClose, QuoteDate = period.ClosingDate }).ToList(); portfolio.CashOnHand = cashOnHand; foreach (var allocation in portfolio.AllStocks) { var currentAllocation = currentAllocations.Find(s => s.Symbol == allocation.Symbol); allocation.CurrentShares = currentAllocation.CurrentShares; } var rebalanceDataSet = new RebalanceDataSet { Portfolio = portfolio, Quotes = quotes }; var rebalanceResult = Rebalance(rebalanceDataSet); cashOnHand = rebalanceResult.RemainingCashOnHand + dataSet.CashInfluxAmount; foreach (var action in rebalanceResult.Actions) { var actualAllocation = currentAllocations.Find(a => a.Symbol == action.Symbol); if (action.ActionType == RebalanceActionTypeEnum.Buy) { actualAllocation.CurrentShares += action.Amount; } else { actualAllocation.CurrentShares -= action.Amount; } } } decimal finalPortfolioValue = cashOnHand - dataSet.CashInfluxAmount; var lastPeriod = dataSet.History.Last(); foreach (var allocation in currentAllocations) { finalPortfolioValue += allocation.CurrentShares *lastPeriod.Stocks.Find(s => s.Symbol == allocation.Symbol).PeriodData.AdjustedClose; } var totalCashInvested = (dataSet.InitialInvestment + dataSet.CashInfluxAmount * (dataSet.History.Count - 1)); var result = new ScenarioResult { PercentIncrease = (finalPortfolioValue / totalCashInvested) - 1, StartDate = dataSet.History.First().ClosingDate, EndDate = lastPeriod.ClosingDate, FinalPortfolioValue = finalPortfolioValue, TotalCashInvested = totalCashInvested }; results.Enqueue(result); }))); return(results.ToList()); }
public async Task <List <SimulationResult> > Simulate(RunScenarioDataSet dataSet) { for (int d = 0; d < dataSet.Portfolios.Count; d++) { dataSet.Portfolios[d].Id = d.ToString(); } ConcurrentDictionary <string, ConcurrentQueue <ScenarioResult> > mapping = new ConcurrentDictionary <string, ConcurrentQueue <ScenarioResult> >(); foreach (var portfolio in dataSet.Portfolios) { mapping[portfolio.Id] = new ConcurrentQueue <ScenarioResult>(); } var realScenario = RunScenario(dataSet); var tasks = new List <Task>(); int stockCount = (int)dataSet.Portfolios.Average(p => p.AllStocks.Count); //int iterationCount = 16000000 / (dataSet.Portfolios.Count * dataSet.History.Count); int iterationCount = 5000000 / (int)(Math.Pow(dataSet.Portfolios.Count * 2, 1.1) * (int)Math.Pow(dataSet.History.Count, .5) * (int)Math.Pow(stockCount, .9)); //int iterationCount = 500000 / (int)(Math.Pow(dataSet.Portfolios.Count, .9) * (int)Math.Pow(dataSet.History.Count, .5) * (int)Math.Pow(stockCount, .9)); //int iterationCount = 4000 / (dataSet.Portfolios.Count * dataSet.History.Count); var start = DateTime.Now; for (var i = 0; i < iterationCount; i++) { tasks.Add(Task.Run(async() => { var revisedHistory = dataSet.History.ShuffleCopy(); var revisedDataSet = new RunScenarioDataSet { CashInfluxAmount = dataSet.CashInfluxAmount, CashInfluxCadence = dataSet.CashInfluxCadence, History = revisedHistory, InitialInvestment = dataSet.InitialInvestment, Portfolios = dataSet.Portfolios.Copy() }; var nextResults = await RunScenario(revisedDataSet); foreach (var scenarioResult in nextResults) { var index = nextResults.IndexOf(scenarioResult); var portfolio = dataSet.Portfolios[index]; mapping[portfolio.Id].Enqueue(scenarioResult); } })); } await Task.WhenAll(tasks); var results = await realScenario; foreach (var scenarioResult in results) { var index = results.IndexOf(scenarioResult); var portfolio = dataSet.Portfolios[index].Copy(); mapping[portfolio.Id].Enqueue(scenarioResult); } var duration = DateTime.Now.Subtract(start).TotalSeconds; Console.WriteLine($"{dataSet.Portfolios.Count} portfolios, {dataSet.History.Count} weeks, {stockCount} stocks took {duration}s"); return(mapping.Select(kp => new SimulationResult { Portfolio = dataSet.Portfolios.First(p => kp.Key == p.Id), Results = kp.Value.ToList() }).ToList()); }
public async Task <T> OptimizeCategoryv2 <T>(T cat, DateTimeOffset?fromDate = null) where T : OptimizableCategory { var categorySymbols = cat.AllSymbols; var categoryPeriods = await _alphaClient.GetPortfolioHistory(categorySymbols); if (fromDate != null) { categoryPeriods = categoryPeriods.Where(p => p.ClosingDate > fromDate).ToList(); } var getCategories = Task.Run(async() => { if (cat.Categories == null || !cat.Categories.Any()) { return(cat.Categories); } var categories = new List <OptimizableCategory>(); var optimizeCategories = cat.Categories.Select(c => OptimizeCategoryv2(c, fromDate)); foreach (var optimizeCategory in optimizeCategories) { var optimized = await optimizeCategory; if (optimized != null) { categories.Add(optimized.Copy()); } } return(categories); }); var optimizedCategories = await getCategories; if (cat.Stocks == null || !cat.Stocks.Any()) { cat.Categories = optimizedCategories; return(cat); } var stockCombinations = GetPossibleStockCombinationsv2(cat.AllocatedAmount, cat.Stocks); var portfolios = stockCombinations.Select((allocations, i) => new Portfolio { Id = i.ToString(), Name = i.ToString(), CashOnHand = 0, Stocks = allocations?.Where(a => a.AllocatedAmount > 0).Select(a => a.Create()).ToList(), Categories = optimizedCategories?.Select(c => c.Create()).ToList() }).ToList(); RunScenarioDataSet dataSet = new RunScenarioDataSet { InitialInvestment = 10000, CashInfluxAmount = 150, CashInfluxCadence = CadenceTypeEnum.Weekly, Portfolios = portfolios, History = categoryPeriods }; var result = await _rebalanceLogic.Simulate(dataSet); var winner = result.Aggregate((r1, r2) => r1.Results.Average(r => r.PercentIncrease) > r2.Results.Average(r => r.PercentIncrease) ? r1 : r2); cat.Categories = optimizedCategories; cat.Stocks = winner.Portfolio.Stocks.Select(s => new OptimizableStock { Symbol = s.Symbol, AllocatedAmount = (int)s.DesiredAmount }).ToList(); return(cat); }
public async Task Scenarios() { //SHY,TLT,IEF,LQD,AGG var stocks = new[] { new[] { new { Symbol = "SOXL", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6m }, new { Symbol = "CIBR", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "MJ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "TAN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "ICLN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "XBI", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "ARKG", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "XLF", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6m }, new { Symbol = "SPY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14m }, new { Symbol = "QQQ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14m }, new { Symbol = "DIA", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6m }, new { Symbol = "^RUT", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6m }, new { Symbol = "TLT", Type = AllocationTypeEnum.Percentage, DesiredAmount = 17m }, new { Symbol = "VIXY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m } }, new[] { new { Symbol = "SOXL", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6m }, new { Symbol = "CIBR", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "MJ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "TAN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "ICLN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "XBI", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "ARKG", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "XLF", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6m }, new { Symbol = "SPY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14m }, new { Symbol = "QQQ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 15m }, new { Symbol = "DIA", Type = AllocationTypeEnum.Percentage, DesiredAmount = 12m }, new { Symbol = "TLT", Type = AllocationTypeEnum.Percentage, DesiredAmount = 16m }, new { Symbol = "VIXY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m } }, new[] { new { Symbol = "SOXL", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6m }, new { Symbol = "CIBR", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "MJ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "TAN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "ICLN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "XBI", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "ARKG", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m }, new { Symbol = "XLF", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6m }, new { Symbol = "SPY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14m }, new { Symbol = "QQQ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 15m }, new { Symbol = "DIA", Type = AllocationTypeEnum.Percentage, DesiredAmount = 12m }, new { Symbol = "TLT", Type = AllocationTypeEnum.Percentage, DesiredAmount = 16m }, new { Symbol = "VIXY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3m } } }.ToList(); var symbols = stocks.SelectMany(s => s.Select(st => st.Symbol)).Distinct().ToList(); var relevantPeriods = await _alphaClient.GetPortfolioHistory(symbols); var portfolios = stocks.Select(stockSet => new Portfolio { Stocks = stockSet.Select(s => new StockAllocation { Symbol = s.Symbol, DesiredAmountType = s.Type, DesiredAmount = s.DesiredAmount }).ToList() }).ToList(); RunScenarioDataSet dataSet = new RunScenarioDataSet { InitialInvestment = 10000, CashInfluxAmount = 150, CashInfluxCadence = CadenceTypeEnum.Weekly, Portfolios = portfolios, History = relevantPeriods }; var results = await _rebalanceLogic.RunScenario(dataSet); //foreach (var action in result.Actions) //{ // Console.WriteLine($"{action.ActionType} {action.Amount} shares of {action.Symbol}"); //} foreach (var result in results) { Console.WriteLine($"Portfolio {results.IndexOf(result)} grew by {result.PercentIncrease * 100} percent from {result.StartDate.Date.ToShortDateString()} to {result.EndDate.Date.ToShortDateString()}"); } }
public async Task Simulate() { var stocks = new[] { new[] { new { Symbol = "SOXL", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6 }, new { Symbol = "CIBR", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "MJ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "TAN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 5 }, new { Symbol = "ICLN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "XBI", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "ARKG", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6 }, new { Symbol = "XLF", Type = AllocationTypeEnum.Percentage, DesiredAmount = 5 }, new { Symbol = "SPY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14 }, new { Symbol = "QQQ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 13 }, new { Symbol = "DIA", Type = AllocationTypeEnum.Percentage, DesiredAmount = 12 }, new { Symbol = "VIXY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 4 }, new { Symbol = "TLT", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14 } }, new[] { new { Symbol = "SOXL", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6 }, new { Symbol = "CIBR", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "MJ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "TAN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 5 }, new { Symbol = "ICLN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "XBI", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "ARKG", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6 }, new { Symbol = "XLF", Type = AllocationTypeEnum.Percentage, DesiredAmount = 5 }, new { Symbol = "SPY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14 }, new { Symbol = "QQQ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 12 }, new { Symbol = "DIA", Type = AllocationTypeEnum.Percentage, DesiredAmount = 13 }, new { Symbol = "VIXY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 4 }, new { Symbol = "TLT", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14 } }, new[] { new { Symbol = "SOXL", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6 }, new { Symbol = "CIBR", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "MJ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "TAN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 5 }, new { Symbol = "ICLN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "XBI", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "ARKG", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6 }, new { Symbol = "XLF", Type = AllocationTypeEnum.Percentage, DesiredAmount = 5 }, new { Symbol = "SPY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 13 }, new { Symbol = "QQQ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14 }, new { Symbol = "DIA", Type = AllocationTypeEnum.Percentage, DesiredAmount = 12 }, new { Symbol = "VIXY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 4 }, new { Symbol = "TLT", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14 } }, new[] { new { Symbol = "SOXL", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6 }, new { Symbol = "CIBR", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "MJ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "TAN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 5 }, new { Symbol = "ICLN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "XBI", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "ARKG", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6 }, new { Symbol = "XLF", Type = AllocationTypeEnum.Percentage, DesiredAmount = 5 }, new { Symbol = "SPY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 13 }, new { Symbol = "QQQ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 12 }, new { Symbol = "DIA", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14 }, new { Symbol = "VIXY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 4 }, new { Symbol = "TLT", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14 } }, new[] { new { Symbol = "SOXL", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6 }, new { Symbol = "CIBR", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "MJ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "TAN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 5 }, new { Symbol = "ICLN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "XBI", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "ARKG", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6 }, new { Symbol = "XLF", Type = AllocationTypeEnum.Percentage, DesiredAmount = 5 }, new { Symbol = "SPY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 12 }, new { Symbol = "QQQ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 13 }, new { Symbol = "DIA", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14 }, new { Symbol = "VIXY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 4 }, new { Symbol = "TLT", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14 } }, new[] { new { Symbol = "SOXL", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6 }, new { Symbol = "CIBR", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "MJ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "TAN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 5 }, new { Symbol = "ICLN", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "XBI", Type = AllocationTypeEnum.Percentage, DesiredAmount = 3 }, new { Symbol = "ARKG", Type = AllocationTypeEnum.Percentage, DesiredAmount = 6 }, new { Symbol = "XLF", Type = AllocationTypeEnum.Percentage, DesiredAmount = 5 }, new { Symbol = "SPY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 12 }, new { Symbol = "QQQ", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14 }, new { Symbol = "DIA", Type = AllocationTypeEnum.Percentage, DesiredAmount = 13 }, new { Symbol = "VIXY", Type = AllocationTypeEnum.Percentage, DesiredAmount = 4 }, new { Symbol = "TLT", Type = AllocationTypeEnum.Percentage, DesiredAmount = 14 } } }.ToList(); var symbols = stocks.SelectMany(s => s.Select(st => st.Symbol)).Distinct().ToList(); var relevantPeriods = await _alphaClient.GetPortfolioHistory(symbols); var portfolios = stocks.Select(stockSet => new Portfolio { Stocks = stockSet.Select(s => new StockAllocation { Symbol = s.Symbol, DesiredAmountType = s.Type, DesiredAmount = s.DesiredAmount }).ToList() }).ToList(); RunScenarioDataSet dataSet = new RunScenarioDataSet { InitialInvestment = 10000, CashInfluxAmount = 150, CashInfluxCadence = CadenceTypeEnum.Weekly, Portfolios = portfolios, History = relevantPeriods }; var result = await _rebalanceLogic.Simulate(dataSet); foreach (var simulationResult in result) { var percents = simulationResult.Results.Select(r => Math.Round(r.PercentIncrease, 2) * 100).OrderBy(r => r).ToList(); var min = percents[0]; var percentile25 = percents[(int)(.25 * percents.Count)]; var percentile50 = percents[(int)(.50 * percents.Count)]; var percentile75 = percents[(int)(.75 * percents.Count)]; var max = percents.Last(); string percentilesString = $"{min}%, {percentile25}%, {percentile50}%, {percentile75}%, {max}%"; var firstScenario = simulationResult.Results.First(); var averagePercent = Math.Round(percents.Average(), 2); //var maxPercent = Math.Round(simulationResult.Results.Max(r => r.PercentIncrease), 2); //var minPercent = Math.Round(simulationResult.Results.Min(r => r.PercentIncrease), 2); //Console.WriteLine($"Portfolio {result.IndexOf(simulationResult)} experienced growth between {minPercent * 100}% and {maxPercent * 100}% with an average of {averagePercent * 100}% from {firstScenario.StartDate.Date.ToShortDateString()} to {firstScenario.EndDate.Date.ToShortDateString()}"); Console.WriteLine($"Portfolio {result.IndexOf(simulationResult)} experienced an average growth of {averagePercent}% from {firstScenario.StartDate.Date.ToShortDateString()} to {firstScenario.EndDate.Date.ToShortDateString()} with the following percentiles: {percentilesString}."); } }
public async Task <T> OptimizeCategory <T>(T cat) where T : Category { var categorySymbols = cat.AllStocks.Select(st => st.Symbol).Distinct().ToList(); var getCategoryPeriods = _alphaClient.GetPortfolioHistory(categorySymbols); var getCategories = Task.Run(async() => { if (cat.Categories == null || !cat.Categories.Any()) { return(cat.Categories); } var categories = new List <Category>(); var optimizeCategories = cat.Categories.Select(OptimizeCategory); foreach (var optimizeCategory in optimizeCategories) { var optimized = await optimizeCategory; Clean(optimized); categories.Add(optimized); } return(categories); }); var optimizedCategories = await getCategories; if (cat.Stocks == null || !cat.Stocks.Any()) { cat.Categories = optimizedCategories; return(cat); } var stockPercent = (int)cat.Stocks.Sum(s => s.DesiredAmount); var stockCombinations = GetPossibleStockCombinations(stockPercent, cat.Stocks.Copy(), 3, 6); var portfolios = stockCombinations.Select((allocations, i) => new Portfolio { Id = i.ToString(), Name = i.ToString(), CashOnHand = 0, Stocks = allocations.Where(a => a.DesiredAmount > 0).Copy(), Categories = optimizedCategories }).ToList(); RunScenarioDataSet dataSet = new RunScenarioDataSet { InitialInvestment = 10000, CashInfluxAmount = 150, CashInfluxCadence = CadenceTypeEnum.Weekly, Portfolios = portfolios, History = await getCategoryPeriods }; var result = await _rebalanceLogic.Simulate(dataSet); var winner = result.Aggregate((r1, r2) => r1.Results.Average(r => r.PercentIncrease) > r2.Results.Average(r => r.PercentIncrease) ? r1 : r2); cat.Categories = winner.Portfolio.Categories.Copy(); cat.Stocks = winner.Portfolio.Stocks.Copy(); return(cat); }