private void Init(RebalanceInput input) { m_input = input ?? throw new ArgumentNullException(nameof(input)); if (m_input.MaxOrderCount < 1 || m_input.MaxOrderCount > input.Portfolio.Count) { throw new ArgumentOutOfRangeException(nameof(input.MaxOrderCount)); } m_maxDepth = m_input.MaxOrderCount - 1; m_result = new RebalanceResult(); }
public RebalanceResult Rebalance(RebalanceInput input) { var bestPercentage = decimal.MaxValue; List <ETFItem> bestPortfolio = null; // When the max order amount is minimized, we get all possible item // combinations to try out var combinations = input.Portfolio.GetKCombs(input.MaxOrderCount); var mutex = new object(); // for each possible combination... combinations.AsParallel().ForAll(c => { // Simulating investment with this combination var newPortfolio = SimulateInvestment(input, c); // Calculating final percentage for this combination var newPercentage = CalculateCurrentAllocation(newPortfolio); lock (mutex) { // if combination ends up better than the previous combinations, remember it if (newPercentage < bestPercentage) { bestPercentage = newPercentage; bestPortfolio = newPortfolio; } } }); // Calculation is done, creating the orders and returning the final result List <Order> order = new List <Order>(); foreach (var item in input.Portfolio) { var itemAfter = bestPortfolio.First(p => p.ISIN == item.ISIN); if (itemAfter.CurrentlyOwned > item.CurrentlyOwned) { order.Add(new Order { ISIN = itemAfter.ISIN, CurrentPrice = itemAfter.CurrentPrice, OrderAmount = (short)(itemAfter.CurrentlyOwned - item.CurrentlyOwned) }); } } var result = new RebalanceResult(); result.Percentage = bestPercentage; result.Orders = order; return(result); }