Term Structures

Customization

Term structure charts can be customized to your preferences — to present different kinds of information, to enhance understanding of the term structure data.

In this tutorial

You will learn how to customize the y-axis values, y-axis formatting, instrument background shading, and x-axis scaling of term structure charts.

Before you begin

This tutorial is a continuation of the Term Structures Introduction tutorial.

Please familiarize yourself with the introductory material before proceeding.

Customizing the chart

We'll customize the termstructure.html file we created in the introductory tutorial by adding some markup and JavaScript.

Here's where we left off:

<!doctype html>
<html>
<head>
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">

<!-- Include the main ChartIQ CSS file. -->
<link rel="stylesheet" type="text/css" href="css/stx-chart.css" media="screen" />

<!-- Reference the main ChartIQ JavaScript library file. -->
<script src="js/chartiq.js"></script>

<!-- Reference the term structure plug-in. -->
<script src="plugins/termstructure/termstructure.js"></script>

<script>
// Create a handler that displays the term structure chart.
function displayChart() {
    // Create a chart engine instance.
    var stxx = new CIQ.ChartEngine({container: document.querySelector(".chartContainer")});

    // Create a term structure object and associate it with the chart engine.
    new CIQ.TermStructure({stx: stxx, useQuotefeed: false});

    // Notify the chart engine of the chart type.
    stxx.setChartType("termstructure");

    // Load the chart.
    stxx.loadChart("US-T BENCHMARK", {
        masterData: quotes // Add a data source to the chart.
    });
};
</script>
</head>

<!-- Set the onload handler. -->
<body onload="displayChart()">

<!-- Create the container for the chart. -->
<div class="chartContainer" style="width: 1200px; height: 675px; position: relative;"></div>

</body>

<!-- Create a static data source for the term structure. -->
<script>
var quotes = [
    {
        DT: new Date(),
        Date: new Date().toISOString(),
        termStructure: {
             "1 MO": {yield: 2.31},
             "2 MO": {yield: 2.37},
             "3 MO": {yield: 2.41},
             "6 MO": {yield: 2.53},
             "1 YR": {yield: 2.70},
             "2 YR": {yield: 2.83},
             "3 YR": {yield: 2.86},
             "5 YR": {yield: 2.89},
             "7 YR": {yield: 2.98},
            "10 YR": {yield: 3.06},
            "20 YR": {yield: 3.22},
            "30 YR": {yield: 3.32}
        }
    }
];
</script>
</html>

Data source

Let's begin by adding some data to our term structure instruments. Replace the termStructure property in the static data source in termstructure.html with the following:

termStructure: {
     "1 MO": { yield: 2.31, bid:  77.27, mid:  79.27, ask:  81.27 },
     "2 MO": { yield: 2.37, bid:  80.89, mid:  82.89, ask:  84.89 },
     "3 MO": { yield: 2.41, bid:  83.06, mid:  85.06, ask:  87.06 },
     "6 MO": { yield: 2.53, bid:  85.64, mid:  87.64, ask:  89.64 },
     "1 YR": { yield: 2.70, bid:  89.57, mid:  91.57, ask:  93.57 },
     "2 YR": { yield: 2.83, bid:  92.82, mid:  94.82, ask:  96.82 },
     "3 YR": { yield: 2.86, bid:  93.11, mid:  95.11, ask:  97.11 },
     "5 YR": { yield: 2.89, bid:  96.06, mid:  98.06, ask: 100.06 },
     "7 YR": { yield: 2.98, bid:  96.48, mid:  98.48, ask: 100.48 },
    "10 YR": { yield: 3.06, bid:  99.94, mid: 101.94, ask: 103.94 },
    "20 YR": { yield: 3.22, bid: 103.52, mid: 105.52, ask: 107.52 },
    "30 YR": { yield: 3.32, bid: 105.52, mid: 107.52, ask: 109.52 }
}

Treasury instruments are bought and sold through financial markets (they can also be bought directly from the U.S. Treasury). The bid, mid, and ask values are the dollar amounts at which the instruments are trading at a given point in time (the DT or Date value in the quote object).

The bid is the price buyers are willing to pay for the instrument. The ask is the price sellers are willing to accept for the instrument. The mid is the average of the bid and ask.

Y-axis values

The term structure chart, by default, plots yield as the instrument values; that is, the y-axis values.

To plot a different field, include the optional dataField parameter in the call to the CIQ.TermStructure constructor function and set its value to the key of one of the data fields; for example, dataField: "bid".

Revise the CIQ.TermStructure constructor call in termstructure.html as follows:

new CIQ.TermStructure({stx: stxx, useQuotefeed: false, dataField: "bid"});

Load the file into your web browser to see how the chart has changed.

Try setting the data field to "ask" and "mid".

Y-axis formatting

Some data fields are best displayed as raw values, some as percentages. ChartIQ enables you to format term structure y-axis values either way.

