Range and Span

The left and right dates displayed on a chart are referred to as the chart's range. The amount of time displayed is referred to as span. A chart might have a range of Jan 1, 2016 to Jan 1, 2017 which is a span of 1 year.

Developers can programmatically set a chart's range or span using CIQ.ChartEngine#setRange and CIQ.ChartEngine#setSpan. The span of the chart can also be specified when initializing a chart with CIQ.ChartEngine#loadChart. By default, the span of a chart is "remembered" in the chart's layout, so that the span will remain consistent as the user changes symbols.

sample-template-advanced.html, for example, includes a range selector web component which allows a user to dynamically set the range for the chart. Range selectors are easy to build using the setSpan() method.

Example, chart that provides a "range selector" which allows users to set both span and range for the chart :

Span Options

Setting Span or Range

The library provides two helper methods: setSpan() and setRange().

setRange and setSpan will try to determine an appropriate periodicity for the requested span or range. By default, periodicity will be limited to intervals of "1 minute", "5 minute", "30 minute" or "1 day".

The default periodicity selection can optionally be overridden by passing a periodicity object as a separate argument.

Understanding Periodicity

To properly implement range, it is important to understand periodicity.

Periodicity is the amount of time represented by one bar or point on the chart. For example, in the chart above, each bar represents 1 day, therefore it has a periodicity of 1 day. The span of the chart is 3 months, composed of 1 day bars.

The periodicity of the chart is represented by the variables stxx.layout.interval, stxx.layout.timeUnit and stxx.layout.periodicity.

  • timeUnit is the time unit of the bars in the source data when the interval is numeric. Otherwise, timeUnit is not used.
  • interval, when containing a numeric value, specifies the number of timeUnits in a bar. For example, a 5 minute bar would have an interval of 5 and a timeUnit of 'minute'. If interval is not numeric, it represents the time unit, which could be 'day', 'week', 'month' or 'tick'.
  • periodicity is the number of intervals (if the interval is time unit) or interval-timeUnits (if the interval is numeric) from the source data to roll up into one visual chart bar. This is primarily used to create additional chart periodicities that are not natively available from the data source.

Here are some examples:

  • Source data has a periodicity of 1 minute. Chart needs a periodicity of 2 minutes. In this case, set interval to 1, timeUnit to 'minute' or 'null' and periodicity to 2.
  • Source data has a periodicity of 5 minutes. Chart needs a periodicity of 20 minutes. In this case, set interval to 5, timeUnit to 'minute' or 'null' and periodicity to 4.
  • Source data and chart both have a periodicity of 1 minute. set interval to 'day' and periodicity to 1.

The chart stores the source data in stxx.chart.masterData. It stores the rolled up (periodicity converted from source to that displayed on the chart) data in stxx.chart.dataSet.

It is important to set an appropriate periodicity for a given span. You wouldn't want to use 1 minute bars for a chart with a 1 year span. That would require 525,000 data points! You also wouldn't want to use 1 month bars. That would only show 12 data points. By default, CIQ.ChartEngine#setSpan and CIQ.ChartEngine#setRange will automatically pick a reasonable periodicity but developers can also specify the periodicity, to optimize the performance and aesthetics of the chart.

Note: For interactive charts, span is momentary. Scrolling or zooming changes the span!

Note: Many legacy data feeds have the "concept" of span built in. This is particularly true for feeds that previously serviced static charts. In such systems, a chart might request "1 year of data" from the server, and then blindly display the data. Charts produced by the ChartIQ library however are designed to be interactive. In the ChartIQ library, the concept of span is handled on the client side. The chart will typically request more than 1 year of data when displaying a 1 year span. This is so that the user can interact with the chart (zoom or scroll) without triggering an immediate pagination request.

For more information on the data objects, visit Understanding the Data Shown on the Chart.

