Overall Statistics |
Total Trades 253 Average Win 1.21% Average Loss -0.62% Compounding Annual Return -0.786% Drawdown 13.400% Expectancy -0.040 Net Profit -2.171% Sharpe Ratio -0.002 Loss Rate 67% Win Rate 33% Profit-Loss Ratio 1.93 Alpha 0.007 Beta -0.059 Annual Standard Deviation 0.123 Annual Variance 0.015 Information Ratio -0.701 Tracking Error 0.18 Treynor Ratio 0.005 Total Fees $288.51 |
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 { public const string Symbol = "SPY"; public TheilSenLinearRegression theilSen; //Initialize the data and resolution you require for your strategy: public override void Initialize() { //Start and End Date range for the backtest: SetStartDate(2013, 1, 1); SetEndDate(DateTime.Now.Date.AddDays(-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, Symbol, Resolution.Daily); var spyDailyClose = Identity(Symbol); theilSen = new TheilSenLinearRegression("lin_reg", 7, ts => (decimal)ts.TotalDays).Of(spyDailyClose); // plot current close and close predicted by theil sen at current time PlotIndicator(Symbol, true, spyDailyClose, theilSen); // plot slope as computed by theil sen PlotIndicator(Symbol + "_Slope", true, theilSen.Slope); } //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 (!theilSen.IsReady) return; if (theilSen.Slope > 0.025m) { SetHoldings(Symbol, 1.0); } else if (theilSen.Slope < 0.025m) { SetHoldings(Symbol, -1.0); } } } }
namespace QuantConnect { /// <summary> /// The Theil-Sen estimator creates a line from the median slopes between all points in the set. /// The primary output value is the value estimated by the linear regression model at the current time. /// </summary> public class TheilSenLinearRegression : WindowIndicator<IndicatorDataPoint> { private readonly Func<TimeSpan, decimal> _timeSpanUnits; private DateTime _start; public IndicatorBase<IndicatorDataPoint> Slope { get; private set; } public TheilSenLinearRegression(string name, int period) : this(name, period, timeSpan => (decimal) timeSpan.TotalMinutes) { } public TheilSenLinearRegression(string name, int period, Func<TimeSpan, decimal> timeSpanUnits) : base(name, period) { _timeSpanUnits = timeSpanUnits; Slope = new FunctionalIndicator<IndicatorDataPoint>(name + "_Slope", input => input, ind => this.IsReady ); } protected override decimal ComputeNextValue(IReadOnlyWindow<IndicatorDataPoint> window, IndicatorDataPoint input) { if (window.Count == 1) { _start = input.Time; Slope.Update(input.Time, 0m); return input.Value; } // this is an O(n²) operation, so keep the period relatively small var data = (from a in window from b in window where a != b where a.Time != b.Time select new { value = (a + b) / 2, slope = (b.Value - a.Value) / _timeSpanUnits(b.Time - a.Time), time = (a.Time.Ticks + b.Time.Ticks) / 2 }).ToList(); // get the median slope Slope.Update(input.Time, data.Median(x => x.slope)); // y = mx + b, where b= median(yi-m*xi) var intercept = window.Median(x => (x.Value - Slope * _timeSpanUnits(x.Time - _start))); return Slope * _timeSpanUnits(input.Time - _start) + intercept; } } }