/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using QuantConnect.Algorithm.Framework.Alphas; using QuantConnect.Algorithm.Framework.Execution; using QuantConnect.Algorithm.Framework.Portfolio; using QuantConnect.Algorithm.Framework.Risk; using QuantConnect.Algorithm.Framework.Selection; using QuantConnect.Data; using QuantConnect.Orders.Fees; using System; using System.Collections.Generic; using System.Linq; namespace QuantConnect.Algorithm.CSharp.Alphas { /// /// Equity indices exhibit mean reversion in daily returns. The Internal Bar Strength indicator (IBS), /// which relates the closing price of a security to its daily range can be used to identify overbought /// and oversold securities. /// /// This alpha ranks 33 global equity ETFs on its IBS value the previous day and predicts for the following day /// that the ETF with the highest IBS value will decrease in price, and the ETF with the lowest IBS value /// will increase in price. /// /// Source: Kakushadze, Zura, and Juan Andrés Serur. “4. Exchange-Traded Funds (ETFs).” 151 Trading Strategies, Palgrave Macmillan, 2018, pp. 90–91. /// /// This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha. /// public class GlobalEquityMeanReversionIBSAlpha : QCAlgorithm { public override void Initialize() { SetStartDate(2018, 1, 1); SetCash(100000); // Set zero transaction fees SetSecurityInitializer(security => security.FeeModel = new ConstantFeeModel(0)); // Global Equity ETF tickers var symbols = new[] { "ECH", "EEM", "EFA", "EPHE", "EPP", "EWA", "EWC", "EWG", "EWH", "EWI", "EWJ", "EWL", "EWM", "EWM", "EWO", "EWP", "EWQ", "EWS", "EWT", "EWU", "EWY", "EWZ", "EZA", "FXI", "GXG", "IDX", "ILF", "EWM", "QQQ", "RSX", "SPY", "THD"} .Select(x => QuantConnect.Symbol.Create(x, SecurityType.Equity, Market.USA)); // Manually curated universe UniverseSettings.Resolution = Resolution.Daily; SetUniverseSelection(new ManualUniverseSelectionModel(symbols)); // Use MeanReversionIBSAlphaModel to establish insights SetAlpha(new MeanReversionIBSAlphaModel()); // Equally weigh securities in portfolio, based on insights SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel()); // Set Immediate Execution Model SetExecution(new ImmediateExecutionModel()); // Set Null Risk Management Model SetRiskManagement(new NullRiskManagementModel()); } /// /// Uses ranking of Internal Bar Strength (IBS) to create direction prediction for insights /// private class MeanReversionIBSAlphaModel : AlphaModel { private readonly int _numberOfStocks; private readonly TimeSpan _predictionInterval; public MeanReversionIBSAlphaModel( int lookback = 1, int numberOfStocks = 2, Resolution resolution = Resolution.Daily) { _numberOfStocks = numberOfStocks; _predictionInterval = resolution.ToTimeSpan().Multiply(lookback); } public override IEnumerable Update(QCAlgorithm algorithm, Slice data) { var symbolsIBS = new Dictionary(); var returns = new Dictionary(); foreach (var kvp in algorithm.ActiveSecurities) { var security = kvp.Value; if (security.HasData) { var high = security.High; var low = security.Low; var hilo = high - low; // Do not consider symbol with zero open and avoid division by zero if (security.Open * hilo != 0) { // Internal bar strength (IBS) symbolsIBS.Add(security.Symbol, (security.Close - low) / hilo); returns.Add(security.Symbol, security.Close / security.Open - 1); } } } var insights = new List(); // Number of stocks cannot be higher than half of symbolsIBS length var numberOfStocks = Math.Min((int)(symbolsIBS.Count / 2.0), _numberOfStocks); if (numberOfStocks == 0) { return insights; } // Rank securities with the highest IBS value var ordered = from entry in symbolsIBS orderby Math.Round(entry.Value, 6) descending, entry.Key select entry; var highIBS = ordered.Take(numberOfStocks); // Get highest IBS var lowIBS = ordered.Reverse().Take(numberOfStocks); // Get lowest IBS // Emit "down" insight for the securities with the highest IBS value foreach (var kvp in highIBS) { insights.Add(Insight.Price(kvp.Key, _predictionInterval, InsightDirection.Down, Math.Abs((double)returns[kvp.Key]))); } // Emit "up" insight for the securities with the highest IBS value foreach (var kvp in lowIBS) { insights.Add(Insight.Price(kvp.Key, _predictionInterval, InsightDirection.Up, Math.Abs((double)returns[kvp.Key]))); } return insights; } } } }