Overall Statistics |
Total Trades 6 Average Win 8.87% Average Loss -2.48% Compounding Annual Return 0.054% Drawdown 20.400% Expectancy -0.083 Net Profit 0.018% Sharpe Ratio 0.181 Probabilistic Sharpe Ratio 28.174% Loss Rate 80% Win Rate 20% Profit-Loss Ratio 3.58 Alpha 0.066 Beta 0.015 Annual Standard Deviation 0.366 Annual Variance 0.134 Information Ratio 0.119 Tracking Error 0.563 Treynor Ratio 4.333 Total Fees $265.44 Estimated Strategy Capacity $12000.00 Lowest Capacity Asset CERU VPLW2D47KBXH |
/* * 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 System.Collections.Generic; using QuantConnect.Data; using QuantConnect.Data.UniverseSelection; using QuantConnect.Indicators; using QuantConnect.Securities; using QuantConnect.Algorithm.CSharp; namespace QuantConnect.Algorithm.Framework.Alphas { /// <summary> /// Alpha model that uses an EMA cross to create insights /// </summary> public class MyEmaCrossAlphaModel : AlphaModel { private readonly int _fastPeriod; private readonly int _slowPeriod; private readonly Resolution _resolution; private readonly Dictionary<Symbol, SymbolData> _symbolDataBySymbol; private static int numDays = 0; /// <summary> /// Initializes a new instance of the <see cref="EmaCrossAlphaModel"/> class /// </summary> /// <param name="fastPeriod">The fast EMA period</param> /// <param name="slowPeriod">The slow EMA period</param> /// <param name="resolution">The resolution of data sent into the EMA indicators</param> public MyEmaCrossAlphaModel( int fastPeriod, int slowPeriod, Resolution resolution ) { _fastPeriod = fastPeriod; _slowPeriod = slowPeriod; _resolution = resolution; _symbolDataBySymbol = new Dictionary<Symbol, SymbolData>(); Name = $"{nameof(EmaCrossAlphaModel)}({fastPeriod},{slowPeriod},{resolution})"; } /// <summary> /// Updates this alpha model with the latest data from the algorithm. /// This is called each time the algorithm receives data for subscribed securities /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="data">The new data available</param> /// <returns>The new insights generated</returns> public override IEnumerable<Insight> Update(QCAlgorithm _algorithm, Slice data) { EnergeticYellowGreenPelican algorithm = (EnergeticYellowGreenPelican) _algorithm; algorithm.Log("EmaCrossAlphaModel.Update() - data.len=" + data.Count + ", _symbolDataBySymbol.len=" + _symbolDataBySymbol.Count); object x = algorithm.Portfolio.GetType(); object y = data.Keys; // update stop loss foreach (KeyValuePair<Symbol, SecurityHolding> stock in algorithm.Portfolio) { var stopLoss = stock.Value.Price * (1.0m - algorithm.stopLossPercent); if (stock.Key != "dave") x = null; } var insights = new List<Insight>(); var insightPeriod = _resolution.ToTimeSpan().Multiply(20); foreach (var symbolData in _symbolDataBySymbol.Values) { if (symbolData.Fast.IsReady && symbolData.Slow.IsReady) { if (symbolData.FastIsOverSlow) { if (symbolData.Slow > symbolData.Fast) { insights.Add(Insight.Price(symbolData.Symbol, insightPeriod, InsightDirection.Down)); algorithm.Log(symbolData.Symbol + " crossed to down"); } } else if (symbolData.SlowIsOverFast) { if (symbolData.Fast > symbolData.Slow) { insights.Add(Insight.Price(symbolData.Symbol, insightPeriod, InsightDirection.Up)); algorithm.Log(symbolData.Symbol + " crossed to up"); } } } else algorithm.Log(symbolData.Symbol + " symbolData.Fast.IsReady=" + symbolData.Fast.IsReady + ", symbolData.Slow.IsReady=" + symbolData.Slow.IsReady); symbolData.FastIsOverSlow = symbolData.Fast > symbolData.Slow; } numDays ++; if (numDays == 10) { insights.Add(Insight.Price("DARE", _resolution.ToTimeSpan(), InsightDirection.Down)); algorithm.Log("sell DARE"); } if (insights.Count > 0) { algorithm.Log("returning insights, len=" + insights.Count); foreach (var i in insights) algorithm.Log(" " + i.Symbol + " direction=" + i.Direction + " period=" + i.Period); } return insights; } /// <summary> /// Event fired each time the we add/remove securities from the data feed /// </summary> /// <param name="algorithm">The algorithm instance that experienced the change in securities</param> /// <param name="changes">The security additions and removals from the algorithm</param> public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes) { algorithm.Log("EmaCrossAlphaModel.OnSecuritiesChanged()"); foreach (var added in changes.AddedSecurities) { SymbolData symbolData; if (!_symbolDataBySymbol.TryGetValue(added.Symbol, out symbolData)) { algorithm.Log("AddedSecurities new " + added.Symbol); // create fast/slow EMAs var fast = algorithm.EMA(added.Symbol, _fastPeriod, _resolution); algorithm.WarmUpIndicator(added.Symbol, fast, _resolution); var slow = algorithm.EMA(added.Symbol, _slowPeriod, _resolution); algorithm.WarmUpIndicator(added.Symbol, slow, _resolution); _symbolDataBySymbol[added.Symbol] = new SymbolData { Security = added, Fast = fast, Slow = slow }; } else { algorithm.Log("AddedSecurities reset " + added.Symbol); // a security that was already initialized was re-added, reset the indicators symbolData.Fast.Reset(); symbolData.Slow.Reset(); } } foreach (var removed in changes.RemovedSecurities) { algorithm.Log("RemovedSecurities " + removed.Symbol); SymbolData data; //if (_symbolDataBySymbol.Remove(removed.Symbol, out data)) //data.Dispose(); } } /// <summary> /// Contains data specific to a symbol required by this model /// </summary> private class SymbolData { public Security Security { get; set; } public Symbol Symbol => Security.Symbol; public ExponentialMovingAverage Fast { get; set; } public ExponentialMovingAverage Slow { get; set; } /// <summary> /// True if the fast is above the slow, otherwise false. /// This is used to prevent emitting the same signal repeatedly /// </summary> public bool FastIsOverSlow { get; set; } public bool SlowIsOverFast => !FastIsOverSlow; } } }
using QuantConnect.Algorithm.Framework.Alphas; namespace QuantConnect.Algorithm.CSharp { public class EnergeticYellowGreenPelican : QCAlgorithm { public decimal stopLossPercent = 0.02m; public override void Initialize() { SetStartDate(2020, 2, 1); //Set Start Date SetEndDate(2020, 6, 1); //Set End Date SetCash(10000); //Set Strategy Cash SetBenchmark("SPY"); AddEquity("DARE", Resolution.Daily); AddAlpha(new MyEmaCrossAlphaModel(50, 200, Resolution.Daily)); SetExecution(new ImmediateExecutionModel()); SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel()); // SetRiskManagement(new MaximumDrawdownPercentPerSecurity(stopLossPercent)); // SetUniverseSelection(new FineFundamentalUniverseSelectionModel(CoarseSelectionFunction, FineSelectionFunction)); Log("Initialize complete"); } /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. /// Slice object keyed by symbol containing the stock data public override void OnData(Slice data) { Log("OnData"); // if (!Portfolio.Invested) // { // SetHoldings("SPY", 1); // Debug("Purchased Stock"); //} } } }