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