/* * 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.Data.UniverseSelection; using QuantConnect.Orders.Fees; using System; using System.Collections.Generic; using System.Linq; namespace QuantConnect.Algorithm.CSharp.Alphas { /// /// Identify "pumped" penny stocks and predict that the price of a "Pumped" penny stock reverts to mean /// /// 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 SykesShortMicroCapAlpha : QCAlgorithm { public override void Initialize() { SetStartDate(2018, 1, 1); SetCash(100000); // Set zero transaction fees SetSecurityInitializer(security => security.FeeModel = new ConstantFeeModel(0)); // Select stocks using PennyStockUniverseSelectionModel UniverseSettings.Resolution = Resolution.Daily; SetUniverseSelection(new PennyStockUniverseSelectionModel()); // Use SykesShortMicroCapAlphaModel to establish insights SetAlpha(new SykesShortMicroCapAlphaModel()); // 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()); } /// /// Performs coarse selection for constituents. /// The stocks must have fundamental data /// The stock must have positive previous-day close price /// The stock must have volume between $1000000 and $10000 on the previous trading day /// The stock must cost less than $5''' /// private class PennyStockUniverseSelectionModel : FundamentalUniverseSelectionModel { private const int _numberOfSymbolsCoarse = 500; private int _lastMonth = -1; public PennyStockUniverseSelectionModel() : base(false) { } public override IEnumerable SelectCoarse(QCAlgorithm algorithm, IEnumerable coarse) { var month = algorithm.Time.Month; if (month == _lastMonth) { return algorithm.Universe.Unchanged; } _lastMonth = month; return (from cf in coarse where cf.HasFundamentalData where cf.Volume < 1000000 where cf.Volume > 10000 where cf.Price < 5 orderby cf.DollarVolume descending select cf.Symbol).Take(_numberOfSymbolsCoarse); } } /// /// Uses ranking of intraday percentage difference between open price and close price to create magnitude and direction prediction for insights /// private class SykesShortMicroCapAlphaModel : AlphaModel { private readonly int _numberOfStocks; private readonly TimeSpan _predictionInterval; public SykesShortMicroCapAlphaModel( int lookback = 1, int numberOfStocks = 10, Resolution resolution = Resolution.Daily) { _numberOfStocks = numberOfStocks; _predictionInterval = resolution.ToTimeSpan().Multiply(lookback); } public override IEnumerable Update(QCAlgorithm algorithm, Slice data) { return ( from entry in algorithm.ActiveSecurities let security = entry.Value where security.HasData && security.Open > 0 // Rank penny stocks on one day price change let Magnitude = security.Close / security.Open - 1 orderby Math.Round(Magnitude, 6), security.Symbol descending select Insight.Price(security.Symbol, _predictionInterval, InsightDirection.Down, Math.Abs((double)Magnitude))) // Retrieve list of _numberOfStocks "pumped" penny stocks .Take(_numberOfStocks); } } } }