Overall Statistics |
Total Trades 5039 Average Win 0.28% Average Loss -0.32% Compounding Annual Return 28.718% Drawdown 14.400% Expectancy 0.041 Net Profit 83.625% Sharpe Ratio 1.308 Loss Rate 44% Win Rate 56% Profit-Loss Ratio 0.86 Alpha 0.285 Beta -0.057 Annual Standard Deviation 0.21 Annual Variance 0.044 Information Ratio 0.357 Tracking Error 0.242 Treynor Ratio -4.837 Total Fees $18681.87 |
using System; using System.Collections.Generic; 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"; HullMovingAverage HMA; ExponentialMovingAverage slowEMA; CompositeIndicator<IndicatorDataPoint> signal; Resolution resolution = Resolution.Minute; RollingWindow<decimal> Band = new RollingWindow<decimal>(lookbackWindow); // A failed try 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); 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); } 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) { // 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. } } }
/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; namespace QuantConnect.Indicators { /// <summary> /// Represents the Hull moving average indicator (HMA). /// The Hull Moveing Average is a LWMA applied to difference of two Price LWMA /// For example a HMA of period 4 is calucalted as follows: /// TMP = 2 * FastLWMA(Price) - SlowLWMA(Price) /// HMA(4) = HullLWMA(TMP) /// /// As default: /// The slow LWMA period is the HMA period squared /// The fast LWMA period is the half of the slow EMA period /// /// </summary> public class HullMovingAverage : Indicator { private readonly int _periodHMA; private readonly int _periodSlowLWMA; private readonly int _periodFastLWMA; decimal slowLWMA; decimal fastLWMA; decimal previousSlowLWMA; decimal previousfastLWMA; Queue<decimal> windowSlowLWMA = new Queue<decimal>(); Queue<decimal> windowFastLWMA = new Queue<decimal>(); Queue<decimal> windowHMA = new Queue<decimal>(); /// <summary> /// Initializes a new instance of the HullMovingAverage class with the specified name and Hull period /// </summary> /// <param name="name">The name of this indicator.</param> /// <param name="period">The period of the HMA.</param> public HullMovingAverage(string name, int period) : base(name) { _periodHMA = period; _periodSlowLWMA = (int)System.Math.Pow(period, 2); _periodFastLWMA = _periodSlowLWMA / 2; } /// <summary> /// Initializes a new instance of the HullMovingAverage class with the specified name and Hull period /// </summary> /// <param name="name">The name of this indicator.</param> /// <param name="HMAperiod">The HMA aperiod.</param> /// <param name="SlowLWMAPeriod">The slow LWMA period.</param> /// <param name="FastWMAPeriod">The fast LWMA period.</param> public HullMovingAverage(string name, int HMAperiod, int SlowLWMAPeriod, int FastWMAPeriod) :base(name) { _periodHMA = HMAperiod; _periodSlowLWMA = SlowLWMAPeriod; _periodFastLWMA = FastWMAPeriod; } /// <summary> /// Estimate LWMA based in the last observation, the LWMA period and the windows with the previous values. /// </summary> /// <param name="lastInput">The last observation.</param> /// <param name="period">The LWMA period.</param> /// <param name="window">The previos values window.</param> /// <returns>A new value for the LWMA</returns> private decimal _LWMA(decimal lastInput, int period, Queue<decimal> window) { decimal denominator = period * (period + 1) / 2; window.Enqueue(lastInput); if (window.Count > period) { window.Dequeue(); decimal numerator = 0; for (int i = 0; i < window.Count; i++) { numerator += window.ToArray()[i] * (decimal)(i + 1); } return numerator / denominator; } else { return lastInput; } } /// <summary> /// Gets a flag indicating when this indicator is ready and fully initialized /// </summary> public override bool IsReady { get { return Samples > _periodSlowLWMA + _periodHMA; } } /// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(IndicatorDataPoint input) { // our first data point just return identity if (!this.IsReady) { return input; } decimal TMP = 2 * _LWMA(input, _periodFastLWMA, windowFastLWMA) - _LWMA(input, _periodSlowLWMA, windowSlowLWMA); return _LWMA(TMP, _periodHMA, windowHMA); } } }