| Overall Statistics |
|
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio NaN Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio NaN Tracking Error NaN Treynor Ratio NaN |
namespace QuantConnect.Indicators
{
public class RelativeStrengthIndex : IndicatorBase
{
public readonly ExponentialMovingAverage UpDays;
public readonly ExponentialMovingAverage DownDays;
private DataPoint<decimal> previousInput;
public RelativeStrengthIndex(string name, int period)
: base(name)
{
UpDays = new ExponentialMovingAverage(string.Format("[{0}]" + "_UP_EMA{1}", name, period), period);
DownDays = new ExponentialMovingAverage(string.Format("[{0}]" + "_DOWN_EMA{1}", name, period), period);
}
public override bool IsReady
{
get { return UpDays.IsReady && DownDays.IsReady; }
}
protected override decimal ComputeNextValue(DataPoint<decimal> previousValue, DataPoint<decimal> input)
{
if (input.Data > previousInput.Data)
{
UpDays.Update(input.WithNewData(input.Data - previousInput.Data));
}
else if (input.Data < previousInput.Data)
{
DownDays.Update(input.WithNewData(previousInput.Data - input.Data));
}
previousInput = input;
if (DownDays.Samples < 5)
{
return 50;
}
var rs = UpDays.Value.Data/DownDays.Value.Data;
return 100m - (100m/(1 + rs));
}
}
}using System;
using System.Collections.Generic;
using QuantConnect.Models;
namespace QuantConnect.Indicators
{
/// <summary>
/// Shows how we can compose indicators by wrapping them around other indicators
/// </summary>
public class IndicatorAlgorithmDemo : QCAlgorithm
{
private IIndicator smaHigh;
private IIndicator emaLow;
private IIndicator rsiClose;
private WrappedIndicator macdSimpleOpen;
private WrappedIndicator macdExponentialClose;
private WrappedIndicator rsiOfMacdSimpleOpen;
private const string SPY = "SPY";
public override void Initialize()
{
SetCash(25000);
SetStartDate(2007, 01, 01);
SetEndDate(2011, 01, 01);
AddSecurity(SecurityType.Equity, SPY);
// easily define common indicators
smaHigh = SMA(25);
emaLow = EMA(35);
var sma9 = SMA(9);
var macds = MACD(14, 26, "sMACD(14,26)");
// easily compose multiple indicators, here we define an sma signal line for
// our sma macd
macdSimpleOpen = sma9.Of(macds);
var ema9 = EMA(9, "eMACD-EMA9");
var macde = MACD(14, 26, "eMACD(14,26)", MovingAverageType.Exponential);
// here we define an ema signal line for our ema macd
macdExponentialClose = ema9.Of(macde);
var rsi = RSI(14);
rsiOfMacdSimpleOpen = rsi.Of(macdSimpleOpen, "RSI of MACD");
rsiClose = RSI(14);
}
private DateTime previous;
public override void OnTradeBar(Dictionary<string, TradeBar> data)
{
// when pumping data throw an indictor 'machine' we only need to pump from
// the outter most parts, so in this case, sma, ema, macdSimple, and macdExponential
// the 'interior' indicators in the macds (sma9, ema9, macd in Initialize()) are handled by the instance
// we'll only get updates once per day
TradeBar bar;
if (data.TryGetValue(SPY, out bar) && bar.Time.Date != previous.Date)
{
previous = bar.Time;
// we can decide what data to send to each indicator
try
{
var dataPoint = CreateDataPoint(bar.Time, bar.High);
smaHigh.Update(dataPoint);
dataPoint = CreateDataPoint(bar.Time, bar.Low);
emaLow.Update(dataPoint);
// calling update on this one will 'turn the crank' for the
// interior indicators as well (macdSimpleOpen and its interior indicators)
dataPoint = CreateDataPoint(bar.Time, bar.Open);
rsiOfMacdSimpleOpen.Update(dataPoint);
dataPoint = CreateDataPoint(bar.Time, bar.Close);
macdExponentialClose.Update(dataPoint);
rsiClose.Update(dataPoint);
Plot("Price", "Close", bar.Close);
Plot("Price", "SMA14 High", smaHigh.Value.Data);
Plot("Price", "EMA14 Low", emaLow.Value.Data);
// here we use the Root property on the WrappedIndicator to get access
// to the underlying MACD data, and then the Wrapped (or just Value) is the signal line
Plot("sMACD", "MACD", macdSimpleOpen.Root.Value.Data);
Plot("sMACD", "Signal", macdSimpleOpen.Value.Data);
Plot("eMACD", "MACD", macdExponentialClose.Root.Value.Data);
Plot("eMACD", "Signal", macdExponentialClose.Value.Data);
Plot("RSI of MACD", "10*(5+MACD)", 10 * (5 + macdSimpleOpen.Value.Data));
Plot("RSI of MACD", "RSI of MACD", rsiOfMacdSimpleOpen.Value.Data);
Plot("RSI", "RSI", rsiClose.Value.Data);
Log("updated and plotted!");
}
catch (Exception ex)
{
Error(ex.Message + "\r\n\r\n" + ex.StackTrace);
}
}
}
public static IIndicator SMA(int period, string name = null)
{
return new SimpleMovingAverage(name ?? "SMA" + period, period);
}
public static IIndicator EMA(int period, string name = null)
{
return new ExponentialMovingAverage(name ?? "EMA" + period, period);
}
public static IIndicator MACD(int fast, int slow, string name = null, MovingAverageType type = MovingAverageType.Simple)
{
return new MovingAverageConverganceDivergance(name ?? string.Format("{0}MACD({1}, {2})", fast, slow, GetMACDPrefix(type)), fast, slow, type);
}
public static IIndicator RSI(int period, string name = null)
{
return new RelativeStrengthIndex(name ?? "RSI" + period, period);
}
private static string GetMACDPrefix(MovingAverageType type)
{
if (type == MovingAverageType.Simple) return "s";
if (type == MovingAverageType.Exponential) return "e";
throw new ArgumentOutOfRangeException("type", type, "Received unexpected value of type: " + type);
}
public static DataPoint<T> CreateDataPoint<T>(DateTime time, T data)
{
return new DataPoint<T>(time, data);
}
}
}namespace QuantConnect.Indicators
{
public class ExponentialMovingAverage : IndicatorBase
{
private readonly decimal _k;
private readonly int _period;
public ExponentialMovingAverage(string name, int period)
: base(name)
{
_period = period;
_k = 2 / ((decimal)period + 1);
}
public override bool IsReady
{
get { return Samples >= _period; }
}
protected override decimal ComputeNextValue(DataPoint<decimal> previousValue, DataPoint<decimal> input)
{
// our first data point just return identity
if (Samples == 1)
{
return input.Data;
}
return input.Data * _k + previousValue.Data * (1 - _k);
}
}
}namespace QuantConnect.Indicators
{
/// <summary>
/// Represents a forward-only in time time series filter
/// </summary>
public interface IIndicator
{
/// <summary>
/// Gets a name for this indicator
/// </summary>
string Name { get; }
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
bool IsReady { get; }
/// <summary>
/// Gets the current state of this indicator. If the state has not been updated
/// then the time on the value will equal DateTime.MinValue.
/// </summary>
DataPoint<decimal> Value { get; }
/// <summary>
/// Gets the number of samples processed by this indicator
/// </summary>
int Samples { get; }
/// <summary>
/// Updates the state of this indicator with the given value and returns true
/// if this indicator is ready, false otherwise
/// </summary>
/// <param name="input">The value to use to update this indicator</param>
/// <returns>True if this indicator is ready, false otherwise</returns>
bool Update(DataPoint<decimal> input);
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
void Reset();
}
}using System;
namespace QuantConnect.Indicators
{
/// <summary>
/// Represents the basic functionality of conforming to the IIndicator interface invariants
/// </summary>
public abstract class IndicatorBase : IIndicator
{
// the most recent time data was given to this indicator
private DateTime _previous;
protected IndicatorBase(string name)
{
Name = name;
}
/// <summary>
/// Gets a name for this indicator
/// </summary>
public string Name { get; private set; }
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public abstract bool IsReady { get; }
/// <summary>
/// Gets the current state of this indicator. If the state has not been updated
/// then the time on the value will equal DateTime.MinValue.
/// </summary>
public DataPoint<decimal> Value { get; private set; }
/// <summary>
/// Gets the number of samples processed by this indicator
/// </summary>
public int Samples { get; private set; }
/// <summary>
/// Updates the state of this indicator with the given value and returns true
/// if this indicator is ready, false otherwise
/// </summary>
/// <param name="input">The value to use to update this indicator</param>
/// <returns>True if this indicator is ready, false otherwise</returns>
public bool Update(DataPoint<decimal> input)
{
if (input.Time < _previous)
{
// if we receive a time in the past, throw
throw new ArgumentException("This is a forward only indicator.");
}
if (input.Time != _previous)
{
// if the time isn't the current time, then it must be future,
// compute a new value and update our previous time
Samples++;
_previous = input.Time;
decimal nextValue = ComputeNextValue(Value, input);
Value = input.WithNewData(nextValue);
}
// this is when _previous==time and we've already computed
// so do nothing and return IsReady
// else { }
return IsReady;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public virtual void Reset()
{
Value = new DataPoint<decimal>(DateTime.MinValue, default(decimal));
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="previousValue">The most recent value of this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected abstract decimal ComputeNextValue(DataPoint<decimal> previousValue, DataPoint<decimal> input);
}
}namespace QuantConnect.Indicators
{
public static class IndicatorExtensions
{
/// <summary>
/// Wraps an indicator with another indicator allowing composability
/// </summary>
/// <param name="wrapper">The exterior indicator</param>
/// <param name="root">The interior indicator</param>
/// <param name="name">An optional name for this indicator, if null, a name like wrapper.Name{root.Name} will be specified</param>
/// <returns></returns>
public static WrappedIndicator Of(this IIndicator wrapper, IIndicator root, string name = null)
{
name = name ?? string.Format("{0}{{{1}}}", wrapper.Name, root.Name);
return new WrappedIndicator(name, wrapper, root);
}
}
}using System.Collections.ObjectModel;
namespace QuantConnect.Indicators
{
/// <summary>
/// Manages indicators and their plotting
/// </summary>
public class IndicatorManager : KeyedCollection<string, IIndicator>
{
protected override string GetKeyForItem(IIndicator item)
{
return item.Name;
}
/// <summary>
/// Updates each item in this collection with the specified data
/// </summary>
/// <param name="input"></param>
public void Update(DataPoint<decimal> input)
{
foreach (var indicator in Items)
{
indicator.Update(input);
}
}
public void Plot(QCAlgorithm algorithm)
{
foreach (var indicator in Items)
{
algorithm.Plot("Indicators", indicator.Name, indicator.Value.Data);
}
}
}
}namespace QuantConnect.Indicators
{
public class MovingAverageConverganceDivergance : IndicatorBase
{
public readonly IIndicator Fast;
public readonly IIndicator Slow;
public MovingAverageConverganceDivergance(string name, int fastPeriod, int slowPeriod, MovingAverageType type = MovingAverageType.Simple)
: base(name)
{
switch (type)
{
case MovingAverageType.Simple:
Fast = new SimpleMovingAverage(string.Format("[{0}]_MACD_SMA{1}", name, fastPeriod), fastPeriod);
Slow = new SimpleMovingAverage(string.Format("[{0}]_MACD_SMA{1}", name, slowPeriod), slowPeriod);
break;
case MovingAverageType.Exponential:
Fast = new ExponentialMovingAverage(string.Format("[{0}]_MACD_EMA{1}", name, fastPeriod), fastPeriod);
Slow = new ExponentialMovingAverage(string.Format("[{0}]_MACD_EMA{1}", name, slowPeriod), slowPeriod);
break;
}
}
public override bool IsReady
{
// check both just in case someone wants them flipped, since we don't enforce
// that one is actually 'slower' than the other
get { return Slow.IsReady && Fast.IsReady; }
}
protected override decimal ComputeNextValue(DataPoint<decimal> previousValue, DataPoint<decimal> input)
{
Fast.Update(input);
Slow.Update(input);
return Fast.Value.Data - Slow.Value.Data;
}
}
}namespace QuantConnect.Indicators
{
public enum MovingAverageType
{
Simple,
Exponential
}
}namespace QuantConnect.Indicators
{
public class SimpleMovingAverage : WindowIndicator
{
private decimal _sum;
public SimpleMovingAverage(string name, int period) : base(name, period)
{
}
protected override decimal ComputeNextValue(IReadOnlyWindow<DataPoint<decimal>> window, DataPoint<decimal> previousValue, DataPoint<decimal> input)
{
_sum += input.Data;
if (window.Samples > window.Count) // this is different that window.IsReady by 1 sample
{
_sum -= window.MostRecentlyRemoved.Data;
}
return _sum/window.Count;
}
}
}namespace QuantConnect.Indicators
{
/// <summary>
/// Represents an indicator that acts on a rolling window of data
/// </summary>
public abstract class WindowIndicator : IndicatorBase
{
// a window of data over a certain look back period
private readonly RollingWindow<DataPoint<decimal>> _window;
/// <summary>
/// Initializes a new instance of the WindowIndicator class
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="period">The number of data points to hold in the window</param>
protected WindowIndicator(string name, int period)
: base(name)
{
_window = new RollingWindow<DataPoint<decimal>>(period);
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return _window.IsReady; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="previousValue">The most recent value of this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(DataPoint<decimal> previousValue, DataPoint<decimal> input)
{
_window.Add(input);
return ComputeNextValue(_window, previousValue, input);
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
base.Reset();
_window.Clear();
}
/// <summary>
/// Computes the next value for this indicator from the given state.
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="previousValue">The previous value of this indicator</param>
/// <param name="input">The input value to this indicator on this time step</param>
/// <returns>A new value for this indicator</returns>
protected abstract decimal ComputeNextValue(IReadOnlyWindow<DataPoint<decimal>> window, DataPoint<decimal> previousValue, DataPoint<decimal> input);
}
}namespace QuantConnect.Indicators
{
/// <summary>
/// Provides a means of piping data from one indicator to another, allowing composability
/// </summary>
public class WrappedIndicator : IIndicator
{
/// <summary>
/// Creates a new wrapped indicator that acts as wrapper { root }
/// So, if we have the root= Momentum and wrapper = SMA, then its like
/// having SMA of Momentum
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="wrapper">The wrapper, or external indicator</param>
/// <param name="root">The root, or interior indicator</param>
public WrappedIndicator(string name, IIndicator wrapper, IIndicator root)
{
Wrapper = wrapper;
Root = root;
Name = name;
}
/// <summary>
/// Gets the root, or interior indicator.
/// </summary>
public IIndicator Root { get; private set; }
/// <summary>
/// Gets the wrapper, or exterior indicator
/// </summary>
public IIndicator Wrapper { get; private set; }
/// <summary>
/// Gets a name for this indicator
/// </summary>
public string Name { get; private set; }
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public bool IsReady
{
get { return Wrapper.IsReady; }
}
/// <summary>
/// Gets the current state of this indicator. If the state has not been updated
/// then the time on the value will equal DateTime.MinValue.
/// </summary>
public DataPoint<decimal> Value
{
get { return Wrapper.Value; }
}
/// <summary>
/// Gets the number of samples processed by this indicator
/// </summary>
public int Samples { get; private set; }
/// <summary>
/// Updates the state of this indicator with the given value and returns true
/// if this indicator is ready, false otherwise
/// </summary>
/// <param name="input">The value to use to update this indicator</param>
/// <returns>True if this indicator is ready, false otherwise</returns>
public bool Update(DataPoint<decimal> input)
{
Samples++;
Root.Update(input);
if (Root.IsReady)
{
// we purposefully don't start sending data to the wrapper until the root is ready, since in reality
// we need to wait until the root is ready before we can start 'readying' the wrapper
Wrapper.Update(Root.Value);
}
return IsReady;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public void Reset()
{
Root.Reset();
Wrapper.Reset();
}
}
}using System;
namespace QuantConnect
{
public static class DataPoint
{
public static DataPoint<T> Create<T>(DateTime time, T value)
{
// this method provides some type inference convience so we need not specify the type parameter
return new DataPoint<T>(time, value);
}
}
/// <summary>
/// Represents a piece of data at a specific time
/// </summary>
/// <typeparam name="T">The type of data</typeparam>
public struct DataPoint<T>
{
public readonly T Data;
public readonly DateTime Time;
public DataPoint(DateTime time, T data)
: this()
{
Time = time;
Data = data;
}
public DataPoint<T> WithNewData(T newData)
{
return new DataPoint<T>(Time, newData);
}
}
}using System;
using System.Collections;
using System.Collections.Generic;
namespace QuantConnect
{
/// <summary>
/// Interface type used to pass windows around without worry of external modification
/// </summary>
/// <typeparam name="T">The type of data in the window</typeparam>
public interface IReadOnlyWindow<out T> : IEnumerable<T>
{
/// <summary>
/// Gets the size of this window
/// </summary>
int Size { get; }
/// <summary>
/// Gets the current number of elements in this window
/// </summary>
int Count { get; }
/// <summary>
/// Gets the number of samples that have been added to this window over its lifetime
/// </summary>
decimal Samples { get; }
/// <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>
T this[int i] { get; }
/// <summary>
/// Gets a value indicating whether or not this window is ready, i.e,
/// it has been filled to its capacity, this is when the Size==Count
/// </summary>
bool IsReady { get; }
/// <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>
T MostRecentlyRemoved { get; }
}
/// <summary>
/// This is a window that allows for list access semantics,
/// where this[0] refers to the most recent item in the
/// window and this[Count-1] refers to the last item in the window
/// </summary>
/// <typeparam name="T">The type of data in the window</typeparam>
public class RollingWindow<T> : IReadOnlyWindow<T>
{
private int _tail;
private decimal _samples;
private T _mostRecentlyRemoved;
private readonly List<T> _list;
private readonly object _lock = new object();
/// <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; }
}
public T MostRecentlyRemoved
{
get
{
if (!IsReady)
{
throw new InvalidOperationException("No items have been removed yet!");
}
return _mostRecentlyRemoved;
}
}
public RollingWindow(int size)
{
_list = new List<T>(size);
}
/// <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 { return _list[(Count + _tail - i - 1)%Count]; }
set { _list[Count + _tail - i - 1] = value; }
}
/// <summary>
/// Gets a value indicating whether or not this window is ready, i.e,
/// it has been filled to its capacity, this is when the Size==Count
/// </summary>
public bool IsReady
{
get { return Size == Count; }
}
/// <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)
{
lock (_lock)
{
_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 Clear()
{
lock (_lock)
{
_list.Clear();
}
}
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);
lock (_lock)
{
for (int i = 0; i < Count; i++)
{
temp.Add(this[i]);
}
}
return temp.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}