setSpan() is used to set the range of the data displayed on the chart to cover a specific span of time. Examples would be: "1 year", "3 months", "1 hour", "53 minutes". Spans always assume the right side of the chart is the most recent bar (it is not possible to set a span that occurred in the past, such as "last year"). Internally, setSpan calculates a date range for the requested span and calls setRange with those dates.

Note: setSpan will determine a periodicity for optimal chart display unless the maintainPeriodicity parameter is present and set to true.

Example, using setSpan() to make 1 year of data visible on the chart :

// 1 year chart
stxx.setSpan({
	multiplier: 1,
	base: "year"
});
Special Values for "base"
  • 'today': The behavior of today is different from other span choices. This span will range from the current day's market open to the current day's market close. Unlike the other spans, the chart will extend into the future, leaving enough blank space on the right side of the chart for the remaining time left in the day. A streaming chart set to a span of "today" will slowly fill up the screen as the trading day progresses.

    • "today" relies on the market definition that is set on the chart using setMarket(). If a market definition is not set then a 24 hour market is assumed and the span is set from today's first available data of the day until midnight. If no data is available for the current day, then the span is set to the data available for the previous market day.
  • 'ytd': Sets the span from the start of the year to now.

  • 'all': Sets the span to all available data for the symbol. If pagination is supported by the chart's quotefeed then multiple requests will be made to the server until all the data has been loaded.

setRange()

setRange() is used to set the start and end dates for the chart. Note that this only affects the displayed portion of the chart. More data may be available off the left edge of the screen so that a user can scroll or zoom the chart without forcing a pagination request.

Example, use setRange() to set the visible portion of the chart from January to November :

stxx.setRange({
	dtLeft: new Date(2016, 01, 01), // Date of the left edge of chart
	dtRight: new Date(2016, 11, 01) // Date of the right edge of chart
});

loadChart()

It is often desirable to set the span for a newly initialized chart. This is done with optional parameters when calling stxx.loadChart().

Example, change the symbol and set the chart to a span of 1 day :

stxx.loadChart(
	newSymbol,
	{
		span: {
			base: "day",
			multiplier: 1
		}
	},
	callback
);

To change the span after the chart has been initialized, use setSpan() on its own.

Note: loadChart() does not support range, only span. To initialize a chart with a specific range, call setRange() in the loadChart's callback.

Example, initialize a chart with a range :

stxx.loadChart(symbol, function() {
	stxx.setRange({
		dtLeft: new Date(2016, 01, 01), // Date of the left edge of chart
		dtRight: new Date(2016, 11, 01) // Date of the right edge of chart
	});
});

Overriding periodicity when setting span or range

setSpan(), setRange() and loadChart() automatically pick an appropriate periodicity from the subset of "1 minute", "5 minute", "30 minute" or daily bars. This behavior can be overridden by passing an optional period parameter.

Example, Set the chart to span one year. Each bar should represent 2 days :

stxx.setSpan({
	multiplier: 1,
	span: "year",
	periodicity: {
		period: 2,
		timeUnit: "day"
	}
});

The same rules apply for periodicity when setting a span or range as apply for CIQ.ChartEngine#setperiodicity.


Candlewidth and Number of Ticks

The amount of data shown on the chart (the zoom level) is controlled by two factors:

  • The width of the chart (stxx.chart.width)
  • The width of a bar or candle (stxx.layout.candleWidth)

The amount of data displayed can therefore be controlled by setting either the number of bars or the width of the candles (bars). The library provides the setCandleWidth() method to set the width of the bars and the setMaxTicks() method to specify the number of bars shown on the chart.

By default, the Minimum Width for a bar is 1px. As such, there may be times when the requested data will not all fit on the screen, even though it is available. See CIQ.ChartEngine#minimumCandleWidth for instructions on how to override the default to allow more data to display.

Note: The width of the chart is computed automatically as the width of the chart container minus the width of y-axis.

What happens to a range if the width of the chart changes?

As previously outlined, a range is set by adjusting the width of the candles together with the scroll position to ensure the requested data is shown on the currently sized "view window".

