Indicators

Custom Resolutions

Introduction

This page explains how to create and update indicators with data of a custom resolution.

Prerequisites

Working knowledge of C#.

If you use Python, you must understand how to work with pandas DataFrames and Series. If you are not familiar with pandas, refer to the pandas documentation.

Get Historical Data

Get some historical market data to warm-up and create a historical record of indicator values. For example, to get data for SPY, run:

var qb = new QuantBook();
var symbol = qb.AddEquity("SPY").Symbol;
var history = qb.History(symbol, 70, Resolution.Daily);
qb = QuantBook()
symbol = qb.AddEquity("SPY").Symbol
history = qb.History(symbol, 70, Resolution.Daily).loc[symbol]

Create Indicator Timeseries

Follow these steps to create an indicator timeseries:

  1. Create an data-point indicator. In this tutorial, use a 20-period 2-standard-deviation BollingerBands indicator.
  2. var bb = new BollingerBands(20, 2);
    bb = BollingerBands(20, 2)
  3. Create a RollingWindow for each attribute of the indicator to hold their values.
  4. In this example, save 50 data points.

    var time = new RollingWindow<DateTime>(50);
    var window = new Dictionary<string, RollingWindow<decimal>>();
    window["bollingerbands"] = new RollingWindow<decimal>(50);
    window["lowerband"] = new RollingWindow<decimal>(50);
    window["middleband"] = new RollingWindow<decimal>(50);
    window["upperband"] = new RollingWindow<decimal>(50);
    window["bandwidth"] = new RollingWindow<decimal>(50);
    window["percentb"] = new RollingWindow<decimal>(50);
    window["standarddeviation"] = new RollingWindow<decimal>(50);
    window["price"] = new RollingWindow<decimal>(50);
    
    window = {}
    window['time'] = RollingWindow[DateTime](50)
    window["bollingerbands"] = RollingWindow[float](50)
    window["lowerband"] = RollingWindow[float](50)
    window["middleband"] = RollingWindow[float](50)
    window["upperband"] = RollingWindow[float](50)
    window["bandwidth"] = RollingWindow[float](50)
    window["percentb"] = RollingWindow[float](50)
    window["standarddeviation"] = RollingWindow[float](50)
    window["price"] = RollingWindow[float](50)
    
  5. Set handler methods to update the RollingWindows.
  6. bb.Updated += (sender, updated) => 
    {
        var indicator = (BollingerBands)sender;
        time.Add(updated.EndTime);
        window["bollingerbands"].Add(updated);
        window["lowerband"].Add(indicator.LowerBand);
        window["middleband"].Add(indicator.MiddleBand);
        window["upperband"].Add(indicator.UpperBand);
        window["bandwidth"].Add(indicator.BandWidth);
        window["percentb"].Add(indicator.PercentB);
        window["standarddeviation"].Add(indicator.StandardDeviation);
        window["price"].Add(indicator.Price);
    };
    def UpdateBollingerBandWindow(sender: object, updated: IndicatorDataPoint) -> None:
        indicator = sender
        window['time'].Add(updated.EndTime)
        window["bollingerbands"].Add(updated.Value)
        window["lowerband"].Add(indicator.LowerBand.Current.Value)
        window["middleband"].Add(indicator.MiddleBand.Current.Value)
        window["upperband"].Add(indicator.UpperBand.Current.Value)
        window["bandwidth"].Add(indicator.BandWidth.Current.Value)
        window["percentb"].Add(indicator.PercentB.Current.Value)
        window["standarddeviation"].Add(indicator.StandardDeviation.Current.Value)
        window["price"].Add(indicator.Price.Current.Value)
    
    bb.Updated += UpdateBollingerBandWindow

    When the indicators receive new data, the handler will add the new IndicatorDataPoints into the RollingWindows.

  7. Create a TradeBarConsolidator to consolidate data into the custom resolution needed.
  8. In this tutorial, 7-day bar will be used.

    var consolidator = new TradeBarConsolidator(TimeSpan.FromDays(7));
    consolidator = TradeBarConsolidator(timedelta(days=7))
  9. Set a handler method to feed data into the consolidator and generate consolidated bar.
  10. consolidator.DataConsolidated += (sender, consolidated) =>
    {
        bb.Update(consolidated.EndTime, consolidated.Close);
    };
    consolidator.DataConsolidated += lambda sender, consolidated: bb.Update(consolidated.EndTime, consolidated.Close)

    When the consolidator receive data for every 7 days, the handler will generate a 7-day TradeBar and update the indicator.

  11. Iterate the historical market data and feed into the consolidator to update the indicators and the RollingWindows.
  12. foreach(var bar in history){
        consolidator.Update(bar);
    }
    for time, row in history.iterrows():
        # Create a TradeBar object.
        bar = TradeBar(time, symbol, row.open, row.high, row.low, row.close, row.volume)
        # Update the consolidator with the TradeBar
        consolidator.Update(bar)
  13. Display the data.
  14. Console.WriteLine($"time,{string.Join(',', window.Select(kvp => kvp.Key))}");
    foreach (var i in Enumerable.Range(0, 5).Reverse())
    {
        var data = string.Join(", ", window.Select(kvp => Math.Round(kvp.Value[i],6)));
        Console.WriteLine($"{time[i]:yyyyMMdd}, {data}");
    }
  15. Convert the RollingWindows' data into pandas.DataFrame.
  16. bb_dataframe = pd.DataFrame(window).set_index('time')

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: