ASE Home Page Products Download Purchase Support About ASE
ChartDirector Support
Forum HomeForum Home   SearchSearch

Message ListMessage List     Post MessagePost Message

  Candle timeline and zooming
Posted by Geoff Harris on Jan-04-2018 16:27
Attachments:
Hi

I realise that these will be FAQs but I'm not finding the answers I need. I'm trying to evaluate ChartDirector vs other options under pressure of time so would appreciate any help as there's a limit to how long I can realistically spend on this.

I'm using Java Swing on Windows for a native standalone app.

My data is typically around 500k OHLC bars with millisecond dates in Java.util.Date format.

I'm trying to set up a scrollable, zoomable Candlestick chart with viewport to display trades from backtests, but I've hit a couple of issues.

First, as I zoom in the bars are staying tiny and illegible. At max zoom they are basically flat lines. I'm adapting the "Zooming and Scrolling with Viewport Control (Windows)" example, which was set up for line plotting so there's clearly something carrying over that's not suitable for candlesticks.

Second, I use price and tick based bars, so I have an arbitrary number of bars per time period. But the chart is printing equal spaced per time period, and from what little I can see of the bars they are scrunched together and overlapping. Following the example I'm using layer.setXData(dateVals); for the X Axis.

It seems that these are frequent issues, but I can't find much help in the docs and a quick skim though the forum didn't turn up anything directly relevant to my scenario. So as I say, I'd very much appreciate some help.

I've enclosed my class, if you'd find it any help.
ChartDirectorChart.java
ChartDirectorChart.java

23.22 Kb

  Re: Candle timeline and zooming
Posted by Peter Kwan on Jan-04-2018 20:21
Hi Geoff,

Would you mind to clarify what are your data?

As you probably know, a OHLC bar contains 4 values - open, high, low, close. So each bar in general represent many trades over an interval. (If it is only one trade, there is only one price, and we would not need open/high/low/close.) The interval can be 1 day, 1 week, 1 hour, 15 minutes, etc.. All OHLC bar in a chart must use the same interval, otherwise they are not comparable and not consistent with other indicators (such as the moving average indicator). Within the trading hours, there should be an OHLC bar even if there is no trade, in which case the open/high/low/close are set to the same value as the previous close.

It is rare to find OHLC bars for short period (such as 1 millisecond). It is because it is very likely multiple trades will occur for every millisecond, so that OHLC bars are not useful. Most other technical indicators are not useful too if most of the milliseconds there are no trade.

You mentioned you have 500k "OHLC bars". Does it mean you have 500k prices, or does it really means you have 500k "OHLC bars"? If you have 500k OHLC bars, by definition each one bar must represent the same period (say 15 minute bar), but you mention that the Date has millisecond resolution. Does it mean you have 500k OHLC bars, each representing 1 millisecond, and the total time is there 500 seconds for the 500k bars? (Remember, each bar must represent the same interval.)

If what you mean is 500k prices, then it needs to be converted to open, high, low, close to plot the OHLC bar. To do this, you must provide a period for grouping the points into bars. Also, you must provide the trading hours, as it is impossible to determine the trading hours from the prices. (For some stocks, trading can be quite infrequent. So even when there is no trading, it can still be within the trading hours, and we still need to come up with an OHLC bar. As the trading hours cannot be inferred from the trading data, it must be given.)

In practice, normally, for intraday charts, people may choose 15 minute bars. Sometimes 5 minute or even 1 minute bars are used. For chart covering more than a few days to may be 2 years, the bar interval is usually 1 day. For longer duration, it is common to use weekly and then monthly bars.

ChartDirector allows you to aggregate the data differently based on different duration. So as you zoom out, you can switch the data group from 15 minutes to 1 day to 1 week, etc..

But first, to begin coding, we must understand what exactly are your data (is it 500k OHLC bars or 500k prices?), the trading hours (if it cannot be reliably inferred from the data) and the preferred bar interval.

Regards
Peter Kwan

  Re: Candle timeline and zooming
Posted by Geoff Harris on Jan-05-2018 00:01
Attachments:
Hi Peter

Thanks for getting back to quickly!

As I said, we use tick and price based OHLC bars such as Tick Bars, Renko and Heiken Ashi , and we use charts with up to 500k bars per year.

