|
How to track the value of extra indicator in FinanceChart |
Posted by James on Feb-07-2021 17:54 |
|
Hi,
I added an indicator chart to a FinanceChart by:
XYChart* c_youzi = c->addIndicator(75); //user indicator
and this chart works fine.
But I can't track the value of this indicator chart.
The tracking routine is here:
void CDongFang_Data_AnalyseView::trackFinance(MultiChart *m, int mouseX)
{
#if 1
// Clear the current dynamic layer and get the DrawArea object to draw on it.
DrawArea *d = m->initDynamicLayer();
// It is possible for a FinanceChart to be empty, so we need to check for it.
if (m->getChartCount() == 0)
return;
// Get the data x-value that is nearest to the mouse
int xValue = (int)(((XYChart *)m->getChart(0))->getNearestXValue(mouseX));
// Iterate the XY charts (main price chart and indicator charts) in the FinanceChart
XYChart *c = 0;
for (int i = 0; i < m->getChartCount(); ++i) {
c = (XYChart *)m->getChart(i);
// Variables to hold the legend entries
std::ostringstream ohlcLegend;
std::vector<std::string> legendEntries;
// Iterate through all layers to find the highest data point
for (int j = 0; j < c->getLayerCount(); ++j) {
Layer *layer = c->getLayerByZ(j);
int xIndex = layer->getXIndexOf(xValue);
int dataSetCount = layer->getDataSetCount();
// In a FinanceChart, only layers showing OHLC data can have 4 data sets
if (dataSetCount == 4) {
double highValue = layer->getDataSet(0)->getValue(xIndex);
double lowValue = layer->getDataSet(1)->getValue(xIndex);
double openValue = layer->getDataSet(2)->getValue(xIndex);
double closeValue = layer->getDataSet(3)->getValue(xIndex);
if (closeValue != Chart::NoValue) {
// Build the OHLC legend
ohlcLegend << " <*block*>";
ohlcLegend << "Open: " << c->formatValue(openValue, "{value|P4}");
ohlcLegend << ", High: " << c->formatValue(highValue, "{value|P4}");
ohlcLegend << ", Low: " << c->formatValue(lowValue, "{value|P4}");
ohlcLegend << ", Close: " << c->formatValue(closeValue, "{value|P4}");
// We also draw an upward or downward triangle for up and down days and the %
// change
double lastCloseValue = layer->getDataSet(3)->getValue(xIndex - 1);
if (lastCloseValue != Chart::NoValue) {
double change = closeValue - lastCloseValue;
double percent = change * 100 / closeValue;
std::string symbol = (change >= 0) ?
"<*font,color=990000*><*img=@triangle,width=8,color=990000*>" : //008800
"<*font,color=00cc00*><*img=@invertedtriangle,width=8,color=00CC00*>"; //cc0000
ohlcLegend << " " << symbol << " " << c->formatValue(change, "{value|P4}");
ohlcLegend << " (" << c->formatValue(percent, "{value|2}") << "%)<*/font*>";
}
ohlcLegend << "<*/*>";
}
}
else {
// Iterate through all the data sets in the layer
for (int k = 0; k < layer->getDataSetCount(); ++k) {
DataSet *dataSet = layer->getDataSetByZ(k);
std::string name = dataSet->getDataName();
double value = dataSet->getValue(xIndex);
if ((0 != name.size()) && (value != Chart::NoValue)) {
// In a FinanceChart, the data set name consists of the indicator name and its
// latest value. It is like "Vol: 123M" or "RSI (14): 55.34". As we are
// generating the values dynamically, we need to extract the indictor name
// out, and also the volume unit (if any).
// The volume unit
std::string unitChar;
// The indicator name is the part of the name up to the colon character.
int delimiterPosition = (int)name.find(':');
if (name.npos != delimiterPosition) {
// The unit, if any, is the trailing non-digit character(s).
int lastDigitPos = (int)name.find_last_of("0123456789");
if ((name.npos != lastDigitPos) && (lastDigitPos + 1 < (int)name.size()) &&
(lastDigitPos > delimiterPosition))
unitChar = name.substr(lastDigitPos + 1);
name.resize(delimiterPosition);
}
// In a FinanceChart, if there are two data sets, it must be representing a
// range.
if (dataSetCount == 2) {
// We show both values in the range in a single legend entry
value = layer->getDataSet(0)->getValue(xIndex);
double value2 = layer->getDataSet(1)->getValue(xIndex);
name = name + ": " + c->formatValue(min(value, value2), "{value|P3}");
name = name + " - " + c->formatValue(max(value, value2), "{value|P3}");
}
else { //james mod
// In a FinanceChart, only the layer for volume bars has 3 data sets for
// up/down/flat days
if (dataSetCount == 3) {
// The actual volume is the sum of the 3 data sets.
value = layer->getDataSet(0)->getValue(xIndex) + layer->getDataSet(1
)->getValue(xIndex) + layer->getDataSet(2)->getValue(xIndex);
}
// Create the legend entry
name = name + ": " + c->formatValue(value, "{value|P3}") + unitChar;
}
// Build the legend entry, consist of a colored square box and the name (with
// the data value in it).
std::ostringstream legendEntry;
legendEntry << "<*block*><*img=@square,width=8,edgeColor=000000,color="
<< std::hex << dataSet->getDataColor() << "*> " << name << "<*/*>";
legendEntries.push_back(legendEntry.str());
}
}
}
}
// Get the plot area position relative to the entire FinanceChart
PlotArea *plotArea = c->getPlotArea();
int plotAreaLeftX = plotArea->getLeftX() + c->getAbsOffsetX();
int plotAreaTopY = plotArea->getTopY() + c->getAbsOffsetY();
// The legend begins with the date label, then the ohlcLegend (if any), and then the
// entries for the indicators.
std::ostringstream legendText;
legendText << "<*block,valign=top,maxWidth=" << (plotArea->getWidth() - 5)
<< "*><*font=arialbd.ttf*>[" << c->xAxis()->getFormattedLabel(xValue, "mmm dd, yyyy")
<< "]<*/font*>" << ohlcLegend.str();
for (int i = ((int)legendEntries.size()) - 1; i >= 0; --i) {
legendText << " " << legendEntries[i];
}
legendText << "<*/*>";
// Draw a vertical track line at the x-position
d->vline(plotAreaTopY, plotAreaTopY + plotArea->getHeight(), c->getXCoor(xValue) +
c->getAbsOffsetX(), d->dashLineColor(0x000000, 0x0101));
// Display the legend on the top of the plot area
TTFText *t = d->text(legendText.str().c_str(), "arial.ttf", 8);
t->draw(plotAreaLeftX + 5, plotAreaTopY + 3, 0x000000, Chart::TopLeft);
t->destroy();
}
#endif
}
Where is the entrance to get my indicator's data ?
What's the meaning of '{value|P3}' P2, P4...?
Thanks
Regards
James
|
Re: How to track the value of extra indicator in FinanceChart |
Posted by James on Feb-08-2021 09:37 |
|
Dear All,
I've checked the sample code, there is a judge of dataset name:
std::string name = dataSet->getDataName();
double value = dataSet->getValue(xIndex);
if ((0 != name.size()) && (value != Chart::NoValue)) { <---- name.size()
//---------------------------------------
So, you should defined the dataset name at the time it is added in layer, like this:
// Add a bar chart layer using the given data
BarLayer *barYouzi = c_youzi->addBarLayer(DoubleArray(dyouzi, duration ),0xff00ff,"YouZi",0); //<------"Youzi" is the name of dataset
Now the legend box displays the value of my indicator
Regards
|
|