Overall Statistics |
Total Trades 2797 Average Win 0.53% Average Loss -0.99% Compounding Annual Return 15.437% Drawdown 44.600% Expectancy 0.079 Net Profit 120.627% Sharpe Ratio 0.626 Probabilistic Sharpe Ratio 14.652% Loss Rate 30% Win Rate 70% Profit-Loss Ratio 0.53 Alpha 0.269 Beta -0.183 Annual Standard Deviation 0.391 Annual Variance 0.153 Information Ratio 0.25 Tracking Error 0.447 Treynor Ratio -1.335 Total Fees $4265.35 |
namespace QuantConnect.Algorithm.CSharp { using QuantConnect.Algorithm; 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; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; // public class EmaCrossAlphaModelX : EmaCrossAlphaModel // { // public EmaCrossAlphaModelX(int fastPeriod = 12, int slowPeriod = 26, Resolution resolution = Resolution.Daily) : base(fastPeriod, slowPeriod, resolution) { } // public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data) // { // var updates = base.Update(algorithm, data); // //return updates; // double? equal = 10.0 / (((SeparatedConcernEMAWeighted)algorithm).tickers.Count * 1.0); // List<Insight> weighted = new List<Insight>(); // foreach (var update in updates) // { // Insight temp = null; // if (update.Weight.HasValue == false || update.Weight.Value == 0.0) // { // temp = new Insight( // update.Symbol, // update.Period, // update.Type, // update.Direction, // update.Magnitude, // update.Confidence, // update.SourceModel, // equal); // } // else // { // temp = update; // } // weighted.Add(temp); // } // return weighted; // } // public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes) // { // base.OnSecuritiesChanged(algorithm, changes); // } // } public class StandardDeviationExecutionModelX : StandardDeviationExecutionModel { public StandardDeviationExecutionModelX(int period = 60, decimal deviations = 2, Resolution resolution = Resolution.Hour) : base(period, deviations, resolution) { } public override void Execute(QCAlgorithm algorithm, IPortfolioTarget[] targets) { base.Execute(algorithm, targets); } public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes) { base.OnSecuritiesChanged(algorithm, changes); } } public class InsightWeightingPortfolioConstructionModelX : InsightWeightingPortfolioConstructionModel { public override IEnumerable<IPortfolioTarget> CreateTargets(QCAlgorithm algorithm, Insight[] insights) { return base.CreateTargets(algorithm, insights); } public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes) { base.OnSecuritiesChanged(algorithm, changes); } protected override Dictionary<Insight, double> DetermineTargetPercent(List<Insight> activeInsights) { return base.DetermineTargetPercent(activeInsights); } protected override double GetValue(Insight insight) { return base.GetValue(insight); //return insight.Score.Direction; } } public class MaximumUnrealizedProfitPercentPerSecurityX : MaximumUnrealizedProfitPercentPerSecurity { public MaximumUnrealizedProfitPercentPerSecurityX(decimal maximumUnrealizedProfitPercent = 0.05M) : base(maximumUnrealizedProfitPercent) { } public override IEnumerable<IPortfolioTarget> ManageRisk(QCAlgorithm algorithm, IPortfolioTarget[] targets) { return base.ManageRisk(algorithm, targets); } public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes) { base.OnSecuritiesChanged(algorithm, changes); } } public class SeparatedConcernEMAWeighted : QCAlgorithm { public Dictionary<int, Insight> insights = new Dictionary<int, Insight>(); int i = 0; //random stock picks. replace these with your own picks public List<string> tickers = new List<string> { "GILD", "ABMD", "UNH", "ALXN", "BLK", "HFC", "KSU" }; public override void Initialize() { SetStartDate(2015, 4, 5); //Set Start Date SetCash(100000); //Set Strategy Cash // // AddEquity("SPY", Resolution.Hour); AddAlpha(new WeightedEmaCrossAlphaModel(50, 200, Resolution.Hour)); SetExecution(new StandardDeviationExecutionModelX(60, 0.75m, Resolution.Hour)); //SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel()); SetPortfolioConstruction(new InsightWeightingPortfolioConstructionModelX()); //SetRiskManagement(new MaximumUnrealizedProfitPercentPerSecurityX(0.03m)); SetRiskManagement(new MaximumDrawdownPercentPerSecurity(0.09m)); UniverseSettings.Resolution = Resolution.Hour; var symbols = tickers.Select(t => QuantConnect.Symbol.Create(t, SecurityType.Equity, Market.USA)).ToArray(); SetUniverseSelection(new LiquidETFUniverse()); //SetUniverseSelection(new ManualUniverseSelectionModel(symbols)); //InsightsGenerated += SeparatedConcernEMAWeighted_InsightsGenerated; } private void SeparatedConcernEMAWeighted_InsightsGenerated(Interfaces.IAlgorithm algorithm, GeneratedInsightsCollection eventData) { //Insight.CloseTimeUtc //Insight.Confidence //Insight.Direction //Insight.EstimatedValue //Insight.GeneratedTimeUtc //Insight.GroupId //Insight.Id //Insight.Magnitude //Insight.Period //Insight.ReferenceValue //Insight.ReferenceValueFinal //Insight.Score //Insight.SourceModel //Insight.Symbol //Insight.Type //Insight.Weight //this.EmitInsights foreach (var insight in eventData.Insights) { insights.Add(i++, insight); } //delete old insights var keys = new List<int>(); foreach (var kvp in insights) { if (kvp.Value.IsActive(Time) == false) { keys.Add(kvp.Key); } } keys.ForEach(k => insights.Remove(k)); } public static OrderDirection ItoODir(InsightDirection direction) { switch (direction) { case InsightDirection.Down: return OrderDirection.Sell; case InsightDirection.Up: return OrderDirection.Buy; default: return OrderDirection.Hold; } } // 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) { // //foreach (var target in PortfolioConstruction.CreateTargets(this, insights.Values.ToArray())) // foreach(var insight in insights) // { // if(data.ContainsKey(insight.Value.Symbol) == false) continue; // var cash = Portfolio.Cash; // var holding = Portfolio[insight.Value.Symbol]; // //holding.SetHoldings(holding.Price, Portfolio.GetMarginRemaining(insight.Value.Symbol, ItoODir(insight.Value.Direction))); // if(insight.Value.Direction == InsightDirection.Up) // { // SetHoldings(insight.Value.Symbol, 1.0m/tickers.Count); // //Debug(insight.Value.Symbol.Value + ": before; " + cash + ", after; " + Portfolio.Cash); // } // if(insight.Value.Direction == InsightDirection.Down) // { // SetHoldings(insight.Value.Symbol, -1.0m/tickers.Count); // //Debug(insight.Value.Symbol.Value + ": before; " + cash + ", after; " + Portfolio.Cash); // } // } } public override void OnWarmupFinished() { } public override void OnOrderEvent(OrderEvent orderEvent) { } public override void OnSecuritiesChanged(SecurityChanges changes) { } } }
using System.Collections.Generic; using QuantConnect.Data; using QuantConnect.Data.UniverseSelection; using QuantConnect.Indicators; using QuantConnect.Securities; namespace QuantConnect.Algorithm.Framework.Alphas { /// <summary> /// Alpha model that uses an EMA cross to create insights /// </summary> public class WeightedEmaCrossAlphaModel : AlphaModel { private readonly int _fastPeriod; private readonly int _slowPeriod; private readonly Resolution _resolution; private readonly int _predictionInterval; private readonly Dictionary<Symbol, SymbolData> _symbolDataBySymbol; /// <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 WeightedEmaCrossAlphaModel( int fastPeriod = 12, int slowPeriod = 26, Resolution resolution = Resolution.Daily ) { _fastPeriod = fastPeriod; _slowPeriod = slowPeriod; _resolution = resolution; _predictionInterval = fastPeriod; _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) { var insights = new List<Insight>(); foreach (var symbolData in _symbolDataBySymbol.Values) { if (symbolData.Fast.IsReady && symbolData.Slow.IsReady) { var ratio1 = (double)symbolData.Slow.Current.Value/ (double)symbolData.Fast.Current.Value; var ratio2 = (double)symbolData.Fast.Current.Value / (double)symbolData.Slow.Current.Value; var insightPeriod = _resolution.ToTimeSpan().Multiply(_predictionInterval); if (symbolData.FastIsOverSlow) { if (ratio1 > 1.0005) { insights.Add(Insight.Price( symbolData.Symbol, _resolution, _predictionInterval, InsightDirection.Down, null, null, null, ratio1*ratio1*ratio1 )); } } else if (symbolData.SlowIsOverFast) { if (ratio2 > 1.0005) { insights.Add(Insight.Price( symbolData.Symbol, _resolution, _predictionInterval, InsightDirection.Up, null, null, null, ratio2*ratio2*ratio2 )); } } } symbolData.FastIsOverSlow = symbolData.Fast > symbolData.Slow; } 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) { foreach (var added in changes.AddedSecurities) { SymbolData symbolData; if (!_symbolDataBySymbol.TryGetValue(added.Symbol, out symbolData)) { // create fast/slow EMAs var fast = algorithm.EMA(added.Symbol, _fastPeriod, _resolution); var slow = algorithm.EMA(added.Symbol, _slowPeriod, _resolution); _symbolDataBySymbol[added.Symbol] = new SymbolData { Security = added, Fast = fast, Slow = slow }; } else { // a security that was already initialized was re-added, reset the indicators symbolData.Fast.Reset(); symbolData.Slow.Reset(); } } } /// <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; } } }