/// <summary> /// Immediately submits orders for the specified portfolio targets. /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="targets">The portfolio targets to be ordered</param> public override void Execute(QCAlgorithmFramework algorithm, IPortfolioTarget[] targets) { //So target.Quantity represents the ABSOLUTE holding value in the portfolio (usually based on indicator magnitude) // - the execution model should seek to bring the portfolio in line with it. _targetsCollection.AddRange(targets); foreach (var target in _targetsCollection.OrderByMarginImpact(algorithm)) { //only care about derivatives if (!target.Symbol.HasUnderlying) { continue; } var existing = algorithm.Securities[target.Symbol].Holdings.Quantity + algorithm.Transactions.GetOpenOrders(target.Symbol).Sum(o => o.Quantity); decimal quantity = target.Quantity - existing; if (quantity != 0) { if (target.Quantity == 0) { //CLOSING a position, we want to do so immediately //TODO: maybe skew it? algorithm.MarketOrder(target.Symbol, quantity); } else if (MinutesTilClose(algorithm) <= 30) { algorithm.MarketOrder(target.Symbol, target.Quantity); } else { //Adding or entering new position QuoteBar quote = algorithm.CurrentSlice[target.Symbol]; algorithm.LimitOrder(target.Symbol, quantity, Math.Round(quote.Bid.Close + (quote.Ask.Close - quote.Bid.Close) / 2, 2)); } } } //TODO: try resubmitting the order to closer to the spread as time goes by before cancelling/market ordering //convert to market order within 30 mins foreach (var order in algorithm.Transactions.GetOpenOrders(o => (algorithm.CurrentSlice.Time - o.CreatedTime).TotalMinutes >= 30)) { algorithm.Transactions.CancelOrder(order.Id); algorithm.MarketOrder(order.Symbol, order.Quantity); } _targetsCollection.Clear(); }