/// <summary> /// Gets the point in time portfolio over multiple deployments /// </summary> /// <param name="equityCurve">Equity curve series</param> /// <param name="orders">Orders</param> /// <returns>Enumerable of <see cref="PointInTimePortfolio"/></returns> public static IEnumerable <PointInTimePortfolio> FromOrders(Series <DateTime, double> equityCurve, IEnumerable <Order> orders) { // Don't do anything if we have no orders or equity curve to process if (!orders.Any() || equityCurve.IsEmpty) { yield break; } // Chunk different deployments into separate Lists for separate processing var portfolioDeployments = new List <List <Order> >(); // Orders are guaranteed to start counting from 1. This ensures that we have // no collision at all with the start of a deployment var previousOrderId = 0; var currentDeployment = new List <Order>(); // Make use of reference semantics to add new deployments to the list portfolioDeployments.Add(currentDeployment); foreach (var order in orders) { // In case we have two different deployments with only a single // order in the deployments, <= was chosen because it covers duplicate values if (order.Id <= previousOrderId) { currentDeployment = new List <Order>(); portfolioDeployments.Add(currentDeployment); } currentDeployment.Add(order); previousOrderId = order.Id; } PointInTimePortfolio prev = null; foreach (var deploymentOrders in portfolioDeployments) { // For every deployment, we want to start fresh. var looper = new PortfolioLooper( equityCurve.Where(kvp => kvp.Key <= deploymentOrders.First().Time).LastValue(), deploymentOrders ); foreach (var portfolio in looper.ProcessOrders(deploymentOrders)) { prev = portfolio; yield return(portfolio); } } if (prev != null) { yield return(new PointInTimePortfolio(prev, equityCurve.LastKey())); } }
/// <summary> /// Gets the point in time portfolio over multiple deployments /// </summary> /// <param name="equityCurve">Equity curve series</param> /// <param name="orders">Orders</param> /// <param name="liveSeries">Equity curve series originates from LiveResult</param> /// <returns>Enumerable of <see cref="PointInTimePortfolio"/></returns> public static IEnumerable <PointInTimePortfolio> FromOrders(Series <DateTime, double> equityCurve, IEnumerable <Order> orders, bool liveSeries = false) { // Don't do anything if we have no orders or equity curve to process if (!orders.Any() || equityCurve.IsEmpty) { yield break; } // Chunk different deployments into separate Lists for separate processing var portfolioDeployments = new List <List <Order> >(); // Orders are guaranteed to start counting from 1. This ensures that we have // no collision at all with the start of a deployment var previousOrderId = 0; var currentDeployment = new List <Order>(); // Make use of reference semantics to add new deployments to the list portfolioDeployments.Add(currentDeployment); foreach (var order in orders) { // In case we have two different deployments with only a single // order in the deployments, <= was chosen because it covers duplicate values if (order.Id <= previousOrderId) { currentDeployment = new List <Order>(); portfolioDeployments.Add(currentDeployment); } currentDeployment.Add(order); previousOrderId = order.Id; } PortfolioLooper looper = null; PointInTimePortfolio prev = null; foreach (var deploymentOrders in portfolioDeployments) { if (deploymentOrders.Count == 0) { Log.Trace($"PortfolioLooper.FromOrders(): Deployment contains no orders"); continue; } var startTime = deploymentOrders.First().Time; var deployment = equityCurve.Where(kvp => kvp.Key <= startTime); if (deployment.IsEmpty) { Log.Trace($"PortfolioLooper.FromOrders(): Equity series is empty after filtering with upper bound: {startTime}"); continue; } // Skip any deployments that haven't been ran long enough to be generated in live mode if (liveSeries && deploymentOrders.First().Time.Date == deploymentOrders.Last().Time.Date) { Log.Trace("PortfolioLooper.FromOrders(): Filtering deployment because it has not been deployed for more than one day"); continue; } // For every deployment, we want to start fresh. looper = new PortfolioLooper(deployment.LastValue(), deploymentOrders); foreach (var portfolio in looper.ProcessOrders(deploymentOrders)) { prev = portfolio; yield return(portfolio); } } if (prev != null) { yield return(new PointInTimePortfolio(prev, equityCurve.LastKey())); } looper.DisposeSafely(); }