Overall Statistics |
Total Trades 1188 Average Win 2.31% Average Loss -1.15% Compounding Annual Return 58.155% Drawdown 15.400% Expectancy 0.463 Net Profit 1839.475% Sharpe Ratio 2.294 Loss Rate 52% Win Rate 48% Profit-Loss Ratio 2.02 Alpha 0.485 Beta -0.022 Annual Standard Deviation 0.209 Annual Variance 0.044 Information Ratio 1.022 Tracking Error 0.271 Treynor Ratio -21.908 Total Fees $878399.95 |
using System; using System.Collections.Generic; using System.Linq; namespace QuantConnect.Algorithm.Examples { public class TrailingStop { public decimal TrailingStopValue {get;set;} decimal TrailingStopPercent{get;set;} bool IsLong {get;set;} public TrailingStop ( decimal stopValue, decimal stopPercent, bool isLongEntry ) { TrailingStopValue = stopValue; TrailingStopPercent = stopPercent; IsLong = isLongEntry; } public bool IsTrailingExit( TradeBar b, out decimal exitPrice) { bool rtn = false; exitPrice = 0; if ( IsLong == true) { if ( b.Close / TrailingStopValue < 1-TrailingStopPercent/100) { exitPrice = b.Close; rtn = true; } } else { // short if ( b.Close / TrailingStopValue > 1+TrailingStopPercent/100 ) { exitPrice = b.Close; rtn = true; } } // update Trailing stop if needed if ( rtn != true) { if ( IsLong == true && b.Close > TrailingStopValue) TrailingStopValue = b.Close; if ( IsLong == false && b.Close < TrailingStopValue) TrailingStopValue = b.Close; } return rtn; } // IsTrailingExit } // TrailingStop }
/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace QuantConnect.Algorithm.Examples { /// <summary> /// Basic template algorithm simply initializes the date range and cash /// </summary> public class VIXIntraDay : QCAlgorithm { string Symbol = null; int RollingSize = 2; RollingWindow<TradeBar> history = null; DateTime lastTrade = new DateTime(); TradeBar entryBar = null; decimal spyma=0; TradeBar firstBar = null; TrailingStop trlStop = null; bool enableEntry = true; /// <summary> /// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized. /// </summary> public override void Initialize() { SetStartDate(2009, 3, 1); //Set Start Date SetEndDate(2015, 10, 13); SetCash(1000000); //Set Strategy Cash history = new RollingWindow<TradeBar>(RollingSize); Symbol = "VXX"; // Find more symbols here: http://quantconnect.com/data AddSecurity(SecurityType.Equity, Symbol, Resolution.Minute); } /// <summary> /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. /// </summary> /// <param name="data">TradeBars IDictionary object with your stock data</param> public void OnData(TradeBars data) { try { bool IsLong = true; TradeBar b = null; data.TryGetValue(Symbol, out b); //Debug(">> " + b.Time.ToString() ); decimal price = 0; if (b!=null && history.IsReady ) { if ( IsFirstTradingMin(b) == true ) { firstBar = b; // enable entry on the first bar if not invested yet if ( Portfolio.Invested == false ) enableEntry = true; } if ( IsExit(b, out price) == true) { Liquidate(); entryBar = null; Log(">>Close>> " + b.Time.ToString() + " " + Symbol + " @" + price); } else { if ( IsEntry(b, out price, out IsLong ) == true) { entryBar = b; int qnt = (int) (Portfolio.Cash / price); if ( IsLong == false) { // shorts qnt = -qnt; SetHoldings(Symbol, -1.0); } else { // longs SetHoldings(Symbol, 1.0); } trlStop = new TrailingStop(price, 2, IsLong ); enableEntry = false; //SetHoldings(Symbol, 1.0); Log(">>BUY/sell>> " + b.Time.ToString() + " " + qnt + " " + Symbol + " @" + price); } // if } } // if if ( b!=null && IsLastTradingMin(b) == true) { history.Add(b); //lastClose = data[Symbol]; //Debug("Add a bar " + b.Time.ToString() +" " + (history.Count >= RollingSize) ); } } catch (Exception ex) { Error("OnData: " + ex.Message + "\r\n\r\n" + ex.StackTrace); } } // OnData bool IsLastTradingMin(TradeBar b) { if ( b.Time.Hour==15 && b.Time.Minute == 59) return true; else return false; } // IsLastTradingMin bool IsFirstTradingMin(TradeBar b) { if ( b.Time.Hour==9 && b.Time.Minute == 31) return true; else return false; } // IsFirstTradingMin /// <summary> /// checks if this bar is good for entry /// </summary> /// <param name="b"></param> /// <returns></returns> bool IsEntry( TradeBar b, out decimal entryPrice, out bool IsLong) { entryPrice = 0; IsLong = true; bool rtn = false; // check for Long entry VXX if ( Portfolio.Invested == false //&& false && ( b.Time.Date.DayOfWeek == DayOfWeek.Monday // || b.Time.Date.DayOfWeek == DayOfWeek.Tuesday || b.Time.Date.DayOfWeek == DayOfWeek.Wednesday || b.Time.Date.DayOfWeek == DayOfWeek.Thursday || b.Time.Date.DayOfWeek == DayOfWeek.Friday ) && enableEntry == true && (b.Time.Hour == 9 ) && history[0].Close > history[1].Close // vxx && b.Close < history[0].Close // vxx open below the Close ) { // enter //Debug("good day " + b.Time.ToString() +" " + history[0].Close + " " + history[1].Close ); entryPrice = b.Close; IsLong = true; rtn = true; } // if // check for Sort entry VXX if ( Portfolio.Invested == false && enableEntry == true && history[0].Close < history[1].Close && firstBar.Close < history[0].Close *0.99m ) { // enter //Debug("good day " + b.Time.ToString() +" " + history[0].Close + " " + history[1].Close ); entryPrice = b.Close; IsLong = false; rtn = true; } // if return rtn; } // IsEntry bool IsExit( TradeBar b, out decimal exitPrice ) { exitPrice = 0; bool rtn = false; if ( Portfolio.Invested == true && Portfolio[Symbol] != null ) { if ( // for Long exit Portfolio[Symbol].IsLong==true && b.Time.Hour==10 && b.Time.Minute==45 || // for short exit Portfolio[Symbol].IsShort==true && ( //b.Time.Hour==15 && b.Time.Minute==59 // converts to MarketOnOpen for next day trlStop.IsTrailingExit(b,out exitPrice) ) // && trlStop.IsTrailingExit(b,out exitPrice) ) { rtn = true; exitPrice = b.Close; } } return rtn; } // IsExit decimal GettPercentGain( TradeBar b, string ticker) { decimal rtn = 0; if ( Portfolio[ticker] != null ) { rtn = (Portfolio[ticker].Price - Portfolio[ticker].AveragePrice) / Portfolio[ticker].AveragePrice*100; if (Portfolio[ticker].IsShort==true) rtn = -rtn; } return rtn; } // GettPercentGain } }
namespace QuantConnect.Algorithm.Examples { // // 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 //} public class RollingWin<T> : IReadOnlyWindow<T> { // the backing list object used to hold the data public List<T> _list; // read-write lock used for controlling access to the underlying list data structure //private readonly ReaderWriterLockSlim _listLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); // the most recently removed item from the window (fell off the back) private T _mostRecentlyRemoved; // the total number of samples taken by this indicator private decimal _samples; // used to locate the last item in the window as an indexer into the _list private int _tail; /// <summary> /// Initializes a new instance of the RollwingWindow class with the specified window size. /// </summary> /// <param name="size">The number of items to hold in the window</param> public RollingWin(int size) { if (size < 1) { throw new ArgumentException("RollingWindow must have size of at least 1.", "size"); } _list = new List<T>(size); } /// <summary> /// Gets the size of this window /// </summary> public int Size { get { return _list.Capacity; } } /// <summary> /// Gets the current number of elements in this window /// </summary> public int Count { get { return _list.Count; } } /// <summary> /// Gets the number of samples that have been added to this window over its lifetime /// </summary> public decimal Samples { get { return _samples; } } /// <summary> /// Gets the most recently removed item from the window. This is the /// piece of data that just 'fell off' as a result of the most recent /// add. If no items have been removed, this will throw an exception. /// </summary> public T MostRecentlyRemoved { get { if (!IsReady) { throw new InvalidOperationException("No items have been removed yet!"); } return _mostRecentlyRemoved; } } /// <summary> /// Indexes into this window, where index 0 is the most recently /// entered value /// </summary> /// <param name="i">the index, i</param> /// <returns>the ith most recent entry</returns> public T this [int i] { get { //_listLock.EnterReadLock(); if (i >= Count) { throw new ArgumentOutOfRangeException("i", i, string.Format("Must be between 0 and Count {0}", Count)); } return _list[(Count + _tail - i - 1) % Count]; } set { if (i >= Count) { throw new ArgumentOutOfRangeException("i", i, string.Format("Must be between 0 and Count {0}", Count)); } _list[(Count + _tail - i - 1) % Count] = value; } } /// <summary> /// Gets a value indicating whether or not this window is ready, i.e, /// it has been filled to its capacity and one has fallen off the back /// </summary> public bool IsReady { get { return Samples > Size; } } /// <summary> /// Returns an enumerator that iterates through the collection. /// </summary> /// <returns> /// A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection. /// </returns> /// <filterpriority>1</filterpriority> public IEnumerator<T> GetEnumerator() { // we make a copy on purpose so the enumerator isn't tied // to a mutable object, well it is still mutable but out of scope var temp = new List<T>(Count); for (int i = 0; i < Count; i++) { temp.Add(this[i]); } return temp.GetEnumerator(); } /// <summary> /// Returns an enumerator that iterates through a collection. /// </summary> /// <returns> /// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection. /// </returns> /// <filterpriority>2</filterpriority> IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// <summary> /// Adds an item to this window and shifts all other elements /// </summary> /// <param name="item">The item to be added</param> public void Add(T item) { _samples++; if (Size == Count) { // keep track of what's the last element // so we can reindex on this[ int ] _mostRecentlyRemoved = _list[_tail]; _list[_tail] = item; _tail = (_tail + 1) % Size; } else { _list.Add(item); } } /// <summary> /// Clears this window of all data /// </summary> public void Reset() { _samples = 0; _list.Clear(); } } }