| Overall Statistics |
|
Total Trades 24 Average Win 0.31% Average Loss -0.04% Compounding Annual Return 7.670% Drawdown 0.300% Expectancy 0.532 Net Profit 0.243% Sharpe Ratio 2.174 Loss Rate 83% Win Rate 17% Profit-Loss Ratio 8.19 Alpha 0.136 Beta -4.514 Annual Standard Deviation 0.028 Annual Variance 0.001 Information Ratio 1.585 Tracking Error 0.028 Treynor Ratio -0.014 Total Fees $30.79 |
namespace QuantConnect.Algorithm.CSharp
{
public class BasicTemplateFrameworkAlgorithm : QCAlgorithmFramework
{
public SecurityChanges _changes = SecurityChanges.None;
public override void Initialize()
{
SetStartDate(2018, 1, 1); //Set Start Date
SetEndDate(2018, 1, 15); //Set End Date
SetCash(100000); //Set Strategy Cash
// SetTimeZone(TimeZones.Phoenix);
UniverseSettings.Resolution = Resolution.Daily;
UniverseSettings.Leverage = 1;
SetUniverseSelection(new CoarseFundamentalUniverseSelectionModel(CoarseSelectionFunction));
// Example defining an alpha model as a composite of the rsi and ema cross models.
// Replace this with your own combination of alpha models.
SetAlpha(new CompositeAlphaModel(
//new EmaCrossAlphaModel(50, 200, Resolution.Daily)
new MacdAlphaNewModel()
));
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
// SetExecution(new StandardDeviationExecutionModel(60, 2, Resolution.Minute));
// SetRiskManagement(new MaximumDrawdownPercentPerSecurity(0.01m));
}
public static IEnumerable<Symbol> CoarseSelectionFunction(IEnumerable<CoarseFundamental> coarse)
{
// sort descending by daily dollar volume
var sortedByDollarVolume = coarse.OrderByDescending(x => x.DollarVolume);
// take the top 5 entries from our sorted collection
var top5 = sortedByDollarVolume.Take(5);
// we need to return only the symbols
return top5.Select(x => x.Symbol);
}
//Data Event Handler: New data arrives here. "TradeBars" type is a dictionary of strings so you can access it by symbol.
public void OnData(TradeBars data)
{
// Log($"OnData({UtcTime:o}): Keys: {string.Join(", ", data.Keys.OrderBy(x => x))}");
// if we have no changes, do nothing
if (_changes == SecurityChanges.None) return;
// liquidate removed securities
foreach (var security in _changes.RemovedSecurities)
{
if (security.Invested)
{
Liquidate(security.Symbol);
}
}
// we want 20% allocation in each security in our universe
foreach (var security in _changes.AddedSecurities)
{
SetHoldings(security.Symbol, 0.2m);
}
_changes = SecurityChanges.None;
}
// this event fires whenever we have changes to our universe
public override void OnSecuritiesChanged(SecurityChanges changes)
{
_changes = changes;
}
public override void OnOrderEvent(OrderEvent fill)
{
Log($"OnOrderEvent({UtcTime:o}):: {fill}");
}
}
}
// using System.Collections.Generic;
// using QuantConnect.Data;
// using QuantConnect.Data.Consolidators;
// using QuantConnect.Data.UniverseSelection;
// using QuantConnect.Indicators;
// using QuantConnect.Securities;
namespace QuantConnect.Algorithm.Framework.Alphas
{
/// <summary>
/// Defines a custom alpha model that uses MACD crossovers. The MACD signal line is
/// used to generate up/down insights if it's stronger than the bounce threshold.
/// If the MACD signal is within the bounce threshold then a flat price insight is returned.
/// </summary>
public class MacdAlphaNewModel : AlphaModel
{
private readonly int _fastPeriod;
private readonly int _slowPeriod;
private readonly int _signalPeriod;
private readonly MovingAverageType _movingAverageType;
private readonly Resolution _resolution;
private const decimal BounceThresholdPercent = 0.01m;
private readonly Dictionary<Symbol, SymbolData> _symbolData;
/// <summary>
/// Initializes a new instance of the <see cref="MacdAlphaModel"/> class
/// </summary>
/// <param name="fastPeriod">The MACD fast period</param>
/// <param name="slowPeriod">The MACD slow period</param>
/// <param name="signalPeriod">The smoothing period for the MACD signal</param>
/// <param name="movingAverageType">The type of moving average to use in the MACD</param>
/// <param name="resolution">The resolution of data sent into the MACD indicator</param>
public MacdAlphaNewModel(
int fastPeriod = 12,
int slowPeriod = 26,
int signalPeriod = 9,
MovingAverageType movingAverageType = MovingAverageType.Exponential,
Resolution resolution = Resolution.Daily
)
{
_fastPeriod = fastPeriod;
_slowPeriod = slowPeriod;
_signalPeriod = signalPeriod;
_movingAverageType = movingAverageType;
_resolution = resolution;
_symbolData = new Dictionary<Symbol, SymbolData>();
Name = $"{nameof(MacdAlphaModel)}({fastPeriod},{slowPeriod},{signalPeriod},{movingAverageType},{resolution})";
}
/// <summary>
/// Determines an insight for each security based on it's current MACD signal
/// </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(QCAlgorithmFramework algorithm, Slice data)
{
foreach (var sd in _symbolData.Values)
{
if (sd.Security.Price == 0)
{
continue;
}
var direction = InsightDirection.Flat;
var normalizedSignal = sd.MACD.Signal / sd.Security.Price;
if (normalizedSignal > BounceThresholdPercent)
{
direction = InsightDirection.Up;
}
else if (normalizedSignal < -BounceThresholdPercent)
{
direction = InsightDirection.Down;
}
// ignore signal for same direction as previous signal
if (direction == sd.PreviousDirection)
{
continue;
}
var insightPeriod = _resolution.ToTimeSpan().Multiply(_fastPeriod);
var insight = Insight.Price(sd.Security.Symbol, insightPeriod, direction);
sd.PreviousDirection = insight.Direction;
yield return insight;
}
}
/// <summary>
/// Event fired each time the we add/remove securities from the data feed.
/// This initializes the MACD for each added security and cleans up the indicator for each removed security.
/// </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(QCAlgorithmFramework algorithm, SecurityChanges changes)
{
foreach (var added in changes.AddedSecurities)
{
if (!_symbolData.ContainsKey(added.Symbol)){
_symbolData.Add(added.Symbol, new SymbolData(algorithm, added, _fastPeriod, _slowPeriod, _signalPeriod, _movingAverageType, _resolution));
}
}
foreach (var removed in changes.RemovedSecurities)
{
SymbolData data;
if (_symbolData.TryGetValue(removed.Symbol, out data))
{
// clean up our consolidator
algorithm.SubscriptionManager.RemoveConsolidator(data.Security.Symbol, data.Consolidator);
}
}
}
class SymbolData
{
public InsightDirection? PreviousDirection { get; set; }
public readonly Security Security;
public readonly IDataConsolidator Consolidator;
public readonly MovingAverageConvergenceDivergence MACD;
public SymbolData(QCAlgorithmFramework algorithm, Security security, int fastPeriod, int slowPeriod, int signalPeriod, MovingAverageType movingAverageType, Resolution resolution)
{
Security = security;
Consolidator = algorithm.ResolveConsolidator(security.Symbol, resolution);
algorithm.SubscriptionManager.AddConsolidator(security.Symbol, Consolidator);
MACD = new MovingAverageConvergenceDivergence(fastPeriod, slowPeriod, signalPeriod, movingAverageType);
algorithm.RegisterIndicator(security.Symbol, MACD, Consolidator);
}
}
}
}