I don't know about you guys but I love charts! And what good is a chart without indicators, right? So naturally, when I ventured into this glorious universe we call QuantConnect, the first thing I wanted to do is get some squiggles up on the screen.

What I've done here is try to package up a core design philosophy I have about indicators (really they're sequential forward-only filters, but that's a mouthful!). The idea is that a filter works on a stream of data. More importantly, the filter doesn't care where the data came from... just that it's new data and needs to be accounted for in the filter's state. Looking at a filter like this it immediately lends itself to a recursive relationship, where a filter's input can be the output from another filter! This has many application in quantitative finance for the technical traders. What exactly is a 'signal line' other than an indicator on top of another indicator. Think back to the classic MACD cross. The 'fast' line is the actual MACD (difference between two moving averages) and the signal line is typically a 9 day SMA of the MACD, and when they cross it means something special. Baking this concept into the IIndicator infrastructure is central to achieving composability.

So I took a little time and whipped up some of the basic indicators. We now have easy access to SMA, EMA, RSI, and MACD. We also have access to what I've called the 'WrappedIndicator' which is defining an indicator from two existing ones by 'piping data' from the 'root' indicator to the 'wrapper' indicator. Moreover, adding new indicators should be easy as pie with two abstract classes to lend you much of the implementation. See the IndicatorBase and the WindowIndicator abstract classes. IndicatorBase is just that, it's a base and can be used by all indictors as it enforces the IIndicator contract invariants. WindowIndicator using a RollingWindow (very similar to FixedSizeQueue I've seen elsewhere, with the added benefit of this[int] accessors being well defined). I've also included some static functions in the algorithm class itself to allow for easy instantiation of these types. After placing the static functions in your algorithm class (along with supporting classes... there are many!) you can write code like this:

public override void Initialize()

{

// initialize your indicators in the Initialize method

sma = SMA(14); // create a SimpleMovingAverage of period 14

ema = EMA(14); // create an ExponentialMovingAverage of period 14

macd = MACD(14, 26); // create a MovingAverageConvergenceDivergence with fast=14 and slow=26, defaults to MovingAverageType.Simple

rsi = RSI(14); // create a RelativeStrengthIndex of period 14

// now say we actually want to get the MACD of the RSI(14)... we can easily do that!!

// this 'Of' method is an extension method defined on IndicatorExtensions and makes for better code readability

// under the hood all it does is create a new WrappedIndicator which pipes the data through the 'root' indicator and then

// pipes the 'root' indicator's output to the 'wrapper' inidicator

macdOfRsi = macd.Of(rsi);

}

public override void OnTradeBar(Dictionary data)

{

// update your indicators when you get new data for the indicator... if it's a daily indicator make sure you only feed it data daily!

TradeBar bar;

if (data.TryGetValue("SPY", out bar)

{

var dataPoint = DataPoint.Create(bar.Time, bar.Close);

sma.Update(dataPoint);

ema.Update(dataPoint);

// an important not here is that calling Update will also call update on the child

// indicators, in this case, rsi and macd from the Initialize method

macdOfRsi.Update(dataPoint);

}

}

Sadly, there's a fair amount of files here, but I think they're worth a serious look for anyone developing strategies involving indicators. Hopefully in the future we'll get an update that gives QuantConnect better web support for many files -- hint hint Jared -- folders!! :D.

Phew, I think that's enough for now (its almost 2am!). Also, please excuse me, I didn't write complete unit tests so if there's a bug please let me know.

As always, feedback is appreciated!