You may have noticed that yield is formatted as a percentage but bid, ask, and mid are not. Yields are typically expressed as percentages, so CIQ.TermStructure formats them that way by default.

To format other values as percentages, include the optional fieldsToFormatAsPercent parameter in the CIQ.TermStructure constructor function call. Set an array as the value of the parameter, and add the name of the data field to the array; for example, fieldsToFormatAsPercent: ["bid"]. The default value is ["yield"].

Revise the CIQ.TermStructure instantiation as follows:

new CIQ.TermStructure({stx: stxx, useQuotefeed: false, dataField: "bid", fieldsToFormatAsPercent: ["bid"]});

You can add "ask" and "mid" to the fieldsToFormatAsPercent array to display their values as percentages.

Load the file to see the change to the y-axis legend.

Note: The values of bid, ask, and mid are dollar amounts, so formatting them as percentages doesn't make sense, but the fieldsToFormatAsPercent parameter enables you to format any field as a percentage.

Shading

The background shading of term structure charts helps you visually group instruments that are similar.

The shading can be customized by specifying RBGA values in CSS styles defined for the term structure instruments. The term structure plug-in looks for CSS class names that take the form: .stx_shading_ + <the instrument name with spaces removed>; for example, .stx_shading_1MO (see the data source above for the instrument names).

Add the following styles to termstructure.html, and reload the file:

<style>
.stx_shading_1MO,
.stx_shading_2MO,
.stx_shading_3MO,
.stx_shading_4MO,
.stx_shading_5MO,
.stx_shading_6MO,
.stx_shading_8MO,
.stx_shading_9MO {
    background-color: rgba(162, 199, 255, 0.3);
}
.stx_shading_1YR,
.stx_shading_2YR,
.stx_shading_3YR,
.stx_shading_4YR,
.stx_shading_5YR,
.stx_shading_7YR,
.stx_shading_ST {
    background-color: rgba(95, 159, 255, 0.3);
}
.stx_shading_10YR,
.stx_shading_15YR,
.stx_shading_20YR,
.stx_shading_30YR,
.stx_shading_40YR,
.stx_shading_MT,
.stx_shading_LT {
    background-color: rgba(20, 97, 212, 0.3);
}
</style>

You can insert the <style> element wherever you like in the file; stx-chart.css does not contain these styles.

Feel free to extract the styles into an external CSS style sheet.

Scaling

Term structure charts feature the concept of scaled spacing. Instruments can be non-uniformly spaced based on delivery dates or contract expiration dates or some other criterion that implies non-uniform differences among the instruments. The Treasury yield curve is a good example: maturity dates occur in the irregular time sequence of 1 Mo, 2 Mo, 3 Mo, 6 Mo, 1 Yr, 2 Yr, 3 Yr, 5 Yr, 7 Yr, 10 Yr, 20 Yr, and 30 Yr.

A uniform representation of those time-to-maturity differences in actual time values (such as months) would produce a chart with most of the data points very tightly clustered on the left of the chart. To spread out the data while still providing a sense of the relative differences among instruments, the data points are plotted along the x-axis using a scaling algorithm that is effectively logarithmic.

You can create a custom spacing algorithm by overriding the default calculateScaledSpacingUnits method of CIQ.TermStructure. The only thing the term structure plug-in expects is that the returned spacingUnits object contains key/value pairs for all instruments, where the keys identify the instruments and the values represent the number of “spacing units” for the instrument. The renderer adds up all the spacing units and allocates a percentage of horizontal space to each instrument based on how many spacing units the instrument has relative to the total amount.

Add the following custom calculateScaledSpacingUnits script to termstructure.html:

<script>
CIQ.TermStructure.prototype.calculateScaledSpacingUnits = function(instruments) {

    let spacingUnits = {};

    function calculateValue(instrument) {
        let [value, type] = instrument.split(" ");
        value = parseInt(value);
        if (type === "WK") value *= 7;
        if (type === "MO") value *= 30;
        if (type === "YR") value *= 30 * 12;
        return value;
    }

    for (let i = 0; i < instruments.length; i++) {
        let instrument = instruments[i];
        let previousInstrument = instruments[i - 1];
        // No spacing for first entry.
        if (i === 0) {
            spacingUnits[instrument] = 0;
            continue;
        }

        let value = calculateValue(instrument) - calculateValue(previousInstrument);
        value = Math.pow(value, 0.5);
        spacingUnits[instrument] = value;
    }

    return spacingUnits;
};
</script>

Note: For the override to work, you have to add the script after the term structure plug-in:

<script src="plugins/termstructure/termstructure.js"></script>

Tip: To change the instrument spacing, adjust the power in the following statement:

value = Math.pow(value, 0.5);

Set the power to zero to space the instruments evenly; 1, to space them based on the number of months. Vary the power and see what you get.

The customized chart

Here's an example of what termstructure.html might look like with all of our customizations in place:

<!doctype html>
<html>
<head>
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">

<!-- Include the main ChartIQ CSS file. -->
<link rel="stylesheet" type="text/css" href="css/stx-chart.css" media="screen" />

