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