Series, Comparisons and Renderers

An explanation of the addSeries() method

Initially, a chart contains a single series of data, but additional series can be added with CIQ.ChartEngine#addSeries. The most common use for additional series is to produce comparison charts. A comparison chart displays two or more securities, each one plotted by percentage change from a known starting point. Series can be used for many purposes though. They can be used by technical studies (such as the price relative study) or can be used by "renderers" to create additional visualizations on the chart.

Using addSeries()

addSeries() adds additional data to stxx.chart.masterData.

When a quotefeed is attached to the chart engine, adding a series will prompt a fetchInitialData() call. The results of that fetch are then merged into the masterData array.

Example, adding a comparison series to a chart that has a quoteFeed attached to it, to be displayed as a red line :

stxx.addSeries("GE", {isComparison: true, color:"#FF0000"});

You can also provide data directly:

Example, add a series and provide the data :

stxx.addSeries("GE", {isComparison: true, color:"#FF0000", data:[...the data...]});

Note: when providing data statically, the quoteFeed will not manage pagination or updates for the series, and your array should contain objects with DT/Date and Close/Value fields.

Once a series has been added, the masterData will contain additional fields for that series. If you add multiple series, then multiple fields will be added.

Example, a data object from masterData after adding two additional series: GE and IBM :

{
  "DT": Date(),
  "Date": "20160101125943",
  "Close": 112.13,
  "GE": 54.54,
  "IBM": 165.32
}

Note: your masterData might also contain Open, High, Low, Volume or other fields.

The objects in masterData are processed and cloned into dataSet, then dataSegment, and eventually, the chart engine traverses dataSegment to render the chart. The chart engine uses a "renderer" to create the visual for the series. The default renderer simply draws a line.

It is not necessary for a series field to exist in every masterData element. Series data can also extend beyond the borders of masterData. The chart engine will intelligently compose masterData from the various independent series that are provided. When a renderer encounters an object without a data point for its series (a "gap") it will usually form a gap on the screen. The most common case is when comparing two symbols that trade on different hours.

Example, an FX security compared with a US stock shows gaps where one of the series has no data:

FX compared with US Stock

See CIQ.ChartEngine#addSeries for a complete list of parameters and a variety of examples.

To remove a series call stxx.removeSeries("GE"); .

Y-Axis

The y-axis must increase its range to accommodate all of the series prices that are displayed. If series prices are very wide apart, this can result in a chart with very tiny lines.

Example, The prices for T and IBM are so far apart that the chart isn't useful :

Series prices are far apart

stxx.addSeries("IBM", {color:"#FF0000", shareYAxis:true});

By default, additional series are "overlayed" onto the primary symbol. The y-axis retains the range of the primary symbol, and the actual prices of the overlayed series are reduced to fit in the same segment. In this way, an overlayed series retains the same visual movement that it would have if it were the primary. Note: If you want series to share the same y-axis then pass shareYAxis:true when adding the series.

Example, now IBM is overlayed so that we can visually see the price action :

IBM overlayed on T

stxx.addSeries("IBM", {color:"#FF0000"});

While an overlay shows the price action for two symbols, it doesn't show how they performed relative to each other. Setting isComparison:true when adding a series will set the chart into comparison mode. In this mode, the y-axis is transformed to represent the percentage change of each series. By convention, the comparison begins at the left edge of the chart. As a user zooms or scrolls, the computed ranges will change.

Example, IBM price change showed in percentage comparison :

IBM compared to T by percentage change

stxx.addSeries("IBM", {color:"#FF0000", isComparison:true});

Sometimes it's preferable to provide each series with its own y-axis. The visual representation of price movement is the same as in overlay mode but the overlayed series will have its own price range displayed on a separate y-axis. We can use a renderer to accomplish this (more on renderers later).

Example, IBM is given its own y-axis :

IMG with its own y-axis

var axis=new STXChart.YAxis({position:"left"});
var renderer=new STX.Renderer.Lines({params:{name:"lines", type:"line", "yAxis":axis}});
renderer=stxx.setSeriesRenderer(renderer);

stx.addSeries("IBM", {color:"#FF0000"}, function(){
  renderer.attachSeries("IBM").ready();
});

Renderers

Renderers provide a way to add visualizations for additional data series. In a standard securities chart, there is generally a line or candlestick that represents the price of the security over time. Frequently however we wish to plot additional points of data. The most common situation would be plotting the price for another security, as in a comparison chart. Or you might want to plot any sort of data: banking data, sentiment, etc.

