| Overall Statistics |
|
Total Trades 1086 Average Win 2.07% Average Loss -1.25% Compounding Annual Return 31.856% Drawdown 21.300% Expectancy 0.264 Net Profit 425.403% Sharpe Ratio 1.448 Loss Rate 52% Win Rate 48% Profit-Loss Ratio 1.65 Alpha 0.104 Beta 9.653 Annual Standard Deviation 0.204 Annual Variance 0.042 Information Ratio 1.351 Tracking Error 0.204 Treynor Ratio 0.031 Total Fees $11781.69 |
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(2012, 01, 01); //Set Start Date
SetEndDate(2018, 01, 01);
SetCash(100000); //Set Strategy Cash
history = new RollingWindow<TradeBar>(RollingSize);
Symbol = "VXX";
// Find more symbols here: http://quantconnect.com/data
AddSecurity(SecurityType.Equity, Symbol, Resolution.Minute, true, 1m, false);
}
/// <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();
}
}
}