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

Message ListMessage List     Post MessagePost Message

  Once more a scrolling candlestick problem
Posted by Sinan on Feb-06-2011 10:10
Attachments:
First of all: wonderfull library! Very usefull and supporting all required features which I was searching for, so far.

Unfortunately I cannot find the solution for my problem in the distinct examples arround.
The problem is the Y-Axis in of a scrollable candlestick layer: It does not change (adopt) it's scale when scrolling ( see attached example ).
If the following is too much code, let me know - I can reduce if needed.
I wanted, that you can see (almost) the complete thing.
Btw. In this code both a line and a candlechart is shown, but I tried also candle alone.

I would be very glad if I could get your help.
Tanks in advance!!

ChartWindowDlg::drawChart(CChartViewer *viewer)
{
    // Get the line data
    int*    pTmpTimes = 0;
    double* pData  = 0;
    int nCount = (int)m_pDomain->getLst(&pTmpTimes, &pData );
    if( nCount == 0 )
    {
        return;
    }

    // get the time data for the line
    double* pTimes = new double[nCount];
    itod( pTimes, pTmpTimes, nCount ); // convert time_t to doubles
    delete [] pTmpTimes;

    // convert times to chartdirector times
    for( int i = 0; i < nCount; i++ )
    {
        struct tm ts;
        const time_t x = time_t(pTimes[i]);
        localtime_r(&x, &ts );
        pTimes[i] = Chart::chartTime(ts.tm_year + 1900,
                                     ts.tm_mon,
                                     ts.tm_mday,
                                     ts.tm_hour,
                                     ts.tm_min,
                                     ts.tm_sec);
    }

    // copied from examples
    double viewPortStartDate = m_lfMinDate +
                               (__int64)(viewer->getViewPortLeft() * m_lfDateRange + 0.5);
    double viewPortEndDate = viewPortStartDate +
                               (__int64)(viewer->getViewPortWidth() * m_lfDateRange + 0.5);

    // Get the starting index of the array using the start date ( from examples )
    int startIndex = (int)(std::lower_bound( pTimes,
                                                          pTimes + nCount,
                                                          viewPortStartDate) - pTimes);
    if ((startIndex > 0) && (pTimes[startIndex] != viewPortStartDate))
    {
        --startIndex;
    }

    // Get the ending index of the array using the end date
    int endIndex   = (int)(std::upper_bound( pTimes,
                                                           pTimes + nCount,
                                                           viewPortEndDate)   - pTimes );
    if (endIndex > nCount - 1 )
    {
        endIndex = nCount - 1;
    }

    // Get the length
    int noOfPoints = endIndex - startIndex + 1;
    double* viewPortTimeStamps = pTimes + startIndex;
    double* viewPortData = pData + startIndex;

    CRect clientRect;
    m_oChartViewer.GetClientRect(&clientRect);
    int nWidth = clientRect.Width();

    XYChart *c = new XYChart(clientRect.Width(),
                                          clientRect.Height(),
                                          0xa3c0b3,
                                          0x0000FF,
                                          1);

    // create the plot area
    c->setPlotArea( 50,
                          40,
                          clientRect.Width()-50,
                          clientRect.Height()-80,
                          Chart::Transparent,
                          -1,
                          -1,
                          0xcccccc,
                          0xcccccc);
    c->setClipping();

    // Display contract name
    std::string strTitle;
    m_pDomain->getContractDisplayName( strTitle );
    c->addTitle( strTitle.c_str(),
                      "timesbi.ttf",
                      10)->setBackground(0xCCCC99,
                                                  0x000000,
                                                  Chart::glassEffect());

    c->xAxis()->setTickDensity(50, 25);
    c->xAxis()->setWidth(2);
    c->yAxis()->setWidth(2);

    double lfFirstTime = pTimes[0];
    double lfLastTime = pTimes[nCount-1];

    // Set up the x-axis to show the time range in the data buffer
    c->xAxis()->setDateScale(lfFirstTime,  lfLastTime);

    // Set the x-axis label format
    c->xAxis()->setLabelFormat("{value|hh:nn}");

    // Create a line layer to plot the lines
    LineLayer *layer = c->addLineLayer();

    // BEGIN CANDLE ------------------
    double* open = 0;
    double* high = 0;
    double* low = 0;
    double* close = 0;
    double* pOhlcTimes = 0;
    int* pTmpOhlcTimes = 0;
    int nOhlcCount = (int)m_pDomain->getOhlc(&open,
                                                               &high,
                                                               &low,
                                                               &close,
                                                               &pTmpOhlcTimes );

    if( nOhlcCount > 0 )
    {
        // debug only: candle y-axis is shown in 2nd axis --> change plot area
        c->setPlotArea( 50, 40,
                        clientRect.Width()-110, clientRect.Height()-80,
                        Chart::Transparent, -1, -1, 0xcccccc, 0xcccccc);

        // transform candle times
        pOhlcTimes = new double[nOhlcCount];
        itod( pOhlcTimes, pTmpOhlcTimes, nOhlcCount );
        delete [] pTmpOhlcTimes;

        // build chart director times
        for( int i = 0; i < nOhlcCount; i++ )
        {
            struct tm ts;
            const time_t x = time_t(pOhlcTimes[i]);
            localtime_r(&x, &ts );
            pOhlcTimes[i] = Chart::chartTime(ts.tm_year + 1900,
                                             ts.tm_mon,
                                             ts.tm_mday,
                                             ts.tm_hour,
                                             ts.tm_min,
                                             ts.tm_sec);
        }

        CandleStickLayer *candle = 0;
        if( nOhlcCount > 2 )
        {
            candle =
                c->addCandleStickLayer(DoubleArray(high, nOhlcCount),
                                       DoubleArray(low, nOhlcCount),
                                       DoubleArray(open, nOhlcCount),
                                       DoubleArray(close, nOhlcCount),
                                       0x88ff88, 0xff8888);
            candle->setXData(DoubleArray(pOhlcTimes, nOhlcCount-1));
            candle->setUseYAxis2(true);
        }
    }
    // END CANDLE --------------------

    // The x-coordinates are the timeStamps.
    layer->setXData(DoubleArray(viewPortTimeStamps, noOfPoints));
    layer->addDataSet(DoubleArray(viewPortData, noOfPoints), 0x000088, "Test1");

    // Set x-axis date scale to the view port date range.
// ---> with this line, I did try lot's of ideas, none worked <---
    c->xAxis()->setDateScale(viewPortStartDate, viewPortEndDate);
    c->yAxis()->setAutoScale(0, 0);
    c->yAxis2()->setAutoScale(0, 0);
    // Set up y-axis scale
    if (viewer->getZoomDirection() == Chart::DirectionHorizontal)
    {
        // y-axis is auto-scaled - save the chosen y-axis scaled to support xy-zoom mode
        c->layout();
    }

    // Set the chart image to the WinChartViewer
    viewer->setChart(c);
candle_scroll.jpg

  Re: Once more a scrolling candlestick problem
Posted by Peter Kwan on Feb-07-2011 23:53
Hi Sinan,

From your code, is it true that the high, low, open, close and pOhlcTimes are always the same irrespective of where the chart has scrolled to? I am guessing this because it seems m_pDomain->getOhlc would not consider the current view port settings when retrieve the data.

If the candlestick always contains the same data, ChartDirector auto-scaling always pick the same scale for the candlestick layer. This is even if some of the candlesticks are not actually visible.

If the above is the cause of the problem, the solution is to pass only the data visible in the chart to candlestick layer. You may modify m_pDomain->getOhlc so that it only retrieves data within the viewPortStartDate and viewPortEndDate.

Hope this can help.

Regards
Peter Kwan

  Re: Once more a scrolling candlestick problem
Posted by Sinan on Feb-10-2011 01:21
Thank you!

You are right - Even if you didn't say it: it was a bug in my code :-(
I corrected it the same way as the previous start- and endindex calculations of the main array - and it worked! Sorry for having bothered - I will double(tripple) check before next post.

Sinan

  Re: Once more a scrolling candlestick problem
Posted by Sinan on Feb-10-2011 01:25
Thank you!

You are right - Even if you didn't say it: it was a bug in my code :-(
I corrected it the same way as the previous start- and endindex calculations of the main array - and it worked! Sorry for having bothered - I will double(tripple) check before next post.

Sinan