Changing the size of the “view window” (chart width), manually by a user adjusting the browser width or programmatically, will alter the visible data range since it was based on the original chart width.

When the chart width is changed the scroll and candle width remains the same. As a result, the user will end up seeing a different range than initially set.

For example, assuming an original range of 1 year as pictured here:

Original width

You can see that data from April 2019 to March 2020 is being displayed.

After reducing the width of the chart by about 1/3 from its original size, this is the resulting view window:

Half width

You can see that only data from July 2019 to March 2020 is now being displayed.

Conversely, if the the width of the chart is increased to double its original size, this is the reusing view window:

Double width

You can see that data from April 2018 to March 2020 is now being displayed.

If you wish to maintain the same range as the width of the chart is changed, your application will have to explicitly reset the scroll location and the candle width to comply with the new window size. Simply calling setSpan/setRange after every window size change will do this. You don't have to call loadChart, unless you also want to change the data.

Example:

// this will trigger every time the browser window is resized
$(window).resize(/** add your code here to adjust range as needed**/);

For more details see CIQ.ChartEngine#resizeChart

If you want to produce a smooth gradual adjustment, instead of adjusting on the final width, see this injection

setCandleWidth() and setMaxTicks()

The variable stxx.chart.maxTicks contains the number of bars/candles that can be displayed, given the chart's size and the width of the candles. stxx.layout.candleWidth represents the number of pixels occupied by one candle (bar or point). These values are dynamic. They are automatically calculated when a user zooms a chart, when a span or range is set, or when the developer calls setCandleWidth() or setMaxTicks(). Note that if the chart is scrolled past the right margin (into the future), there will be "whitespace" in the positions that don't contain data. The number of "visible" bars may therefore be less than maxTicks because whitespace ticks are also counted.

Example, display a chart with exactly 100 candles :

stxx.setMaxTicks(100);
stxx.home(); // position the chart with "now" on the far right side
stxx.draw();

Example, use candleWidth to Zoom in by 10% :

stxx.setCandleWidth(stxx.layout.candleWidth * 1.1);
stxx.draw();

Understanding candleWidth vs. the actual width of a displayed candle

Each candle is allocated a width (CIQ.ChartEngine.layout.candleWidth) , which starts where the previous candle ended. So in reality there is no padding between their allocated paces.

Now, you can configure a candles to display differently within the allocated space. For example, if you set candles take 100% of the allocated space, they will all be touching each other. But if you set them to take 50%, they will be drawn with space between each other, even tough their allocated space has not changed at all.

The candle rendering can take as much or as little of the allocated space, but for tracking purposes the entire allocated space is used. This is why at times the dataSegment may contain what seems to be extra objects for candles you do not see on the edges of the chart view window.

By default our chart displays candles at 65% of the total allocated width. See CIQ.ChartEngine#candleWidthPercent

Whitespace

The initial amount of whitespace to display between the right edge of the chart and the y-axis is controlled by the stxx.preferences.whitespace variable. Set this to zero in order to get a chart that is flush against the y-axis.

Example, set the chart to be flush with the right edge of the y-axis :

stxx.preferences.whitespace = 0;

The value of this variable will change when a user scrolls the chart. This is so that a user can set a preferred amount of whitespace on the right margin and then maintain that space as new bars form. Note, this preference is not saved automatically in the layout. It is only maintained for the duration of the user's session. To save the whitespace setting permanently, call stxx.changeOccurred("preferences").

Saving and Restoring Span

The library provides the functions importLayout() and exportLayout() to import and export the chart layout. The chart span information is incuded in the chart layout.

The "managePeriodicity" flag must be set to true when restoring a chart layout back to the original span :

stxx.importLayout(layout, { managePeriodicity: true });

For more information, visit Importing and Exporting.

setRange Example:

This example illustrates how to load a chart with a preset range that can not be modified by the user. Note this leverages the 'range' parameter present in CIQ.ChartEngine#loadChart, rather than explicitly calling CIQ.ChartEngine#setRange.


Next Steps: