| Overall Statistics |
|
Total Trades 14 Average Win 0.94% Average Loss -0.77% Compounding Annual Return -6.387% Drawdown 6.600% Expectancy -0.446 Net Profit -2.696% Sharpe Ratio -0.501 Loss Rate 75% Win Rate 25% Profit-Loss Ratio 1.22 Alpha 0.045 Beta -0.301 Annual Standard Deviation 0.098 Annual Variance 0.01 Information Ratio -2.28 Tracking Error 0.158 Treynor Ratio 0.163 Total Fees $19.42 |
namespace QuantConnect
{
/*
* QuantConnect University: Full Basic Template:
*
* The underlying QCAlgorithm class is full of helper methods which enable you to use QuantConnect.
* We have explained some of these here, but the full algorithm can be found at:
* https://github.com/QuantConnect/QCAlgorithm/blob/master/QuantConnect.Algorithm/QCAlgorithm.cs
*/
public class BasicTemplateAlgorithm : QCAlgorithm
{
private Vortex vtx;
public static QCAlgorithm Instance;
//Initialize the data and resolution you require for your strategy:
public override void Initialize()
{
Instance = this;
//Start and End Date range for the backtest:
SetStartDate(2013, 1, 1);
SetEndDate(2013, 6, 1);
//Cash allocation
SetCash(25000);
//Add as many securities as you like. All the data will be passed into the event handler:
AddSecurity(SecurityType.Equity, "SPY", Resolution.Daily);
vtx = new Vortex(14);
RegisterIndicator("SPY", vtx, Resolution.Daily);
PlotIndicator("Vortex", vtx.HI, vtx.LO);
PlotIndicator("VortexValue", vtx);
}
//Data Event Handler: New data arrives here. "TradeBars" type is a dictionary of strings so you can access it by symbol.
public void OnData(TradeBars data)
{
if (!vtx.IsReady) {
return ;
}
Log(vtx.HI.Current.Value.ToString());
Log(vtx.LO.Current.Value.ToString());
//Log(vtx.VMplus.Current.Value.ToString());
//Log(vtx.VMminus.Current.Value.ToString());
//Log(vtx.VIplus.Current.Value.ToString());
//Log(vtx.VIminus.Current.Value.ToString());
//Log(vtx.TrueRange.Current.Value.ToString());
//Plot("Vortex", vtx.VIplus, vtx.VIminus);
//var quantity = Portfolio["SPY"].Quantity;
//Console.WriteLine((vtx.VIplus-vtx.VIminus).ToString());
if ( vtx.VIplus > vtx.VIminus)
{
SetHoldings("SPY", 1.0);
}
else
{
SetHoldings("SPY", -1.0);
}
}
}
}using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// SumTrueRange is defined as the maximum of the following:
/// High - Low
/// ABS(High - PreviousClose)
/// ABS(Low - PreviousClose)
/// Summed over a N peridos window
/// VMplus:
///
/// SUM(ABS(High - previous.Low), N periods)
/// VMminus:
///
/// SUM(ABS(High - previous.High), N periods)
/// Vortex Indicator:
/// VMplus / SumTrueRange - VMminus / SumTrueRange
///
///
/// </summary>
public class Vortex : TradeBarIndicator
{
private int _period;
private TradeBar previous = null;
public IndicatorBase<TradeBar> TrueRange { get; private set; }
public IndicatorBase<TradeBar> HI { get; private set; }
public IndicatorBase<TradeBar> LO { get; private set; }
public IndicatorBase<IndicatorDataPoint> RollingSumTR { get; private set; }
public IndicatorBase<IndicatorDataPoint> VMplus { get; private set; }
public IndicatorBase<IndicatorDataPoint> VMminus { get; private set; }
public IndicatorBase<TradeBar> VIplus { get; private set; }
public IndicatorBase<TradeBar> VIminus { get; private set; }
public override bool IsReady
{
get { return Samples > _period; }
}
public Vortex(string name, int period)
: base(name)
{
_period = period;
RollingSumTR = new Sum(name + "_SumTR", period);
VMplus = new Sum(name + "_Plus", period);
VMminus = new Sum(name + "_Minus", period);
HI = new FunctionalIndicator<TradeBar>(name + period, currentBar =>
{
// in our ComputeNextValue function we'll just call the ComputeTrueRange
var nextValue = ComputeHI(previous, currentBar);
return nextValue;
} // in our IsReady function we just need at least two sample
, trueRangeIndicator => trueRangeIndicator.Samples >= _period
);
LO = new FunctionalIndicator<TradeBar>(name + period, currentBar =>
{
// in our ComputeNextValue function we'll just call the ComputeTrueRange
var nextValue = ComputeLO(previous, currentBar);
return nextValue;
} // in our IsReady function we just need at least two sample
, trueRangeIndicator => trueRangeIndicator.Samples >= _period
);
VIminus = new FunctionalIndicator<TradeBar>(name + period +"minus", currentBar=>
ComputeVIminus(currentBar) , trueRangeIndicator => trueRangeIndicator.Samples >= _period
);
VIplus = new FunctionalIndicator<TradeBar>(name + period +"plus", currentBar=>
ComputeVIplus(currentBar) , trueRangeIndicator => trueRangeIndicator.Samples >= _period
);
TrueRange = new FunctionalIndicator<TradeBar>(name + "_TrueRange", currentBar =>
{
// in our ComputeNextValue function we'll just call the ComputeTrueRange
var nextValue = ComputeSumTrueRange(previous, currentBar);
return nextValue;
} // in our IsReady function we just need at least two sample
, trueRangeIndicator => trueRangeIndicator.Samples >= _period
);
}
public Vortex(int period)
: this("Vortex" + period, period)
{
}
public decimal ComputeSumTrueRange(TradeBar previous, TradeBar current)
{
if (previous == null)
{
return 0;
}
var range1 = current.High - current.Low;
var range2 = Math.Abs(current.High - previous.Close);
var range3 = Math.Abs(current.Low - previous.Close);
return Math.Max(range1, Math.Max(range2, range3));
}
public decimal ComputeHI(TradeBar previous, TradeBar current)
{
if (previous == null)
{
return 0;
}
var _HI = Math.Abs(current.High - previous.Low);
return _HI;
}
public decimal ComputeLO(TradeBar previous, TradeBar current)
{
if (previous == null)
{
return 0;
}
var _LO = Math.Abs(current.Low - previous.High) ;
return _LO;
}
public decimal ComputeVIplus(TradeBar input)
{
if(RollingSumTR.Current.Value == 0) return 0;
return VMplus.Current.Value / RollingSumTR.Current.Value;
}
public decimal ComputeVIminus(TradeBar input)
{
if(RollingSumTR.Current.Value == 0) return 0;
return VMminus.Current.Value / RollingSumTR.Current.Value;
}
protected override decimal ComputeNextValue(TradeBar input)
{
// update the true range and then sum it
TrueRange.Update(input);
RollingSumTR.Update(input.Time, TrueRange.Current.Value);
HI.Update(input);
LO.Update(input);
VMplus.Update(input.Time, HI.Current.Value);
VMminus.Update(input.Time, LO.Current.Value);
VIplus.Update(input);
VIminus.Update(input);
// set the previous in exactly one place and have it be after it's been used
previous = input;
// VMplus / SumTrueRange - VMminus / SumTrueRange
if (RollingSumTR == 0m) return 0m;
return VMplus / RollingSumTR - VMminus / RollingSumTR;
}
public override void Reset()
{
HI.Reset();
LO.Reset();
TrueRange.Reset();
VMplus.Reset();
VMminus.Reset();
RollingSumTR.Reset();
VIplus.Reset();
VIminus.Reset();
base.Reset();
}
}
}