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

Message ListMessage List     Post MessagePost Message

  Finance Chart Indicator Labels
Posted by David on Aug-16-2013 05:46
Attachments:
Dear Peter,

I'm using VS Basic 2010 and CD 5.1.  I have added addRSI and addMACD and two SMA's, but the values don't display on the chart (see the yellow highlighted sections).

I am using trackFinance code with a few adjustments, see below:

    Private Sub trackFinance(m As MultiChart, mouseX As Integer, mouseY As Integer)
        ' Clear the current dynamic layer and get the DrawArea object to draw on it.
        Dim d As DrawArea = m.initDynamicLayer()

        ' It is possible for a FinanceChart to be empty, so we need to check for it.
        If m.getChartCount() = 0 Then
            Return
        End If

        ' Get the data x-value that is nearest to the mouse
        Dim xValue As Integer = CInt(Int(CType(m.getChart(0), XYChart).getNearestXValue(mouseX)))


        ' Iterate the XY charts (main price chart and indicator charts) in the FinanceChart
        Dim c As XYChart = Nothing
        For i As Integer = 0 To m.getChartCount() - 1
            c = CType(m.getChart(i), XYChart)

            ' Variables to hold the legend entries
            Dim ohlcLegend As String = ""
            Dim legendEntries As ArrayList = New ArrayList()

            ' Iterate through all layers to find the highest data point
            For j As Integer = 0 To c.getLayerCount() - 1
                Dim layer As Layer = c.getLayerByZ(j)
                Dim xIndex As Integer = layer.getXIndexOf(xValue)
                Dim dataSetCount As Integer = layer.getDataSetCount()

                ' In a FinanceChart, only layers showing OHLC data can have 4 data sets
                If dataSetCount = 4 Then
                    Dim highValue As Double = layer.getDataSet(0).getValue(xIndex)
                    Dim lowValue As Double = layer.getDataSet(1).getValue(xIndex)
                    Dim openValue As Double = layer.getDataSet(2).getValue(xIndex)
                    Dim closeValue As Double = layer.getDataSet(3).getValue(xIndex)

                    If closeValue <> Chart.NoValue Then
                        ' Build the OHLC legend
                        ohlcLegend = "Open: " & c.formatValue(openValue, "{value|P4}") & ", High: " & _
                            c.formatValue(highValue, "{value|P4}") & ", Low: " & c.formatValue(lowValue, _
                            "{value|P4}") & ", Close: " & c.formatValue(closeValue, "{value|P4}")

                        ' We also draw an upward or downward triangle for up and down days and the % change
                        Dim lastCloseValue As Double = layer.getDataSet(3).getValue(xIndex - 1)
                        If lastCloseValue <> Chart.NoValue Then
                            Dim change As Double = closeValue - lastCloseValue
                            Dim percent As Double = change * 100 / closeValue
                            Dim symbol As String = CStr(IIf(change >= 0, _
                                "<*font,color=008800*><*img=@triangle,width=8,color=008800*>", _
                                "<*font,color=CC0000*><*img=@invertedtriangle,width=8,color=CC0000*>"))

                            ohlcLegend = ohlcLegend & "  " & symbol & " " & c.formatValue(change, _
                                "{value|P4}") & " (" & c.formatValue(percent, "{value|2}") & "%)<*/font*>"
                        End If

                        ' Use a <*block*> to make sure the line does not wrap within the legend entry
                        ohlcLegend = "<*block*>" & ohlcLegend & "      <*/*>"
                    End If
                Else
                    ' Iterate through all the data sets in the layer
                    For k As Integer = 0 To layer.getDataSetCount() - 1
                        Dim dataSet As ChartDirector.DataSet = layer.getDataSetByZ(k)

                        Dim name As String = dataSet.getDataName()
                        Dim value As Double = dataSet.getValue(xIndex)
                        If (Not String.IsNullOrEmpty(name)) And (value <> Chart.NoValue) Then

                            ' 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 unit character, if any, is the last character and must not be a digit.
                            Dim unitChar As String = name.Substring(name.Length - 1)
                            If unitChar.CompareTo("0") >= 0 And unitChar.CompareTo("9") <= 0 Then
                                unitChar = ""
                            End If

                            ' The indicator name is the part of the name up to the colon character.
                            Dim delimiterPosition As Integer = name.IndexOf(":")
                            If delimiterPosition <> -1 Then
                                name = name.Substring(0, delimiterPosition)
                            End If

                            ' In a FinanceChart, if there are two data sets, it must be representing a range.
                            If dataSetCount = 2 Then
                                ' We show both values in the range in a single legend entry
                                value = layer.getDataSet(0).getValue(xIndex)
                                Dim value2 As Double = layer.getDataSet(1).getValue(xIndex)
                                name = name & ": " & c.formatValue(Math.Min(value, value2), "{value|P3}") & " - " & c.formatValue(Math.Max(value, value2), "{value|P3}")
                            Else
                                ' In a FinanceChart, only the layer for volume bars has 3 data sets for
                                ' up/down/flat days
                                If dataSetCount = 3 Then
                                    ' 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)
                                End If

                                ' Create the legend entry
                                name = name & " : " & c.formatValue(value, "{value|P3}") & unitChar
                            End If

                            ' Build the legend entry, consist of a colored square box and the name (with the
                            ' data value in it).
                            legendEntries.Add("<*block*><*img=@square,width=8,edgeColor=000000,color=" & Hex(dataSet.getDataColor()) & "*> " & name & "<*/*>")
                        End If
                    Next
                End If
            Next

            ' Get the plot area position relative to the entire FinanceChart
            Dim plotArea As PlotArea = c.getPlotArea()
            Dim plotAreaLeftX As Integer = plotArea.getLeftX() + c.getAbsOffsetX()
            Dim plotAreaTopY As Integer = plotArea.getTopY() + c.getAbsOffsetY()

            ' The legend is formed by concatenating the legend entries.
            legendEntries.Reverse()
            Dim legendText As String = Join(legendEntries.ToArray.ToString, "  ")

            ' Add the date and the ohlcLegend (if any) at the beginning of the legend
            legendText = "<*block,valign=top,maxWidth=" & (plotArea.getWidth() - 5) & "*><*font=Arial Bold*>[" & c.xAxis().getFormattedLabel(xValue, "mmm dd, yyyy") & "]<*/font*>      " & ohlcLegend & legendText

            ' Draw a vertical track line at the x-position
            d.vline(plotAreaTopY, plotAreaTopY + plotArea.getHeight(), c.getXCoor(xValue) + c.getAbsOffsetX(), d.dashLineColor(&H0, &H101))

            ' Display the legend on the top of the plot area
            Dim t As TTFText = d.text(legendText, "Arial", 8)
            t.draw(plotAreaLeftX + 5, plotAreaTopY + 3, &H0, Chart.TopLeft)

            ' The horizontal line for crosshair

            Dim topLimit As Double = plotArea.getTopY() + c.getAbsOffsetY()
            Dim bottomLimit As Double = plotArea.getBottomY() + c.getAbsOffsetY()
            If mouseY >= topLimit And mouseY <= bottomLimit Then

                d.hline(plotArea.getLeftX(), plotArea.getRightX(), mouseY, d.dashLineColor(&H0, &H101))

                ' Draw y-axis label
                Dim label As String = "<*block,bgColor=FFFFDD,margin=3,edgeColor=000000*>" & c.formatValue(c.getYValue(mouseY, c.yAxis()), "{value|P4}") & "<*/*>"
                Dim ta As TTFText = d.text(label, "Arial Bold", 8)
                'ta.draw(plotArea.getLeftX() - 5, mouseY, &H0, Chart.Right)
                ta.draw(plotArea.getRightX() + 40, mouseY, &H0, Chart.Right)

            End If

        Next

    End Sub
