ChartDirector Ver 3.0 (C++ Edition)

Finance Chart (2)




This example demonstrates combining various ChartDirector features to create full-featured finance charts. The chart in this example includes candlestick, moving averages, Donchian channel, volume data, MACD and Stochastic indicators. You may use techniques demonstrated in this example to create additional indicators of your choice.

This example assumes the source data comes from a database table with 6 columns for time stamp, high value, low value, open value, close value, and volume. These data are then used to devire additional indicators such as moving averages, Donchian channel, MACD and Stochastic.

For simplicity and to allow this example to run without connecting to a real database, a RanTable object is used to simulate the database table. RanTable is a ChartDirector utility class used for creating tables with random numbers.

Data Preparation

Overall Chart Design

Top Chart

Volume Chart

Middle Chart

Bottom Chart

Source Code Listing

[The following project is available in "cppdemo/finance2".]
#include "chartdir.h" int main(int argc, char *argv[]) { //Create a finance chart demo containing 100 days of data int noOfDays = 100; //To compute moving averages, we need to get data points before the first //day int extraDays = 30; //We use a random table to simulate the data from a database. The random //table contains 6 cols x (noOfDays + extraDays) rows, using 9 as the seed. RanTable *rantable = new RanTable(9, 6, noOfDays + extraDays); //Set the 1st col to be the timeStamp, starting from Sep 4, 2002, with each //row representing one day, and counting week days only (jump over Sat and //Sun) rantable->setDateCol(0, chartTime(2002, 9, 4), 86400, true); //Set the 2nd, 3rd, 4th and 5th columns to be high, low, open and close //data. The open value starts from 1800, and the daily change is random from //-5 to 5. rantable->setHLOCCols(1, 1800, -5, 5); //Set the 6th column as the vol data from 50 to 250 rantable->setCol(5, 50, 250); //Now we read the data from the table into arrays DoubleArray timeStamps = rantable->getCol(0); DoubleArray highData = rantable->getCol(1); DoubleArray lowData = rantable->getCol(2); DoubleArray openData = rantable->getCol(3); DoubleArray closeData = rantable->getCol(4); DoubleArray volume = rantable->getCol(5); //To create the date labels for the x axis, we need to trim extraDays at the //beginning. Also, we select only the dates that represent the first date in //the month as labels. ArrayMath labels = ArrayMath(timeStamps).trim(extraDays).selectStartOfMonth( ); //Similarly, for the volume data, we need to trim extraDays at the beginning ArrayMath volData = ArrayMath(volume).trim(extraDays); //========================================================================== // Create the top chart //========================================================================== //Create a XYChart object of size 600 x 210 pixels XYChart *c = new XYChart(600, 210, Transparent); //Set the plotarea at (50, 20) and of size 500 x 180 pixels. Enable both the //horizontal and vertical grids by setting their colors to grey (0xc0c0c0) c->setPlotArea(50, 20, 500, 180)->setGridColor(0xc0c0c0, 0xc0c0c0); //Add a horizontal legend box at (50, 15) and set its border and background //colors to transparent c->addLegend(50, 15, false, "arial.ttf", 7.5)->setBackground(Transparent); //Add a candle stick layer using green/red (0xff00/0xff0000) for up/down //candles, and with data gap set to 0 to maximize the candle width. We need //to trim extraDays at the beginning as these days are just for computing //moving averages. c->addCandleStickLayer(ArrayMath(highData).trim(extraDays), ArrayMath( lowData).trim(extraDays), ArrayMath(openData).trim(extraDays), ArrayMath(closeData).trim(extraDays), 0xff00, 0xff0000)->setDataGap(0); //Add line layers representing 10 days and 20 days moving averages. c->addLineLayer(ArrayMath(closeData).movAvg(10).trim(extraDays), 0x663300, "Moving Average (10 days)"); c->addLineLayer(ArrayMath(closeData).movAvg(20).trim(extraDays), 0x9900ff, "Moving Average (20 days)"); //Donchian Channel is the zone between the maximum and minimum values in the //last 20 days ArrayMath upperBand = ArrayMath(highData).movMax(20).trim(extraDays); ArrayMath lowerBand = ArrayMath(lowData).movMin(20).trim(extraDays); //Add the upper and lower lines for the Donchian Channel LineLayer *uLayer = c->addLineLayer(upperBand, 0x9999ff, "Donchian Channel") ; LineLayer *lLayer = c->addLineLayer(lowerBand, 0x9999ff); //Color the region between the bollinger lines with semi-transparent blue c->addInterLineLayer(uLayer->getLine(), lLayer->getLine(), 0xc06666ff); //Add labels to the x axis formatted as mm/yyyy c->xAxis()->setLabels(labels, "{value|mm/yyyy}"); //For the top chart, the x axis is on top c->setXAxisOnTop(); //========================================================================== // Create the volume chart (the bottom part of the top chart) //========================================================================== //Create a XYChart object of size 600 x 80 pixels XYChart *c2 = new XYChart(600, 80, Transparent); //Set the plotarea at (50, 10) and of size 500 x 50) pixels. Set the //background, border and grid colors to transparent c2->setPlotArea(50, 10, 500, 50, Transparent, -1, Transparent, Transparent, Transparent); //Compute an array to represent the closing price changes ArrayMath closeChange = ArrayMath(closeData).delta().trim(extraDays); //Select the volume data for "up" days. An up day is a day where the closing //price is higher than the preivous day. Use the selected data for a green //bar layer. c2->addBarLayer(ArrayMath(volData).selectGTZ(closeChange), 0x99ff99, "Vol (Up days)")->setBorderColor(Transparent); //Select the volume data for "down" days. An up day is a day where the //closing price is lower than the preivous day. Use the selected data for a //red bar layer. c2->addBarLayer(ArrayMath(volData).selectLTZ(closeChange), 0xff9999, "Vol (Down days)")->setBorderColor(Transparent); //Select the volume data for days when closing prices are unchanged. Use the //selected data for a grey bar layer. c2->addBarLayer(ArrayMath(volData).selectEQZ(closeChange), 0xc0c0c0, "Vol (No change)")->setBorderColor(Transparent); //Set the primary y-axis on the right side c2->setYAxisOnRight(); //========================================================================== // Create the middle chart (MACD chart) //========================================================================== //Create a XYChart object of size 600 x 80 pixels XYChart *c3 = new XYChart(600, 80, Transparent); //Set the plotarea at (50, 10) and of size 500 x 50) pixels. Enable both the //horizontal and vertical grids by setting their colors to grey (0xc0c0c0) c3->setPlotArea(50, 10, 500, 50)->setGridColor(0xc0c0c0, 0xc0c0c0); //Add a horizontal legend box at (50, 5) and set its border and background //colors to transparent c3->addLegend(50, 5, false, "arial.ttf", 7.5)->setBackground(Transparent); //MACD is defined as the difference between 12 days and 26 days exponential //averages (decay factor = 0.15 and 0.075) ArrayMath expAvg26 = ArrayMath(closeData).expAvg(0.075); ArrayMath macd = ArrayMath(closeData).expAvg(0.15).sub(expAvg26); //Add the MACD line using blue (0xff) color c3->addLineLayer(ArrayMath(macd).trim(extraDays), 0xff, "MACD"); //MACD histogram is defined as the MACD minus its 9 days exponential average //(decay factor = 0.2) ArrayMath macd9 = ArrayMath(macd).expAvg(0.2); //Add the 9 days exponential average line using purple color (0xff00ff) c3->addLineLayer(ArrayMath(macd9).trim(extraDays), 0xff00ff); //Add MACD histogram as a bar layer using green color (0x8000). Set bar //border to transparent. c3->addBarLayer(ArrayMath(macd).sub(macd9).trim(extraDays), 0x8000, "MACD Histogram")->setBorderColor(Transparent); //Add labels to the x axis. We do not really need the label text, but we //need the grid line associated the labels c3->xAxis()->setLabels(labels); //We set the label and tick colors to transparent as we do not need them c3->xAxis()->setColors(LineColor, Transparent, Transparent, Transparent); //========================================================================== // Create the bottom chart (Stochastic chart) //========================================================================== //Create a XYChart object of size 600 x 120 pixels XYChart *c4 = new XYChart(600, 120, Transparent); //Set the plotarea at (50, 10) and of size 500 x 50) pixels. Enable both the //horizontal and vertical grids by setting their colors to grey (0xc0c0c0) c4->setPlotArea(50, 10, 500, 50)->setGridColor(0xc0c0c0, 0xc0c0c0); //Add a horizontal legend box at (50, 5) and set its border and background //colors to transparent c4->addLegend(50, 5, false, "arial.ttf", 7.5)->setBackground(Transparent); //Stochastic is defined as (close - moving_low) / (moving_high - moving_low) //x 100. We use 14 days as the period for moving computations. ArrayMath movLow = ArrayMath(lowData).movMin(14); ArrayMath movRange = ArrayMath(highData).movMax(14).sub(movLow); ArrayMath stochastic = ArrayMath(closeData).sub(movLow).div(movRange).mul( 100); //Traditional, for fast Stochastic chart, we draw both the Stochastic line //and its 3 days moving average c4->addLineLayer(ArrayMath(stochastic).trim(extraDays), 0x6060, "Stochastic (14)"); c4->addLineLayer(ArrayMath(stochastic).movAvg(3).trim(extraDays), 0x606000); //Set the y axis scale as 0 - 100, with ticks every 25 units c4->yAxis()->setLinearScale(0, 100, 25); //Add labels to the x axis formatted as mm/yyyy c4->xAxis()->setLabels(labels, "{value|mm/yyyy}"); //We need to explicitly set the indent mode axis. By default, line layers //are not indented, but we need it to be indented so the x axis will //synchronize with the top and middle charts c4->xAxis()->setIndent(true); //========================================================================== // Combine the charts together using a MultiChart //========================================================================== //Create a MultiChart object of size 600 x 400 pixels MultiChart *m = new MultiChart(600, 400); //Add a title to the chart m->addTitle("Finance Chart Demonstration"); //Add the 4 charts to the multi-chart m->addChart(0, 170, c2); m->addChart(0, 30, c); m->addChart(0, 235, c3); m->addChart(0, 300, c4); //output the chart m->makeChart("finance2.png"); //free up resources delete rantable; delete c; delete c2; delete c3; delete c4; delete m; return 0; }