| Overall Statistics |
|
Total Trades 998 Average Win 0.54% Average Loss -0.62% Compounding Annual Return 5.092% Drawdown 16.300% Expectancy 0.085 Net Profit 28.224% Sharpe Ratio 0.557 Probabilistic Sharpe Ratio 13.054% Loss Rate 42% Win Rate 58% Profit-Loss Ratio 0.87 Alpha 0.047 Beta -0.015 Annual Standard Deviation 0.081 Annual Variance 0.007 Information Ratio -0.491 Tracking Error 0.192 Treynor Ratio -2.938 Total Fees $8241.01 Estimated Strategy Capacity $90000.00 Lowest Capacity Asset IYY RVLEALAHHC2T |
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.Indicators;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace QuantConnect.Algorithm.CSharp
{
public class MacdGoldenCross : QCAlgorithm
{
private static Symbol[] _symbols = new Symbol[] { QuantConnect.Symbol.Create("IYY", SecurityType.Equity, Market.USA) };
public override void Initialize()
{
var startYear = 2016;
var endYear = 2021;
var warmup = 150;
SetStartDate(new DateTime(startYear, 1, 1));
SetEndDate(new DateTime(endYear, 1, 1));
SetCash(100000);
UniverseSettings.Resolution = Resolution.Daily;
SetWarmup(new TimeSpan(warmup, 0, 0, 0));
EnableAutomaticIndicatorWarmUp = true;
SetUniverseSelection(new ManualUniverseSelectionModel(_symbols));
AddAlpha(new GoldenCrossAlpha());
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
SetExecution(new ImmediateExecutionModel());
//AddRiskManagement(new MaximumUnrealizedProfitPercentPerSecurity(0.1m));
AddRiskManagement(riskManagement: new MaximumDrawdownPercentPerSecurity(0.05m));
var spy = AddEquity("SPY", Resolution.Daily);
AddRiskManagement(new MarketSmaLimit(spy.Symbol, SMA(spy.Symbol, 150, Resolution.Daily)));
}
private class SymbolData
{
public MovingAverageConvergenceDivergence Macd { get; private set; }
public SymbolData(Symbol symbol, QCAlgorithm algo, MacdSettings settings)
{
Macd = algo.MACD(symbol, settings.Fast, settings.Slow, settings.Signal, MovingAverageType.Exponential, Resolution.Daily);
}
}
private struct MacdSettings
{
public int Fast { get; set; }
public int Slow { get; set; }
public int Signal { get; set; }
}
private class GoldenCrossAlpha : IAlphaModel
{
private readonly Dictionary<Symbol, SymbolData> _symbols = new Dictionary<Symbol, SymbolData>();
private MacdSettings _macdSettings;
public GoldenCrossAlpha(int fast = 12, int slow = 26, int signal = 9)
{
_macdSettings = new MacdSettings()
{
Fast = fast,
Slow = slow,
Signal = signal
};
}
public void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
if (algorithm.IsWarmingUp)
return;
foreach (var added in changes.AddedSecurities)
{
if (!_symbols.ContainsKey(added.Symbol))
{
_symbols.Add(added.Symbol, new SymbolData(added.Symbol, algorithm, _macdSettings));
}
}
foreach (var removed in changes.RemovedSecurities)
{
if (_symbols.ContainsKey(removed.Symbol))
{
_symbols.Remove(removed.Symbol);
}
}
}
public IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
List<Insight> insights = new List<Insight>();
if (algorithm.IsWarmingUp)
return insights;
foreach (var symbol in data.Keys)
{
if (!_symbols.ContainsKey(symbol) || symbol.Value == "SPY")
continue;
var symbolData = _symbols[symbol];
if (!algorithm.Securities[symbol].Invested)
{
if (symbolData.Macd.Fast > symbolData.Macd.Slow)
{
insights.Add(new Insight(symbol, new TimeSpan(), InsightType.Price, InsightDirection.Up));
}
}
else
{
if (symbolData.Macd.Fast < symbolData.Macd.Slow)
{
insights.Add(new Insight(symbol, new TimeSpan(), InsightType.Price, InsightDirection.Down));
}
}
}
return insights;
}
}
private class MarketSmaLimit : RiskManagementModel
{
private readonly Symbol _benchmark;
private readonly SimpleMovingAverage _sma;
public MarketSmaLimit(Symbol benchmark, SimpleMovingAverage sma)
{
_benchmark = benchmark;
_sma = sma;
}
public override IEnumerable<IPortfolioTarget> ManageRisk(QCAlgorithm algorithm, IPortfolioTarget[] targets)
{
var results = new List<IPortfolioTarget>();
var price = algorithm.Portfolio.Securities[_benchmark].Price;
if (price < _sma.Current.Value)
{
algorithm.Debug("Closing all open positions due to SPY falling below SMA");
foreach(var security in algorithm.ActiveSecurities.Values)
{
if(security.Invested)
{
results.Add(new PortfolioTarget(security.Symbol, 0));
}
}
return results;
}
else
{
return targets;
}
}
}
}
}