Overall Statistics |
Total Trades 668 Average Win 0.09% Average Loss -0.07% Compounding Annual Return 1.713% Drawdown 1.500% Expectancy 0.033 Net Profit 0.710% Sharpe Ratio 0.543 Loss Rate 54% Win Rate 46% Profit-Loss Ratio 1.24 Alpha 0.011 Beta 0.019 Annual Standard Deviation 0.022 Annual Variance 0 Information Ratio -0.345 Tracking Error 0.129 Treynor Ratio 0.645 Total Fees $1492.24 |
namespace QuantConnect { // // Make sure to change "BasicTemplateAlgorithm" to your algorithm class name, and that all // files use "public partial class" if you want to split up your algorithm namespace into multiple files. // //public partial class BasicTemplateAlgorithm : QCAlgorithm, IAlgorithm //{ // Extension functions can go here...(ones that need access to QCAlgorithm functions e.g. Debug, Log etc.) //} //public class Indicator //{ // ...or you can define whole new classes independent of the QuantConnect Context //} class Utility{ /// <summary> /// Returns the business date (EventDate + post days) after accouning for weekends; will not take into other exchange holidays /// </summary> /// <param name="EventDate"></param> /// <param name="postDays"></param> /// <returns></returns> public static DateTime getPostBusinessDate(DateTime EventDate, int postDays) { DateTime applicableDate = EventDate; //Checking if the event itself occurs on a weekend if (postDays == 0) while (applicableDate.DayOfWeek == DayOfWeek.Saturday || applicableDate.DayOfWeek == DayOfWeek.Sunday) applicableDate = applicableDate.AddDays(1); for (int tempCount = 0; tempCount < Math.Abs(postDays); tempCount++) { applicableDate = applicableDate.AddDays(Math.Sign(postDays)); while (applicableDate.DayOfWeek == DayOfWeek.Saturday || applicableDate.DayOfWeek == DayOfWeek.Sunday) applicableDate = applicableDate.AddDays(Math.Sign(postDays)); } return applicableDate; } public static List<DateTime> getDaysAroundEvent(List<DateTime> eventDates, int NbPreDays, int NbPostDays) { List<DateTime> _finalDates = new List<DateTime>(); foreach(DateTime eventDate in eventDates) { int count = -NbPreDays; while(count<=NbPostDays) { _finalDates.Add(getPostBusinessDate(eventDate,count)); count++; } } return _finalDates; } } }
using System; using System.Collections; using System.Collections.Generic; using MathNet.Numerics.Statistics; using MathNet.Numerics; using System.Linq; namespace QuantConnect { //Returns the channel end values based on previous Trade bar public class PolynomialRegression { private int _period; public int period {get{return _period;}} private double _deviation; private int _power; private int _samples; private decimal _oneStdDev; public decimal oneStdDev {get{return _oneStdDev;}} private decimal _lastPredictedValue; public decimal lastPredictedValue {get{return _lastPredictedValue;}} private decimal _slope; public decimal slope {get{return _slope;}} private double[] _slopeCoefficients; public double[] slopeCoefficients {get{return _slopeCoefficients;}} private decimal _upBand; public decimal upBand {get{return _upBand;}} private decimal _lowBand; public decimal lowBand {get{return _lowBand;}} //Will check if the value from the indicator should be used or not private bool _isReady; public bool isReady {get{return _isReady;}} private List<double> _yBuffer; public List<double> yBuffer {get{return _yBuffer;}} private List<double> _xBuffer; public List<double> xBuffer {get{return _xBuffer;}} public PolynomialRegression (int period, double deviation, int power) { this._period = period; this._deviation = deviation; this._power = power; this._samples = 0; this._yBuffer = new List<double>(); this._xBuffer = new List<double>(); //_xBuffer.Add(1); } public void AddSample(decimal price) { if (_samples<_period) { _slope = 1m; _upBand = price; _lowBand =price; _isReady = false; _samples++; _yBuffer.Add((double)price); _xBuffer.Add(_samples); return; } else { _slopeCoefficients = Fit.Polynomial(_xBuffer.ToArray(), _yBuffer.ToArray(), _power); _isReady = true; double[] _errors = new double[_xBuffer.Count()]; double[] _modelledValues = new double[_yBuffer.Count()]; for (int _curCount = 0;_curCount<_xBuffer.Count();_curCount++) { //_modelledValues[_curCount] = Evaluate.Polynomial(_xBuffer[_curCount], _slopeCoefficients); _modelledValues [_curCount] = _slopeCoefficients[0] + _slopeCoefficients[1]*_xBuffer[_curCount]; _errors[_curCount] = _modelledValues[_curCount] - _yBuffer[_curCount]; } _oneStdDev = (decimal)ArrayStatistics.PopulationStandardDeviation(_errors); //Standard Devation of errors - Population uses N _lastPredictedValue = (decimal)(_slopeCoefficients[0] + _slopeCoefficients[1]*_xBuffer.Last()); //Getting the last calculated value _slope = (decimal)_slopeCoefficients[1]; _upBand = _lastPredictedValue + _oneStdDev*(decimal)_deviation; _lowBand = _lastPredictedValue - _oneStdDev*(decimal)_deviation; _yBuffer.Add((double)price); //Preparing for next band value _yBuffer.RemoveAt(0); } } } //public class Indicator //{ // ...or you can define whole new classes independent of the QuantConnect Context //} }
using System; namespace QuantConnect { // Create 2 channels, operate only during Europe time, Mean Reversion only public partial class PolynomialRegressionDemo : QCAlgorithm { //string symbol = "EURUSD"; // string symbol = "USDJPY"; // string symbol = "AUDUSD"; // string symbol = "USDCAD"; string symbol = "EURCHF"; // string symbol = "EURSEK"; //int europeStartHours = 3; //NY Time //int usStartHours = 6; //int usEndHours = 15; bool isTradeTime; DateTime[] ECBDays = new DateTime[] { new DateTime(2015,1,22),new DateTime(2015,3,5),new DateTime(2015,4,15),new DateTime(2015,6,3),new DateTime(2015,7,16),new DateTime(2015,9,3),new DateTime(2015,10,22),new DateTime(2015,12,3),new DateTime(2016,1,21),new DateTime(2016,3,10),new DateTime(2016,4,21)}; DateTime[] FedDays = new DateTime[]{ new DateTime(2015,1,28),new DateTime(2015,3,18),new DateTime(2015,4,29),new DateTime(2015,6,17),new DateTime(2015,7,29),new DateTime(2015,9,17),new DateTime(2015,10,28),new DateTime(2015,12,16),new DateTime(2016,1,27),new DateTime(2016,3,16),new DateTime(2016,4,27)}; DateTime[] NFPDays = new DateTime[]{ new DateTime(2015,1,9),new DateTime(2015,2,6),new DateTime(2015,3,6),new DateTime(2015,4,3),new DateTime(2015,5,8),new DateTime(2015,6,5),new DateTime(2015,7,2),new DateTime(2015,8,7),new DateTime(2015,9,4),new DateTime(2015,10,2),new DateTime(2015,11,6),new DateTime(2015,12,4),new DateTime(2016,1,8),new DateTime(2016,2,5),new DateTime(2016,3,4),new DateTime(2016,4,1),new DateTime(2016,5,6),new DateTime(2016,6,3)}; bool _excludeNFP = true; int _NbNFPPreDays = 4; int _NbNFPPostDays = 1; bool _excludeECB = true; int _NbECBPreDays =2; int _NbECBPostDays =1; bool _excludeFed = true; int _NbFEDPreDays = 0; int _NbFEDPostDays = 1; bool isTradDate; List <DateTime> _excludeDates; DateTime _latestEventDate; int _fastPeriod = 300; //Period in minutes int _slowPeriod = 1200; //Period in minutes double _fastNbDevBands = 2.0; //Number of deviations (bands) double _slowNbDevBands = 2; //Number of deviations (band int _notional = 100000; double _leverage = 1; private OrderTicket _orderCurrentOrder; private OrderTicket _orderStopLoss; private OrderTicket _orderProfitTarget; decimal _fastHiBandPrev1, _fastLowBandPrev1; decimal _prevClose, _entryPrice, _exitPrice; decimal _stopPrice,_tpPrice; decimal _NAV; DateTime _entryTime, _exitTime; //Assumes only 1 trade at a time char _buyorsell; //int NbData; //int _NbOpenOrders = 0; PolynomialRegression prSlow; PolynomialRegression prFast; //Initialize the data and resolution you require for your strategy: public override void Initialize() { SetTimeZone("America/New_York"); SetStartDate(2016,1, 1); SetEndDate(2016,5, 31); _excludeDates = new List<DateTime>(); if(_excludeFed==true) _excludeDates.AddRange(Utility.getDaysAroundEvent(FedDays.ToList(),_NbFEDPreDays, _NbFEDPostDays)); if(_excludeNFP==true) _excludeDates.AddRange(Utility.getDaysAroundEvent(NFPDays.ToList(),_NbNFPPreDays, _NbNFPPostDays)); if(_excludeECB==true) _excludeDates.AddRange(Utility.getDaysAroundEvent(ECBDays.ToList(),_NbECBPreDays, _NbECBPostDays)); if(_excludeDates.Count()==0) _excludeDates.Add(DateTime.Now.AddDays(1)); _excludeDates = _excludeDates.Distinct().ToList(); _excludeDates.Sort(); //Contains list of all sorted events which are to be avoided _latestEventDate = _excludeDates.ElementAt(0); AddSecurity(SecurityType.Forex,symbol, Resolution.Minute); //prUpper time should be greater than prFast by at least 1 period prSlow = new PolynomialRegression(_slowPeriod,_slowNbDevBands,1); prFast = new PolynomialRegression(_fastPeriod,_fastNbDevBands,1); //previous value of Fast channel _fastHiBandPrev1=0; _fastLowBandPrev1=0; _prevClose=0; //Cash allocation SetCash(_notional/_leverage); //_leverage = 1 =>No Leverage; //NbData=0; var history = History(symbol, _slowPeriod + 10); //Buffer of 10 for the slow channel foreach (var tradeBar in history) { prFast.AddSample( tradeBar.Close); prSlow.AddSample(tradeBar.Close); } } //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) { decimal price = data[symbol].Close; var holdings = Portfolio[symbol].Quantity; if(prSlow.isReady==false ) //Wait for upper channel to be ready { prFast.AddSample(price); prSlow.AddSample(price); return; } //if (!Portfolio.HoldStock) //Time Filters /*if(Time.Hour>=europeStartHours && Time.Hour<usStartHours) isTradeTime = true; else isTradeTime = false;*/ isTradeTime = true; if(Time.Date> _latestEventDate && _latestEventDate == _excludeDates.Last()) isTradDate=true; else { if(Time.Date> _latestEventDate) { _latestEventDate = _excludeDates.ElementAt(_excludeDates.IndexOf(_latestEventDate)+1); if(Time.Date == _latestEventDate) //event dates move in days while data comes in minutes isTradDate = false; else isTradDate= true; } else if(Time.Date == _latestEventDate) isTradDate = false; else if(Time.Date < _latestEventDate) isTradDate = true; } if(Time.DayOfWeek == DayOfWeek.Sunday) isTradDate = false; if(isTradDate&& isTradeTime) isTradeTime = true; else isTradeTime = false; if(holdings==0) //No position { // if(price<prFast.lowBand & _prevClose>_fastLowBandPrev1 & prFast.slope>0 & prSlow.slope>0 & isTradeTime==true) //Fast channel line of Fast band is greater than price - buy if(price<prFast.lowBand & _prevClose>_fastLowBandPrev1 & prFast.slope>0 & isTradeTime==true) { _stopPrice = price - prFast.oneStdDev * 2.0m; _tpPrice = price + prFast.oneStdDev *3.0m; _buyorsell = 'B'; _entryTime = Time;_entryPrice = price; //Recording Trade data // Debug("Placing Buy Mkt Order now.."); _orderCurrentOrder = Order(symbol, _notional); //Debug("Purchased " + symbol + " on " + Time.ToString() + " at Price: " + price.ToString("0.0000") + " SL: " + _stopPrice.ToString("0.0000") + " TP: " + _tpPrice.ToString("0.0000") ); _orderStopLoss = StopMarketOrder(symbol, -_notional, _stopPrice); _orderProfitTarget = LimitOrder(symbol,-_notional, _tpPrice); } // else if(price>prFast.upBand & _prevClose<_fastHiBandPrev1 & prFast.slope<0 & prSlow.slope<0 & isTradeTime==true) //higher channel of Fast band is less than price - sell else if(price>prFast.upBand & _prevClose<_fastHiBandPrev1 & prFast.slope<0 & isTradeTime==true) //higher channel of Fast band is less than price - sell { _stopPrice = price + prFast.oneStdDev*2.0m; _tpPrice = price - prFast.oneStdDev*3.0m; _buyorsell = 'S'; _entryTime = Time; _entryPrice = price; //Recording Trade data // Debug("Placing Sell Mkt Order now.."); _orderCurrentOrder = Order(symbol, -_notional); //Debug("Sold " + symbol + " on " + Time.ToString() + " at Price: " + price.ToString("0.0000") + " SL: " + _stopPrice.ToString("0.0000") + " TP: " + _tpPrice.ToString("0.0000")); _orderStopLoss = StopMarketOrder(symbol, +_notional, _stopPrice); _orderProfitTarget = LimitOrder(symbol,+_notional, _tpPrice); } } _fastLowBandPrev1 = prFast.lowBand; _fastHiBandPrev1 = prFast.upBand; _prevClose = price; prFast.AddSample(price); prSlow.AddSample(price); // Debug(i.ToString() + " Time " + Time.ToString() + "Price = " + price + " loBand = " + prFast.lowBand + " upBand = " + prFast.upBand); // Debug ("Last =" + PolynomialRegression._yBuffer.Last().ToString()); //Debug("Time = " + Time.ToString() + "Price = " + price.ToString("0.0000")); /* Plot("Custom","prUpper_upBand", prSlow.upBand); Plot("Custom","prFast_upBand", prFast.upBand); Plot("Custom","prFast_lowBand", prFast.lowBand); Plot("Custom","prUpper_lowBand", prSlow.lowBand); Plot("Custom",symbol, data[symbol].Close); */ } // If the StopLoss or ProfitTarget is filled, cancel the other // If you don't do this, then the ProfitTarget or StopLoss order will remain outstanding // indefinitely, which will cause very bad behaviors in your algorithm public override void OnOrderEvent(OrderEvent orderEvent) { // Ignore OrderEvents that are not closed if (!orderEvent.Status.IsClosed()) { return; } // Defensive check if (_orderProfitTarget == null || _orderStopLoss == null) { return;} //This is getting called recursively if an order is canceled if(orderEvent.Status == OrderStatus.Canceled ) { // Debug("Canceled outstanding order"); return; } var filledOrderId = orderEvent.OrderId; // Debug("current order ID " +_orderCurrentOrder.OrderId + "Filled Order ID = " + filledOrderId ); if(_orderCurrentOrder.OrderId +3 == filledOrderId) { //Debug("Market Order checked"); return; } // If the ProfitTarget order was filled, close the StopLoss order if (_orderProfitTarget.OrderId == filledOrderId) { // Debug("TP Order hit"); if(_orderStopLoss.Status != OrderStatus.Filled) _orderStopLoss.Cancel(); else Liquidate(); } // If the StopLoss order was filled, close the ProfitTarget if (_orderStopLoss.OrderId == filledOrderId) { // Debug("SL Order hit"); if(_orderProfitTarget.Status != OrderStatus.Filled) _orderProfitTarget.Cancel(); else Liquidate(); } _exitPrice = orderEvent.FillPrice; _exitTime = Time; _NAV = Portfolio.TotalPortfolioValue; double _thisTradePnL = (double)(_exitPrice-_entryPrice)*_notional; if(char.ToUpper(_buyorsell).CompareTo('S')==0 ) _thisTradePnL*= -1; Debug( ",Entry Time," + _entryTime + "," + _entryTime.DayOfWeek + ","+ _entryPrice.ToString("0.0000") + "," + _buyorsell + "," + _exitPrice.ToString("0.0000") + "," + _exitTime + "," + _thisTradePnL.ToString("0") + "," + _NAV.ToString("0") ); } } }