| Overall Statistics |
|
Total Trades 4744 Average Win 0.28% Average Loss -0.32% Compounding Annual Return 34.842% Drawdown 10.600% Expectancy 0.051 Net Profit 105.365% Sharpe Ratio 1.57 Loss Rate 44% Win Rate 56% Profit-Loss Ratio 0.88 Alpha 0.342 Beta -0.121 Annual Standard Deviation 0.203 Annual Variance 0.041 Information Ratio 0.548 Tracking Error 0.24 Treynor Ratio -2.633 Total Fees $19845.08 |
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.Minute;
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;
}
}
}
}