Overall Statistics |
Total Trades 1898 Average Win 0.63% Average Loss -0.38% Compounding Annual Return 18.064% Drawdown 8.900% Expectancy 0.246 Net Profit 134.423% Sharpe Ratio 1.752 Loss Rate 53% Win Rate 47% Profit-Loss Ratio 1.66 Alpha 0.169 Beta 0.086 Annual Standard Deviation 0.098 Annual Variance 0.01 Information Ratio 1.547 Tracking Error 0.098 Treynor Ratio 1.985 Total Fees $124215.06 |
using System; using QuantConnect.Algorithm; using QuantConnect.Data; using QuantConnect.Data.Market; using QuantConnect.Indicators; 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 { /** * The script appears to be using the current price, but the RSI value from the last bar. Add consolidators for all of the Index tickers. Add a set to keep track of which tickers have been updated by the consolidator and don't do any calculations until all the tickers have been updated. */ private SimpleMovingAverage uvxyAverage; private SimpleMovingAverage uvxyLongAverage; private bool positionOpen = false; private SpreadSlippageModel slippageModel = new SpreadSlippageModel(); //Index tickers private String[] indexTickers = {"SPY", "DIA", "IWM", "QQQ"}; private Dictionary<string,RelativeStrengthIndex> trendMap = new Dictionary<string,RelativeStrengthIndex>(); private String volIndex = "UVXY"; private String volTicker = "XIV"; private bool closeEOD = false; private String maTicker; private bool allUpdated = false; private HashSet<String> completedSet = new HashSet<String>(); //Initialize the data and resolution you require for your strategy: public override void Initialize() { maTicker = volIndex; //Start and End Date range for the backtest: SetStartDate(2013, 1, 1); SetEndDate(DateTime.Now.Date.AddDays(-1)); //Cash allocation SetCash(1000000); foreach( String indexTicker in indexTickers ) { AddSecurity(SecurityType.Equity, indexTicker, Resolution.Minute); Securities[indexTicker].SlippageModel = slippageModel; var consolidator = new TradeBarConsolidator(TimeSpan.FromMinutes(5)); consolidator.DataConsolidated += FiveMinuteHandler; RelativeStrengthIndex trend = new RelativeStrengthIndex(3, MovingAverageType.Simple); RegisterIndicator(indexTicker, trend, consolidator); var history = History(indexTicker, TimeSpan.FromDays(5), Resolution.Minute); foreach (var tradeBar in history) { trend.Update(tradeBar.EndTime, tradeBar.Close); } trendMap[indexTicker] = trend; } AddSecurity(SecurityType.Equity, volIndex, Resolution.Minute); AddSecurity(SecurityType.Equity, volTicker, Resolution.Minute); var fiveMinuteConsolidator2 = new TradeBarConsolidator(TimeSpan.FromMinutes(5)); fiveMinuteConsolidator2.DataConsolidated += FiveMinuteHandler; SetBrokerageModel(new InteractiveBrokersBrokerageModel()); uvxyAverage = new SimpleMovingAverage(20); uvxyLongAverage = new SimpleMovingAverage(50); var tradeBarHistory = History(maTicker, TimeSpan.FromDays(5), Resolution.Minute); foreach (var tradeBar in tradeBarHistory) { uvxyAverage.Update(tradeBar.EndTime, tradeBar.Close); uvxyLongAverage.Update(tradeBar.EndTime, tradeBar.Close); } RegisterIndicator(maTicker, uvxyAverage, fiveMinuteConsolidator2); RegisterIndicator(maTicker, uvxyLongAverage, fiveMinuteConsolidator2); } private void FiveMinuteHandler(object sender, TradeBar consolidatedBar) { DateTime time = consolidatedBar.Time; Log( "UVXY Ready: " + uvxyAverage.IsReady + " uvxyLongAverageReady: " + uvxyLongAverage.IsReady); if( uvxyAverage.IsReady && uvxyLongAverage.IsReady) { Log("Short Avg: " + uvxyAverage + " Long Avg: " + uvxyLongAverage ); foreach(KeyValuePair<string, RelativeStrengthIndex> entry in trendMap) {decimal prc = Securities[entry.Key].Price; if(entry.Value > 0 ) { decimal amt = (prc-entry.Value)/ entry.Value; Log("RSI for: " + entry.Key + " is: " + entry.Value + " last: " + prc + " propValue: " + amt); } else { Log("RSI value is zero for: " + entry.Key + " last: " + prc); } } if( uvxyAverage < uvxyLongAverage && ! positionOpen) { if( time.Hour < 15 || (time.Hour == 15 && time.Minute <= 60) ) { decimal lowest = 100000; decimal highest= 0; String lowestTicker = ""; String highestTicker = ""; foreach(KeyValuePair<string, RelativeStrengthIndex> entry in trendMap) { if(entry.Value > 0 ) { decimal price = Securities[entry.Key].Price; decimal amount = (price-entry.Value)/ entry.Value; //decimal amount = entry.Value; if(amount < lowest) { lowest = amount; lowestTicker = entry.Key; } if( amount > highest ) { highest = amount; highestTicker = entry.Key; } } } Log("Trade triggered, selecting: " + lowestTicker); positionOpen = true; decimal size = 1.0m; SetHoldings(lowestTicker, size); } } else { if( uvxyAverage > uvxyLongAverage && positionOpen ) { if( time.Hour < 15 || (time.Hour == 15 && time.Minute <= 60) ) { positionOpen =false; Liquidate(); } } } if( consolidatedBar.Time.Hour == 15 && consolidatedBar.Time.Minute >= 55 ) { if( closeEOD ) { positionOpen = false; Liquidate(); } } } else { Console.WriteLine("Warming up"); } } //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(data.ContainsKey(volIndex) ) { Plot(volIndex, "Price", data[volIndex].Price); Plot(volIndex, uvxyAverage, uvxyLongAverage); } if (!Portfolio.HoldStock) { } } } }
namespace QuantConnect { public class SpreadSlippageModel : ISlippageModel { private readonly decimal _slippagePercent; /// <summary> /// Initializes a new instance of the <see cref="ConstantSlippageModel"/> class /// </summary> /// <param name="slippagePercent">The slippage percent for each order. Percent is ranged 0 to 1.</param> public SpreadSlippageModel() { } /// <summary> /// Slippage Model. Return a decimal cash slippage approximation on the order. /// </summary> public decimal GetSlippageApproximation(Security asset, Order order) { return 0.01m; } } }