/// <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(QCAlgorithm algorithm, IPortfolioTarget[] targets) { _targetsCollection.AddRange(targets); // for performance we check count value, OrderByMarginImpact and ClearFulfilled are expensive to call if (_targetsCollection.Count > 0) { foreach (var target in _targetsCollection.OrderByMarginImpact(algorithm)) { var security = algorithm.Securities[target.Symbol]; // calculate remaining quantity to be ordered var quantity = OrderSizing.GetUnorderedQuantity(algorithm, target, security); if (quantity != 0) { if (security.BuyingPowerModel.AboveMinimumOrderMarginPortfolioPercentage(security, quantity, algorithm.Portfolio, algorithm.Settings.MinimumOrderMarginPortfolioPercentage)) { algorithm.MarketOrder(security, quantity); } } } _targetsCollection.ClearFulfilled(algorithm); } }
/// <summary> /// Submit orders for the specified portolio targets if the spread is tighter/equal to preset level /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="targets">The portfolio targets to be ordered</param> public override void Execute(QCAlgorithm algorithm, IPortfolioTarget[] targets) { // update the complete set of portfolio targets with the new targets _targetsCollection.AddRange(targets); // for performance we check count value, OrderByMarginImpact and ClearFulfilled are expensive to call if (_targetsCollection.Count > 0) { foreach (var target in _targetsCollection.OrderByMarginImpact(algorithm)) { var symbol = target.Symbol; // calculate remaining quantity to be ordered var unorderedQuantity = OrderSizing.GetUnorderedQuantity(algorithm, target); if (unorderedQuantity != 0) { // get security object var security = algorithm.Securities[symbol]; // check order entry conditions if (PriceIsFavorable(security)) { algorithm.MarketOrder(symbol, unorderedQuantity); } } } _targetsCollection.ClearFulfilled(algorithm); } }
/// <summary> /// Manages the algorithm's risk at each time step /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="targets">The current portfolio targets to be assessed for risk</param> public override IEnumerable <IPortfolioTarget> ManageRisk(QCAlgorithmFramework algorithm, IPortfolioTarget[] targets) { var maximumSectorExposureValue = algorithm.Portfolio.TotalPortfolioValue * _maximumSectorExposure; _targetsCollection.AddRange(targets); // Group the securities by their sector var groupBySector = algorithm.UniverseManager.ActiveSecurities .Where(x => x.Value.Fundamentals != null && x.Value.Fundamentals.HasFundamentalData) .GroupBy(x => x.Value.Fundamentals.CompanyReference.IndustryTemplateCode); foreach (var securities in groupBySector) { // Compute the sector absolute holdings value // If the construction model has created a target, we consider that // value to calculate the security absolute holding value var sectorAbsoluteHoldingsValue = 0m; foreach (var security in securities) { var absoluteHoldingsValue = security.Value.Holdings.AbsoluteHoldingsValue; IPortfolioTarget target; if (_targetsCollection.TryGetValue(security.Value.Symbol, out target)) { absoluteHoldingsValue = security.Value.Price * Math.Abs(target.Quantity) * security.Value.SymbolProperties.ContractMultiplier * security.Value.QuoteCurrency.ConversionRate; } sectorAbsoluteHoldingsValue += absoluteHoldingsValue; } // If the ratio between the sector absolute holdings value and the maximum sector exposure value // exceeds the unity, it means we need to reduce each security of that sector by that ratio // Otherwise, it means that the sector exposure is below the maximum and there is nothing to do. var ratio = sectorAbsoluteHoldingsValue / maximumSectorExposureValue; if (ratio > 1) { foreach (var security in securities) { var quantity = security.Value.Holdings.Quantity; var symbol = security.Value.Symbol; IPortfolioTarget target; if (_targetsCollection.TryGetValue(symbol, out target)) { quantity = target.Quantity; } if (quantity != 0) { yield return(new PortfolioTarget(symbol, quantity / ratio)); } } } } }
/// <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(); }
/// <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) { _targetsCollection.AddRange(targets); foreach (var target in _targetsCollection.OrderByMarginImpact(algorithm)) { var existing = algorithm.Securities[target.Symbol].Holdings.Quantity + algorithm.Transactions.GetOpenOrders(target.Symbol).Sum(o => o.Quantity); var quantity = target.Quantity - existing; if (quantity != 0) { algorithm.MarketOrder(target.Symbol, quantity); } } _targetsCollection.Clear(); }
/// <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(QCAlgorithm algorithm, IPortfolioTarget[] targets) { _targetsCollection.AddRange(targets); foreach (var target in _targetsCollection.OrderByMarginImpact(algorithm)) { var existing = algorithm.Securities[target.Symbol].Holdings.Quantity + algorithm.Transactions.GetOpenOrderTickets(target.Symbol) .Aggregate(0m, (d, ticket) => d + ticket.Quantity - ticket.QuantityFilled); var quantity = target.Quantity - existing; if (quantity != 0) { algorithm.MarketOrder(target.Symbol, quantity); } } _targetsCollection.ClearFulfilled(algorithm); }
/// <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(QCAlgorithm algorithm, IPortfolioTarget[] targets) { _targetsCollection.AddRange(targets); // for performance we check count value, OrderByMarginImpact and ClearFulfilled are expensive to call if (_targetsCollection.Count > 0) { foreach (var target in _targetsCollection.OrderByMarginImpact(algorithm)) { // calculate remaining quantity to be ordered var quantity = OrderSizing.GetUnorderedQuantity(algorithm, target); if (quantity != 0) { algorithm.MarketOrder(target.Symbol, quantity); } } _targetsCollection.ClearFulfilled(algorithm); } }
/// <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(QCAlgorithm algorithm, IPortfolioTarget[] targets) { _targetsCollection.AddRange(targets); foreach (var target in _targetsCollection.OrderByMarginImpact(algorithm)) { var openQuantity = algorithm.Transactions.GetOpenOrders(target.Symbol) .Sum(x => x.Quantity); var existing = algorithm.Securities[target.Symbol].Holdings.Quantity + openQuantity; var quantity = target.Quantity - existing; // Liquidate positions in Crude Oil ETF that is no longer part of the highest-correlation pair if (_previousSymbol != null && target.Symbol != _previousSymbol) { algorithm.Liquidate(_previousSymbol); } if (quantity != 0) { algorithm.MarketOrder(target.Symbol, quantity); _previousSymbol = target.Symbol; } } _targetsCollection.ClearFulfilled(algorithm); }