| 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;
}
}
}