<!-- Create the background shading styles. -->
<style>
.stx_shading_1MO,
.stx_shading_2MO,
.stx_shading_3MO,
.stx_shading_4MO,
.stx_shading_5MO,
.stx_shading_6MO,
.stx_shading_8MO,
.stx_shading_9MO {
    background-color: rgba(162, 199, 255, 0.3);
}
.stx_shading_1YR,
.stx_shading_2YR,
.stx_shading_3YR,
.stx_shading_4YR,
.stx_shading_5YR,
.stx_shading_7YR,
.stx_shading_ST {
    background-color: rgba(95, 159, 255, 0.3);
}
.stx_shading_10YR,
.stx_shading_15YR,
.stx_shading_20YR,
.stx_shading_30YR,
.stx_shading_40YR,
.stx_shading_MT,
.stx_shading_LT {
    background-color: rgba(20, 97, 212, 0.3);
}
</style>

<!-- Reference the main ChartIQ JavaScript library file. -->
<script src="js/chartiq.js"></script>

<!-- Reference the term structure plug-in. -->
<script src="plugins/termstructure/termstructure.js"></script>

<script>
// Create a handler that displays the term structure chart.
function displayChart() {
    // Create a chart engine instance.
    var stxx = new CIQ.ChartEngine({container: document.querySelector(".chartContainer")});

    // Create a term structure object and associate it with the chart engine.
    new CIQ.TermStructure({ stx: stxx,
                            useQuotefeed: false,
                            dataField: "bid",
                            fieldsToFormatAsPercent: ["bid", "ask", "mid"]
                          });

    // Notify the chart engine of the chart type.
    stxx.setChartType("termstructure");

    // Load the chart.
    stxx.loadChart("US-T BENCHMARK", {
        masterData: quotes // Add a data source to the chart.
    });
};
</script>
</head>

<!-- Set the onload handler. -->
<body onload="displayChart()">

<!-- Create the container for the chart. -->
<div class="chartContainer" style="width: 1200px; height: 675px; position: relative;"></div>

</body>

<!-- Create a static data source for the term structure. -->
<script>
var quotes = [
    {
        DT: new Date(),
        Date: new Date().toISOString(),
        termStructure: {
             "1 MO": { yield: 2.31, bid:  77.27, mid:  79.27, ask:  81.27 },
             "2 MO": { yield: 2.37, bid:  80.89, mid:  82.89, ask:  84.89 },
             "3 MO": { yield: 2.41, bid:  83.06, mid:  85.06, ask:  87.06 },
             "6 MO": { yield: 2.53, bid:  85.64, mid:  87.64, ask:  89.64 },
             "1 YR": { yield: 2.70, bid:  89.57, mid:  91.57, ask:  93.57 },
             "2 YR": { yield: 2.83, bid:  92.82, mid:  94.82, ask:  96.82 },
             "3 YR": { yield: 2.86, bid:  93.11, mid:  95.11, ask:  97.11 },
             "5 YR": { yield: 2.89, bid:  96.06, mid:  98.06, ask: 100.06 },
             "7 YR": { yield: 2.98, bid:  96.48, mid:  98.48, ask: 100.48 },
            "10 YR": { yield: 3.06, bid:  99.94, mid: 101.94, ask: 103.94 },
            "20 YR": { yield: 3.22, bid: 103.52, mid: 105.52, ask: 107.52 },
            "30 YR": { yield: 3.32, bid: 105.52, mid: 107.52, ask: 109.52 }
        }
    }
];
</script>

<!-- Override the term structure function that scales the data points on the x-axis. -->
<script>
CIQ.TermStructure.prototype.calculateScaledSpacingUnits = function(instruments) {

    let spacingUnits = {};

    function calculateValue(instrument) {
        let [value, type] = instrument.split(" ");
        value = parseInt(value);
        if (type === "WK") value *= 7;
        if (type === "MO") value *= 30;
        if (type === "YR") value *= 30 * 12;
        return value;
    }

    for (let i = 0; i < instruments.length; i++) {
        let instrument = instruments[i];
        let previousInstrument = instruments[i - 1];
        // No spacing for first entry.
        if (i === 0) {
            spacingUnits[instrument] = 0;
            continue;
        }

        let value = calculateValue(instrument) - calculateValue(previousInstrument);
        value = Math.pow(value, 0.5);
        spacingUnits[instrument] = value;
    }

    return spacingUnits;
};
</script>
</html>

Load the file to see our improvements. The chart should look like this:

Customized term structure

Leveraging Term Structure specific UI

The library provides out-of-the-box UI elements that can be used on a term structure chart if you wish to link it to a time series. See CIQ.UI.CurveEdit for instructions.

Conclusion

This tutorial has shown you several ways to customize term structure charts. The configuration parameters of CIQ.TermStructure provide opportunities for more.

Contact us at support@chartiq.com if you have any questions.

Next Steps: