| Overall Statistics |
|
Total Trades 1 Average Win 115.06% Average Loss 0% Compounding Annual Return 13.612% Drawdown 18.800% Expectancy 0 Net Profit 115.057% Sharpe Ratio 0.824 Loss Rate 0% Win Rate 100% Profit-Loss Ratio 0 Alpha -0.025 Beta 0.953 Annual Standard Deviation 0.173 Annual Variance 0.03 Information Ratio -1.844 Tracking Error 0.018 Treynor Ratio 0.15 |
using System;
using QuantConnect.Data;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Custom;
using QuantConnect.Data.Market;
using QuantConnect.Indicators;
namespace QuantConnect.Algorithm.Examples
{
public class CustomDataIndicators : QCAlgorithm
{
private string SPY_QuandlCode = "YAHOO/INDEX_SPY";
ExponentialMovingAverage emaClose;
ExponentialMovingAverage emaLow;
ExponentialMovingAverage emaHigh;
public override void Initialize()
{
// set up our analysis span
SetStartDate(2009, 01, 01);
SetEndDate(2015, 01, 01);
// request SPY data - the data feed does daily, so pick that too
AddData<Quandl>(SPY_QuandlCode, Resolution.Daily);
// create our consolidator, this will produce a 10 day bar.
var quandlConsolidator = new DynamicTradeBarConsolidator<Quandl>(10, TimeSpan.FromDays(1));
// this indicator is going to be a 5 period EMA, where the period is 10 days
emaClose = new ExponentialMovingAverage("EMA5_Close", 5);
// register our indicator with our custom consolidator, this allows it to receive automatic updates
// the x => x.Value is a selector that picks which data goes into our emaClose,
// in this case, Value is an alias for Close, so we're sending Closing data
// into our consolidator
RegisterIndicator(SPY_QuandlCode, emaClose, quandlConsolidator, x => x.Value);
// we could just as easily register to one of the dynamic properties with a caste
emaLow = new ExponentialMovingAverage("EMA5_Low", 5);
RegisterIndicator(SPY_QuandlCode, emaLow, quandlConsolidator, x => ((TradeBar)x).Low);
// we can do the same for High
emaHigh = new ExponentialMovingAverage("EMA5_High", 5);
RegisterIndicator(SPY_QuandlCode, emaHigh, quandlConsolidator, x => ((TradeBar)x).High);
}
public void OnData(Quandl data)
{
if (!Portfolio.HoldStock)
{
// without this line the plot doesn't show up in the ui
Plot(SPY_QuandlCode, emaClose.Name, data.Value);
SetHoldings(SPY_QuandlCode, 0.95);
return;
}
// don't start plotting until we've received at least one data point in the indicator
if (emaClose == 0m) return;
// plot our results
Plot(SPY_QuandlCode, emaClose, emaLow, emaHigh);
}
}
/// <summary>
/// Define a wrapper around the basic trade bar consolidator to handle the mapping
/// between dynamic OHLCV types and TradeBar
/// </summary>
public class DynamicTradeBarConsolidator<T> : DataConsolidator<T>
where T : BaseData
{
private readonly SequentialConsolidator _consolidator;
public DynamicTradeBarConsolidator(int numberOfPeriods, TimeSpan period)
{
// this is the consolidator we're wrapping, we're basically going to make him do all the work.
// the first parameter will produce bars at a given time resolution
// the second parameter will produce bars at a given number of bars passed
// this allows us to create a 5-day bar correctly, since really we want 10 trading
// days to pass, not just 10 calendar days.
var first = new TradeBarConsolidator(period);
var second = new TradeBarConsolidator(numberOfPeriods);
_consolidator = new SequentialConsolidator(first, second);
// due to a bugg in SequentialConsolidator we need to attach to the second (see commit cff6d3b)
//_consolidator.DataConsolidated += (sender, consolidated) =>
// when our internal consolidator fires we want to call this consolidator's event as well,
// since users are going to subscribe to those (DynamicTradeBarConsolidator.DataConsolidated)
second.DataConsolidated += (sender, consolidated) =>
{
OnDataConsolidated(consolidated);
};
}
public override Type OutputType
{
get { return typeof(TradeBar); }
}
public override void Update(T data)
{
// we're going to take out unknown, dynamic data and assume it has
// OHLCV defined on it. If not, this will throw exceptions.
var dynamicData = data as dynamic;
var dataAsTradeBar = new TradeBar
{
Time = data.Time,
Open = dynamicData.Open,
High = dynamicData.High,
Low = dynamicData.Low,
Close = dynamicData.Close,
Volume = (long)dynamicData.Volume // we parse everything as decimal, so convert to long here
// "Adjusted Close" is also a property
};
// pass our trade bar data through to the underlying trade bar consolidator
_consolidator.Update(dataAsTradeBar);
}
}
}