Capture.JPG

  Re: Finance Chart Indicator Labels
Posted by Peter Kwan on Aug-16-2013 23:10
Hi David,

In your code, I found the followings:

... = Join(legendEntries.ToArray.ToString, "  ")

In the original sample code, it is:

... = Join(CType(legendEntries.ToArray(GetType(String)), String()), "  ")

The two lines above have different meanings and are not the same. Is it possible to change
your code back to the sample code to see if it works?

Regards
Peter Kwan

  Re: Finance Chart Indicator Labels
Posted by David on Aug-17-2013 00:00
Hi Peter,

When I use...

Dim legendText as String = Join(Ctype(legendEntries.ToArray(GetType(String)),String()), " ")

I receive an Overload resolution failed because no accessible 'Join' can be called with these arguments:

'Public Shared Function Join(separator As String, values as System.Collections.Generic.IEnumberable(Of String)) as String': Value of type '1-dimensional array of String' cannot be converted to 'String'.

That's why I attempted to change it with the .toArray.toString code.

Any ideas?

  Re: Finance Chart Indicator Labels
Posted by Peter Kwan on Aug-17-2013 00:52
Hi David,

The Join function in the sample code is the standard Visual Basic Join function. See:

http://msdn.microsoft.com/en-us/library/hdxw14cw.aspx

The standard Visual Basic Join function expects the first parameter as a string array, and
the second parameter as a string. All standard Visual Basic functions are in the
Microsoft.VisualBasic namespace, which Visual Studio should automatically imported in a
Visual Basic project. (Has your Visual Basic project references "Microsoft.VisualBasic"?)

For your case, the error message means that the compiler is trying to use a different Join
function. Is it possible to find out where does this Join function come from? (Do you have
any documentation on the reported Join function? Have you imported some other library
that may have this function, or are your class derived from another class that may have
this function or have your class directly implemented this function?)

Like any other VB methods, if you have multiple methods of the same name, you may need
to specify the exact Join function to use. May be you can try:

Dim legendText as String =
Microsoft.VisualBasic.Strings.Join(Ctype(legendEntries.ToArray(GetType(String)),String()), "
")

Hope this can help.

Regards
Peter Kwan

  Re: Finance Chart Indicator Labels
Posted by David on Aug-17-2013 01:43
Hi Peter,

Thank you so much for your helpful information.  I am currently researching where the other "join" is originating.  I do have several imports and I am checking each one of them for a join function.  As well, I will check the libraries.

Additionally, when I added the Microsoft.VisualBasic.Strings to the join function, the results were perfect.

Thank you for all that you do to help us!
~David