Perhaps you are not familiar with these chart types? The bars are formed after a certain number of ticks or after a certain range of price movement, so have no relation to regular time periods. In a fast moving market, there may be many bars a minute - in a slow moving market, only a few per hour. If you Google for Tick Bars and Renko Bars you'll find plenty of examples.

We use millisecond timestamps, because in fast markets the bars can be formed less than one second apart.

These bar types are less popular than time-based candles, but they are still used by millions of traders and are offered by most of the popular trading and charting platforms.

The problem I'm finding is that almost all the financial charting libraries have a hard-coded assumption that each bar in the time-series will be an equal space apart. I need what one developer calls a "Discontinuous Time Series" - ie a series where the space allocated on the X Axis adjusts depending on the number of bars, leaving each bar equally spaced. Ideally, the X Axis would also simply omit periods such as weekends where no bars are printed.

I was assuming with ChartDirector being so powerful that this would be doable?

I've enclosed a screenshot of a typical Renko chart to give you the idea of what we need to reproduce. Note how the time periods on the X Axis are not evenly spaced. Because the labels are long, the bars are not individually labelled - only a sample of bars have labels to get you oriented. But you can get the exact time for each bar by hovering with the crosshair.

So is there any way I can get this done in ChartDirector Java edition?

Thanks again

Geoff
RenkoExample.PNG

  Re: Candle timeline and zooming
Posted by Peter Kwan on Jan-05-2018 14:18
Hi Geoff,

ChartDirector certain meets you need. We have customers using ChartDirector plotting Renko charts.

ChartDirector also does not assume the bars are equally spaced in time. Even in normal financial charts, the bars are not equally spaced in time. For example, there are non-trading period (Sat and Sun, etc), and some stock exchange has lunch hours. In fact, you can use random numbers for the timestamps or not providing the timestamps at all, and the chart will still be plotted normally. (In ChartDirector financial chart, the timestamp are just for human reading, and are not used for the positioning of the bars.)

I will come up with a simple example for you. Please expect it within 1 day.

Regards
Peter Kwan

  Re: Candle timeline and zooming
Posted by Peter Kwan on Jan-05-2018 21:00
Attachments:
Hi Geoff,

I have just written a simple example for your reference. It is based on the "Zooming and Scrolling with Track Line (1)" sample code. In the code, I use random numbers to generate 500K bars, with the time spacing between bars being random.

For financial charts (including the renko chart), the x-coordinate is the "session number", not date/time. It is because date/time cannot be used to position the bars. For example, in a financial chart, the date/time can have gaps, such as non-trading days, but the bars must always be evenly spaced without gaps. This shows the date/time is not the x-coordinate. In the renko chart or normal financial chart, the date/time are just names for human reading.

You can see in the code, it uses the array index as the x-coordinate, not date/time. The chart will work even without the timestamps. In the code, it just add some timestamps as text labels to the x-axis, using the array index to position the labels.

One thing I am not sure is how would you like the bars to be drawn when fully zoomed out. It is not useful to display 500K bars on a chart only one or 2 thousand pixels wide. For each pixel, there will be dozens of bars overlapping, and what is visible is just the last layer of bars. In a normal candlestick chart, the standard practice is to aggregate the candlesticks (eg. aggregate 15 min candlesticks into daily and then weekly candlesticks), but for renko charts, I am not sure what is the standard method to handle aggregation.

Regards
Peter Kwan
renko.png
zoomscrolltrack.java
zoomscrolltrack.java

16.79 Kb

  Re: Candle timeline and zooming
Posted by Geoff on Jan-05-2018 23:42
Attachments:
Peter - brilliant service! I'll dig into this over the weekend.

As for the zooming out there are a couple of options.

I'm most familiar with Dukascopy's excellent JForex client, and what they do is simply set a sensible limit to the zoom out at a level where the individuals bars are just discernible and before you have to overlap them. I've posted a screenshot near their max zoom, and with this chart you are only seeing a couple of days of data.

This would be the easiest solution, I think. If I need more overview, I can simply switch to a bigger Renko bar or conventional candle.

The alternative would be to aggregate the Renko bars at specific zoom levels, but with a large data set I imagine this would involve a fair bit of coding and some potential lag? I'd have to loop through the data set and synthesise the new bars - I'm not sure it would be worth the hassle unless you have some clever library function to do this.

