Overall Statistics |
Total Trades 13 Average Win 9.57% Average Loss -2.83% Compounding Annual Return 15.007% Drawdown 19.100% Expectancy 1.021 Net Profit 39.981% Sharpe Ratio 0.864 Loss Rate 54% Win Rate 46% Profit-Loss Ratio 3.38 Alpha 0.251 Beta -0.497 Annual Standard Deviation 0.181 Annual Variance 0.033 Information Ratio -0.144 Tracking Error 0.242 Treynor Ratio -0.314 Total Fees $32.61 |
using System; using System.Collections.Generic; using QuantConnect; using QuantConnect.Data; using QuantConnect.Data.Market; using QuantConnect.Indicators; using QuantConnect.Securities; using QuantConnect.Securities.Equity; namespace QuantConnect { public class EMACrossingHMA : QCAlgorithm { /* +--------------------------------------------+ * |Control Panel - Making overfitting easier | * +--------------------------------------------+*/ int HMAPeriod = 4; // The Hull Moving Average period int slowEMAPeriod = 15; // A Slow EMA period static int lookbackWindow = 45; // Channel lookback used to estimate the uppenr and lower bands /* +--------------------------------------------+*/ string symbol = "SPY"; IndicatorBase<IndicatorDataPoint> HMA; ExponentialMovingAverage slowEMA; CompositeIndicator<IndicatorDataPoint> signal; Resolution resolution = Resolution.Daily; RollingWindow<decimal> Band = new RollingWindow<decimal>(lookbackWindow); // NEW: added code to map between regular and trade bar indicators DonchianChannel Channel = new DonchianChannel("myChannel", 10); public override void Initialize() { SetStartDate(2013, 1, 1); SetEndDate(2015, 5, 31); SetCash(25000); AddSecurity(SecurityType.Equity, symbol, resolution); slowEMA = EMA(symbol, slowEMAPeriod, resolution); // hull has two 'source' indicators, a fast and slow int period = HMAPeriod; int slow = (int) Math.Pow(period, 2); int fast = slow/2; var slowLwma = LWMA("SPY", slow); var fastLwma = LWMA("SPY", fast); var twiceFast = fastLwma.Times(new ConstantIndicator<IndicatorDataPoint>("2", 2)); var interior = twiceFast.Minus(slowLwma); HMA = new LinearWeightedMovingAverage(period).Of(interior); //HMA = new HullMovingAverage("HMA(" + symbol + ")", HMAPeriod); // Why is the name needed? Func<BaseData, decimal> selector = null; // I really don't know what this does, but make it work :P RegisterIndicator(symbol, HMA, resolution, selector); signal = HMA.Minus(slowEMA); // this is not very pretty, but it creates an intermediate indicator to accept the signal data // and then transform it into a trade bar for the Channel Channel.AsSimpleIndicator().Of(signal); } bool first = true; public void OnData(TradeBars data) { // I tried to use something like: // Channel.Of(signal); // but didn't work. if (!slowEMA.IsReady || !HMA.IsReady) return; if (Band.IsReady && Channel.IsReady) { if (first) { // PlotIndicator will plot the indicator on each new data point, very awesome! // this version, however, doesn't wait until the indicator is ready, so I added // this ugly code to just wait until they're ready, and then call PlotIndicator // to register for auto-plotting first = false; PlotIndicator("SPY_Hull", HMA); PlotIndicator("SPY_Signal", Channel.UpperBand, Channel.LowerBand, signal); } // Estimating the upper and lower channel band. // Is there a better way? decimal upperBand = decimal.MinValue; decimal lowerBand = decimal.MaxValue; for (int i = 0; i < Band.Count; i++) { upperBand = Math.Max(Band[i], upperBand); lowerBand = Math.Min(Band[i], lowerBand); } // Defining the signals bool longSignal = signal < lowerBand; bool shortSignal = signal > upperBand; // If we don't hold any position if (!Portfolio[symbol].HoldStock) { if (longSignal) SetHoldings(symbol, 1); if (shortSignal) SetHoldings(symbol, -1); } // If we have hold some position else { if (Portfolio[symbol].IsLong && shortSignal) Liquidate(symbol); if (Portfolio[symbol].IsShort && longSignal) Liquidate(symbol); } Band.Add(signal); // Update the channel. } else Band.Add(signal); // Update the channel window until is ready. } } public static class MoreIndicatorExtensions { public static IndicatorBase<IndicatorDataPoint> AsSimpleIndicator(this IndicatorBase<TradeBar> indicator) { return new AsSimpleIndicatorAdapter(indicator); } private sealed class AsSimpleIndicatorAdapter : IndicatorBase<IndicatorDataPoint> { private readonly IndicatorBase<TradeBar> _indicator; public AsSimpleIndicatorAdapter(IndicatorBase<TradeBar> indicator) : base(indicator.Name + "_tb_adapter") { _indicator = indicator; } public override bool IsReady { get { return _indicator.IsReady; } } protected override decimal ComputeNextValue(IndicatorDataPoint input) { _indicator.Update(new TradeBar { Symbol = input.Symbol, Time = input.Time, EndTime = input.EndTime, Value = input.Value, Close = input.Value, High = input.Value, Low = input.Value, Open = input.Value, Period = input.EndTime - input.Time, Volume = 0 }); return _indicator.Current.Value; } } } }