public static AssetSize GetAssetWithSmallestReminder( this AssetAllocation allocation, Money portfolioCost, Dictionary <string, Money> prices) { AssetSize size = null; decimal bestReminder = decimal.MaxValue; foreach (var portion in allocation.Portions) { var ticker = portion.Ticker; var targetCost = portfolioCost * portion.Portion; var targetNumber = Math.Floor(targetCost / prices[ticker]); var rest = (targetCost - targetNumber * prices[ticker]).As(Currency.Rubles).Value; if (bestReminder > rest) { bestReminder = rest; size = new AssetSize(portion.Ticker, Convert.ToInt32(targetNumber)); } } return(size); }
public IReadOnlyList <Action> GetActions( Portfolio portfolio, AssetAllocation allocation, IReadOnlyList <AssetPrice> prices) { var pricesMap = prices.ToDictionary(p => p.Ticker, p => p.Value); ValidateThatProcesForAllTickersAreAvailable(portfolio, allocation, pricesMap); var targetAssetSizes = CalculateTargetAssetSizes(portfolio, allocation, pricesMap); var actions = GetActions(portfolio, targetAssetSizes).OrderBy(a => a.Type).ToArray(); ValidateActions(portfolio, actions, pricesMap); return(actions); }
private static Dictionary <string, int> CalculateTargetAssetSizes(Portfolio portfolio, AssetAllocation allocation, Dictionary <string, Money> pricesMap) { var portfolioCost = portfolio.Cost(pricesMap); var targetAssetSizes = new Dictionary <string, int>(); while (allocation.Portions.Count > 0) { var assetSize = allocation.GetAssetWithSmallestReminder(portfolioCost, pricesMap); allocation = allocation.Remove(assetSize.Ticker); targetAssetSizes[assetSize.Ticker] = assetSize.Size; portfolioCost = portfolioCost - assetSize.Size * pricesMap[assetSize.Ticker]; } return(targetAssetSizes); }
private static void ValidateThatProcesForAllTickersAreAvailable(Portfolio portfolio, AssetAllocation allocation, Dictionary <string, Money> pricesMap) { foreach (var ticker in portfolio.Assets.Select(a => a.Ticker)) { if (!pricesMap.ContainsKey(ticker)) { throw new ArgumentException($"There is no price for ticker '{ticker}' in portfolio."); } } foreach (var ticker in allocation.Portions.Select(p => p.Ticker)) { if (!pricesMap.ContainsKey(ticker)) { throw new ArgumentException($"There is no price for ticker '{ticker}' in asset allocation."); } } }