So I'd be happy with the limited zoom. Any tips about how to set this up would be very welcome. I can set the actual limit by trial and error, depending on screen resolution etc.

Geoff
RenkoZoomExample.PNG

  Re: Candle timeline and zooming
Posted by Peter Kwan on Jan-06-2018 00:35
Hi Geoff,

If you prefer to have a limit to the zoom out level, this can be set in ChartDirector using ChartViewer.setZoomOutWidthLimit. For example:

// Maximum zoom out level is 300 bars
chartViewer1.setZoomOutWidthLimit(300.0 / openData.length);

Hope this can help.

Regards
Peter Kwan

  Re: Candle timeline and zooming
Posted by Geoff Harris on Jan-06-2018 00:52
Peter

I have the demo running and it should hopefully be easy enough to port it over to my View Port code.

Actually, I don't really mind the way the bars mush together when you zoom out. It's really quite useful, as you can see big-picture details like market amplitude in a price-line type way. Wouldn't be good enough for a polished commercial product, but perfectly usable for my personal requirements.

I think I'm in good shape now.

So once again, many thanks for your timely responses. Do you never sleep? I thought you guys were in Hong Kong...

  Re: Candle timeline and zooming
Posted by Geoff Harris on Jan-06-2018 00:53
Peter

I have the demo running and it should hopefully be easy enough to port it over to my View Port code.

Actually, I don't really mind the way the bars mush together when you zoom out. It's really quite useful, as you can see big-picture details like market amplitude in a price-line type way. Wouldn't be good enough for a polished commercial product, but perfectly usable for my personal requirements.

I think I'm in good shape now.

So once again, many thanks for your timely responses. Do you never sleep? I thought you guys were in Hong Kong...

  Re: Candle timeline and zooming
Posted by Geoff Harris on Jan-07-2018 20:23
Peter

I now have a finance chart working with keyboard scrolling, mouse-wheel zooming and track line legend so I'm in business thanks to your kind assistance.

Just one detail to clear up.

Your suggestion for setting a max zoom level doesn't seem to work at all. I've tried a range of settings for the first param:

// Maximum zoom out level is 300 bars
chartViewer1.setZoomOutWidthLimit(300.0 / timeStamps.length);

This is a bit odd, as the min zoom is working fine:

// Set the maximum zoom in points
viewer.setZoomInWidthLimit(30.0 / timeStamps.length);

A max zoom would be nice to have, so I'd appreciate any suggestions. I'm using big data sets with lots of markup on the charts, so it does tend to barf if I try to zoom out to millions of data points. Setting a max zoom level is the elegant solution.

  Re: Candle timeline and zooming
Posted by Peter Kwan on Jan-08-2018 03:10
Hi Geoff,

I have tested myself and I found out the setZoomOutWidth Limit does not limit the zoom out by mouse wheel. It only limits the zoom out by mouse click (when the mouse usage mode is set to zoom out).

To work around, one common method to control zooming is to simply adjust the viewport in the ViewPortChanged event. If the viewport is changed to being too wide, just set it to a smaller value. An example is:

private double currentViewPortLeft = -1;
private double currentViewPortWidth = -1;

void chartViewer1_ViewPortChanged(ViewPortChangedEvent e)
{
    if ((currentViewPortLeft >= 0) && (chartViewer1.getViewPortWidth() > chartViewer1.getZoomOutWidthLimit())) {
        double excessRatio = (chartViewer1.getViewPortWidth() - chartViewer1.getZoomOutWidthLimit()) / Math.max(1E-7, (chartViewer1.getViewPortWidth() - currentViewPortWidth));
        chartViewer1.setViewPortLeft(chartViewer1.getViewPortLeft() * (1 - excessRatio) + currentViewPortLeft * excessRatio);
        chartViewer1.setViewPortWidth(chartViewer1.getZoomOutWidthLimit());
    }
    currentViewPortLeft = chartViewer1.getViewPortLeft();
    currentViewPortWidth = chartViewer1.getViewPortWidth();

    // In addition to updating the chart, we may also need to update other controls that
    // changes based on the view port.
    updateControls(chartViewer1);

    // Update the chart if necessary
    if (e.needUpdateChart())
        drawChart(chartViewer1);
}