Renderers get their data from "series". A series of data is added to the chart with the CIQ.ChartEngine#addSeries method.

Currently there are two types of renderers available:

1) CIQ.Renderer.Lines 2) CIQ.Renderer.Histogram

New renderers can be derived from the CIQ.Renderer base class by following the pattern used in the existing renderers.

Renderers are permanent in much the same way that overlays are permanent. You only need to add a renderer to the chart once. The renderer will continue to exist between newChart() calls (between symbol changes, periodicity changes, etc). However, as the developer you are responsible for ensuring the existence of the series data. When using a Quotefeed this will be done automatically but if you are pushing data into the chart be aware that the renderer data will be cleared anytime the masterData is reset (when newChart() is called).

Most frequently a Renderer will not share the same y-axis scale as the underlying security. You can define a separate y-axis for the renderer.

Here is an example of series using a left axis:

Here is an example of multiple series, each one with its own right axis:

Lines

This renderer will draw a line for each series that is attached. This renderer is used by CIQ.Comparison, which draws comparison charts.

Histogram

This render will draw a histogram (aka "Bar Chart"). If multiple series are attached then it will be a stacked histogram.

Overlays vs. Renderers

An overlay is a study that is displayed on the chart. There is overlap between renderer and overlay functionality but generally you should use an overlay if:

1) The overlay data can be derived from price data 2) The overlay data shares the same y-axis scale as the underlying price data 3) You wish to leverage the studyLibrary, tools and UI for studies

Since renderers are designed specifically to use series data, they are most useful when you need to graphically represent multiple series.

Sample Code

Create a Stacked Histogram

function createRenderer(){
    var axis2=new CIQ.ChartEngine.YAxis(); // Define a Y-axis for the renderer
    axis2.position="left";          // Position that axis on the left side of the chart

    // configure the histogram display
    var params={
        yAxis: axis2,
        name:               "My Data",
        type:               "histogram",
        subtype:            "stacked",
        heightPercentage:   .7,  // how high to go. 1 = 100%
        widthFactor:        .8   // to control space between bars. 1 = no space in between
    };

    //legend creation callback
    function histogramLegend(colors){/* your code to draw a legend*/}

    var histRenderer=stxx.setSeriesRenderer(new CIQ.Renderer.Histogram({params: params, callback: histogramLegend}));


    // add the histogram series, here we use the default QuoteFeed
    stxx.addSeries("EWZ", {display:"Brazil", data:{useDefaultQuoteFeed:true}});
    stxx.addSeries("EWJ", {display:"Japan", data:{useDefaultQuoteFeed:true}});

    histRenderer.removeAllSeries()
            .attachSeries("EWZ","#6B9CF7")
            .attachSeries("EWJ","#95B7F6")
            .ready();  //use ready() to immediately draw the histogram

    // Additional sample code:  

    // remove a single stack from the histogram
    // histRenderer.removeSeries("EWZ").ready();

    // remove all stacks from the histogram
    // histRenderer.removeAllSeries().ready();

    // remove the entire histogram renderer
    // stxx.removeSeriesRenderer(histRenderer);

}

Create a Line Renderer

function createRenderer(){

    var lineRenderer=stxx.setSeriesRenderer(new CIQ.Renderer.Lines({params: {name:"lines",  type:"line"}}));

    // add the comparison series.

    // Use "gaps" when you have series data that trades on different sessions. For instance a 24x7 forex symbol vs. a US equity

    // Use "permanent" to prevent the user from removing the series by right clicking

    stxx.addSeries("AAPL", {display:newSymbol,isComparison:true,data:{useDefaultQuoteFeed:true}, gaps:{pattern:[3,3]},width:4,permanent:true});
    stxx.addSeries("NOK", {display:"Nokia",isComparison:true,data:{useDefaultQuoteFeed:true}, gaps:{pattern:[3,3]},width:4});


    lineRenderer.removeAllSeries()
            .attachSeries("AAPL", "#FFEE00")
            .attachSeries("NOK", "#FFBE00")
            .ready();             
}

See CIQ.ChartEngine#addSeries
See CIQ.ChartEngine#removeSeries
See CIQ.ChartEngine#setSeriesRenderer
See CIQ.ChartEngine#removeSeriesRenderer
See CIQ.Renderer.Histogram
See CIQ.Renderer.Lines
See CIQ.Renderer
See CIQ.Renderer#attachSeries
See CIQ.Renderer#removeSeries
See CIQ.Renderer#removeAllSeries
See CIQ.Renderer#ready

Building Renderers

See CIQ.Renderer#performCalculations
See CIQ.Renderer#draw