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(); } } }