In the above code, if the viewport is wider than the zoom out width limit, it simply adjusts it back to the zoom out width limit.

Hope this can help.

Regards
Peter Kwan

  Re: Candle timeline and zooming
Posted by Geoff Harris on Jan-08-2018 21:24
Thanks Peter, the Zoom fix seems to work nicely with the mouse wheel zoom. I would never have been able to figure that out myself...

I thought I was done, but have run into what I hope is a final issue.

I've added moving averages to the main finance chart, and so I've implemented the lookback period with extraDays = x for the slowest MA.

The problem is with the track line legend. Now, when I hover a bar, the legend is showing the data from the bar extraDays back, not for the bar under the track line. The code is taken pretty directly from your examples, and I'm not clear how to fix this.

I'm passing the lookback into the chart like this:

>>>>>
c.setData(viewPortTimeStamps, viewPortHighData, viewPortLowData, viewPortOpenData,
                viewPortCloseData, viewPortVolData, extraDays);
>>>>>

And I'm drawing the track line like this:

>>>>>
  /**
     * Draw the track line with legend
     */
    private void trackLineLegend(MultiChart m, int mouseX) {

        // Clear the current dynamic layer and get the DrawArea object to draw on it.
        DrawArea d = m.initDynamicLayer();
        XYChart c = (XYChart) m.getChart();

        // It is possible for a FinanceChart to be empty, so we need to check for it.
        if (m.getChartCount() == 0) {
            return;
        }

        // The plot area object
        PlotArea plotArea = c.getPlotArea();

        // Get the data x-value that is nearest to the mouse, and find its pixel coordinate.
        double xValue = c.getNearestXValue(mouseX);
        int xCoor = c.getXCoor(xValue);

        // Get the plot area position relative to the entire FinanceChart

        // int plotAreaLeftX = plotArea.getLeftX() + c.getAbsOffsetX();
        int plotAreaTopY = plotArea.getTopY() + c.getAbsOffsetY();

        // Draw a vertical track line at the x-position
        d.vline(plotAreaTopY, plotAreaTopY + plotArea.getHeight(), c.getXCoor(xValue) + c.getAbsOffsetX(),
                d.dashLineColor(0x000000, 0x0101));

        // Get the time label
        int index = (int) Math.round(chartViewer.getValueAtViewPort("x", chartViewer.getViewPortLeft()) + 0.49999) + (int) xValue;
        String timeLabel = c.formatValue(timeStamps[index], "yyyy-mm-dd hh:nn:ss.fff");

        // Draw time label at the x-axis
        TTFText t = d.text("<*font,bgColor=000000*> " + timeLabel + " <*/font*>", "Arial Bold", 8);
        t.draw(Math.max(t.getWidth() / 2, Math.min(c.getWidth() - t.getWidth() / 2, xCoor)), plotArea.getBottomY() + 1, 0xffffff, Chart.Top);

        // Display the legend on the top of the plot area
        String symbol = ((openData[index] <= closeData[index]) ?
                "<*font,color=008800*><*img=@triangle,width=8,color=008800*>" :
                "<*font,color=CC0000*><*img=@invertedtriangle,width=8,color=CC0000*>");
        java.text.DecimalFormat formatter = new java.text.DecimalFormat(formatPattern);
        String legendText = "[" + timeLabel + "] " + symbol + " " + formatter.format(openData[index])
                + " to " + formatter.format(closeData[index]);
        t = d.text(legendText, "Arial", 8);
        t.draw(plotArea.getLeftX() + 5, plotArea.getTopY() - 30, 0x000000);
    }
>>>>>

PS, is there markup in your forum for code examples?


Thanks

  Re: Candle timeline and zooming
Posted by Peter Kwan on Jan-09-2018 14:16
Hi Geoff,

I think you would need to adjust the index with the extraDays too, like:

int index = (int) Math.round(chartViewer.getValueAtViewPort("x", chartViewer.getViewPortLeft()) + 0.49999) + (int) xValue + extraDays;

(It means you may need to save the extraDays into a member variable so that it is accessible from the trackLineLegend code.)

Hope this can help.

Regards
Peter Kwan

  Re: Candle timeline and zooming
Posted by Geoff Harris on Jan-10-2018 20:30
Thanks Peter - that did the trick!