TransWar File Browser

Path: C:\

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
  Persistable = 0  'NotPersistable
  DataBindingBehavior = 0  'vbNone
  DataSourceBehavior  = 0  'vbNone
  MTSTransactionMode  = 0  'NotAnMTSObject
END
Attribute VB_Name = "FinanceChart"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True
Option Explicit

'/////////////////////////////////////////////////////////////////////////////////////////////////
' Copyright 2012 Advanced Software Engineering Limited
'
' ChartDirector FinanceChart class library
'     - Requires ChartDirector Ver 5.1 or above
'
' You may use and modify the code in this file in your application, provided the code and
' its modifications are used only in conjunction with ChartDirector. Usage of this software
' is subjected to the terms and condition of the ChartDirector license.
'/////////////////////////////////////////////////////////////////////////////////////////////////

'/ <summary>
'/ Represents a Financial Chart
'/ </summary>

Private cd As Object
Private base As Object
Private m_totalWidth As Long
Private m_totalHeight As Long
Private m_antiAlias As Boolean
Private m_logScale As Boolean
Private m_axisOnRight As Boolean
Private m_leftMargin As Long
Private m_rightMargin As Long
Private m_topMargin As Long
Private m_bottomMargin As Long
Private m_plotAreaBgColor As Long
Private m_plotAreaBorder As Long
Private m_plotAreaGap As Long
Private m_majorHGridColor As Long
Private m_minorHGridColor As Long
Private m_majorVGridColor As Long
Private m_minorVGridColor As Long
Private m_legendFont As String
Private m_legendFontSize As Double
Private m_legendFontColor As Long
Private m_legendBgColor As Long
Private m_yAxisFont As String
Private m_yAxisFontSize As Double
Private m_yAxisFontColor As Long
Private m_yAxisMargin As Long
Private m_xAxisFont As String
Private m_xAxisFontSize As Double
Private m_xAxisFontColor As Long
Private m_xAxisFontAngle As Double
Private m_timeStamps()
Private m_highData()
Private m_lowData()
Private m_openData()
Private m_closeData()
Private m_volData()
Private m_volUnit As String
Private m_extraPoints As Long
Private m_yearFormat As String
Private m_firstMonthFormat As String
Private m_otherMonthFormat As String
Private m_firstDayFormat As String
Private m_otherDayFormat As String
Private m_firstHourFormat As String
Private m_otherHourFormat As String
Private m_timeLabelSpacing As Long
Private m_generalFormat As String
Private m_toolTipMonthFormat As String
Private m_toolTipDayFormat As String
Private m_toolTipHourFormat As String
Private m_mainChart As Object
Private m_currentChart As Object

Private Sub InitializeMembers()
    m_totalWidth = 0
    m_totalHeight = 0
    m_antiAlias = True
    m_logScale = False
    m_axisOnRight = True

    m_leftMargin = 40
    m_rightMargin = 40
    m_topMargin = 30
    m_bottomMargin = 30

    m_plotAreaBgColor = &Hffffff
    m_plotAreaBorder = &H888888
    m_plotAreaGap = 2

    m_majorHGridColor = &Hdddddd
    m_minorHGridColor = &Hdddddd
    m_majorVGridColor = &Hdddddd
    m_minorVGridColor = &Hdddddd

    m_legendFont = "normal"
    m_legendFontSize = 8
    m_legendFontColor = cd.TextColor
    m_legendBgColor = &H80cccccc

    m_yAxisFont = "normal"
    m_yAxisFontSize = 8
    m_yAxisFontColor = cd.TextColor
    m_yAxisMargin = 14

    m_xAxisFont = "normal"
    m_xAxisFontSize = 8
    m_xAxisFontColor = cd.TextColor
    m_xAxisFontAngle = 0

    m_timeStamps = Array()
    m_highData = Array()
    m_lowData = Array()
    m_openData = Array()
    m_closeData = Array()
    m_volData = Array()
    m_volUnit = ""
    m_extraPoints = 0

    m_yearFormat = "{value|yyyy}"
    m_firstMonthFormat = "<*font=bold*>{value|mmm yy}"
    m_otherMonthFormat = "{value|mmm}"
    m_firstDayFormat = "<*font=bold*>{value|d mmm}"
    m_otherDayFormat = "{value|d}"
    m_firstHourFormat = "<*font=bold*>{value|d mmm<*br*>h:nna}"
    m_otherHourFormat = "{value|h:nna}"
    m_timeLabelSpacing = 50

    m_generalFormat = "P3"

    m_toolTipMonthFormat = "[{xLabel|mmm yyyy}]"
    m_toolTipDayFormat = "[{xLabel|mmm d, yyyy}]"
    m_toolTipHourFormat = "[{xLabel|mmm d, yyyy hh:nn:ss}]"

    Set m_mainChart = Nothing
    Set m_currentChart = Nothing
End Sub

'/ <summary>
'/ Create a FinanceChart with a given width. The height will be automatically determined
'/ as the chart is built.
'/ </summary>
'/ <param name="width">Width of the chart in pixels</param>
Public Function Init(myAPI, width)
    Set cd = myAPI
    Set base = cd.MultiChart(width, 1)
    InitializeMembers
    m_totalWidth = width
    Call setMainChart(Base)
    Set Init = Me
End Function

'/ <summary>
'/ Enable/Disable anti-alias. Enabling anti-alias makes the line smoother. Disabling
'/ anti-alias make the chart file size smaller, and so can be downloaded faster
'/ through the Internet. The default is to enable anti-alias.
'/ </summary>
'/ <param name="antiAlias">True to enable anti-alias. False to disable anti-alias.</param>
Public Sub enableAntiAlias(antiAlias)
    m_antiAlias = antiAlias
End Sub

'/ <summary>
'/ Set the margins around the plot area.
'/ </summary>
'/ <param name="m_leftMargin">The distance between the plot area and the chart left edge.</param>
'/ <param name="m_topMargin">The distance between the plot area and the chart top edge.</param>
'/ <param name="m_rightMargin">The distance between the plot area and the chart right edge.</param>
'/ <param name="m_bottomMargin">The distance between the plot area and the chart bottom edge.</param>
Public Sub setMargins(leftMargin, topMargin, rightMargin, bottomMargin)
    m_leftMargin = leftMargin
    m_rightMargin = rightMargin
    m_topMargin = topMargin
    m_bottomMargin = bottomMargin
End Sub

'/ <summary>
'/ Add a text title above the plot area. You may add multiple title above the plot area by
'/ calling this method multiple times.
'/ </summary>
'/ <param name="alignment">The alignment with respect to the region that is on top of the
'/ plot area.</param>
'/ <param name="text">The text to add.</param>
'/ <returns>The TextBox object representing the text box above the plot area.</returns>
Public Function addPlotAreaTitle(alignment, text)
    Dim ret As Object
    Set ret = addText(m_leftMargin, 0, text, "bold", 10, cd.TextColor, alignment)
    Call ret.setSize(m_totalWidth - m_leftMargin - m_rightMargin + 1, m_topMargin - 1)
    Call ret.setMargin(0)
    Set addPlotAreaTitle = ret
    Exit Function
End Function

'/ <summary>
'/ Set the plot area style. The default is to use pale yellow 0xfffff0 as the background,
'/ and light grey 0xdddddd as the grid lines.
'/ </summary>
'/ <param name="bgColor">The plot area background color.</param>
'/ <param name="majorHGridColor">Major horizontal grid color.</param>
'/ <param name="majorVGridColor">Major vertical grid color.</param>
'/ <param name="minorHGridColor">Minor horizontal grid color. In current version, minor
'/ horizontal grid is not used.</param>
'/ <param name="minorVGridColor">Minor vertical grid color.</param>
Public Sub setPlotAreaStyle(bgColor, majorHGridColor, majorVGridColor, minorHGridColor, _
    minorVGridColor)
    m_plotAreaBgColor = bgColor
    m_majorHGridColor = majorHGridColor
    m_majorVGridColor = majorVGridColor
    m_minorHGridColor = minorHGridColor
    m_minorVGridColor = minorVGridColor
End Sub

'/ <summary>
'/ Set the plot area border style. The default is grey color (888888), with a gap
'/ of 2 pixels between charts.
'/ </summary>
'/ <param name="borderColor">The color of the border.</param>
'/ <param name="borderGap">The gap between two charts.</param>
Public Sub setPlotAreaBorder(borderColor, borderGap)
    m_plotAreaBorder = borderColor
    m_plotAreaGap = borderGap
End Sub

'/ <summary>
'/ Set legend style. The default is Arial 8 pt black color, with light grey background.
'/ </summary>
'/ <param name="font">The font of the legend text.</param>
'/ <param name="fontSize">The font size of the legend text in points.</param>
'/ <param name="fontColor">The color of the legend text.</param>
'/ <param name="bgColor">The background color of the legend box.</param>
Public Sub setLegendStyle(font, fontSize, fontColor, bgColor)
    m_legendFont = font
    m_legendFontSize = fontSize
    m_legendFontColor = fontColor
    m_legendBgColor = bgColor
End Sub

'/ <summary>
'/ Set x-axis label style. The default is Arial 8 pt black color no rotation.
'/ </summary>
'/ <param name="font">The font of the axis labels.</param>
'/ <param name="fontSize">The font size of the axis labels in points.</param>
'/ <param name="fontColor">The color of the axis labels.</param>
'/ <param name="fontAngle">The rotation of the axis labels.</param>
Public Sub setXAxisStyle(font, fontSize, fontColor, fontAngle)
    m_xAxisFont = font
    m_xAxisFontSize = fontSize
    m_xAxisFontColor = fontColor
    m_xAxisFontAngle = fontAngle
End Sub

'/ <summary>
'/ Set y-axis label style. The default is Arial 8 pt black color, with 13 pixels margin.
'/ </summary>
'/ <param name="font">The font of the axis labels.</param>
'/ <param name="fontSize">The font size of the axis labels in points.</param>
'/ <param name="fontColor">The color of the axis labels.</param>
'/ <param name="axisMargin">The margin at the top of the y-axis in pixels (to leave
'/ space for the legend box).</param>
Public Sub setYAxisStyle(font, fontSize, fontColor, axisMargin)
    m_yAxisFont = font
    m_yAxisFontSize = fontSize
    m_yAxisFontColor = fontColor
    m_yAxisMargin = axisMargin
End Sub

'/ <summary>
'/ Set whether the main y-axis is on right of left side of the plot area. The default is
'/ on right.
'/ </summary>
'/ <param name="b">True if the y-axis is on right. False if the y-axis is on left.</param>
Public Sub setAxisOnRight(b)
    m_axisOnRight = b
End Sub

'/ <summary>
'/ Determines if log scale should be used for the main chart. The default is linear scale.
'/ </summary>
'/ <param name="b">True for using log scale. False for using linear scale.</param>
Public Sub setLogScale(b)
    m_logScale = b
    If Not m_mainChart Is Nothing Then
        If m_logScale Then
            Call m_mainChart.yAxis().setLogScale()
        Else
            Call m_mainChart.yAxis().setLinearScale()
        End If
    End If
End Sub

'/ <summary>
'/ Set the date/time formats to use for the x-axis labels under various cases.
'/ </summary>
'/ <param name="yearFormat">The format for displaying labels on an axis with yearly ticks. The
'/ default is "yyyy".</param>
'/ <param name="firstMonthFormat">The format for displaying labels on an axis with monthly ticks.
'/ This parameter applies to the first available month of a year (usually January) only, so it can
'/ be formatted differently from the other labels.</param>
'/ <param name="otherMonthFormat">The format for displaying labels on an axis with monthly ticks.
'/ This parameter applies to months other than the first available month of a year.</param>
'/ <param name="firstDayFormat">The format for displaying labels on an axis with daily ticks.
'/ This parameter applies to the first available day of a month only, so it can be formatted
'/ differently from the other labels.</param>
'/ <param name="otherDayFormat">The format for displaying labels on an axis with daily ticks.
'/ This parameter applies to days other than the first available day of a month.</param>
'/ <param name="firstHourFormat">The format for displaying labels on an axis with hourly
'/ resolution. This parameter applies to the first tick of a day only, so it can be formatted
'/ differently from the other labels.</param>
'/ <param name="otherHourFormat">The format for displaying labels on an axis with hourly.
'/ resolution. This parameter applies to ticks at hourly boundaries, except the first tick
'/ of a day.</param>
Public Sub setDateLabelFormat(yearFormat, firstMonthFormat, otherMonthFormat, firstDayFormat, _
    otherDayFormat, firstHourFormat, otherHourFormat)
    If yearFormat <> "" Then
        m_yearFormat = yearFormat
    End If
    If firstMonthFormat <> "" Then
        m_firstMonthFormat = firstMonthFormat
    End If
    If otherMonthFormat <> "" Then
        m_otherMonthFormat = otherMonthFormat
    End If
    If firstDayFormat <> "" Then
        m_firstDayFormat = firstDayFormat
    End If
    If otherDayFormat <> "" Then
        m_otherDayFormat = otherDayFormat
    End If
    If firstHourFormat <> "" Then
        m_firstHourFormat = firstHourFormat
    End If
    If otherHourFormat <> "" Then
        m_otherHourFormat = otherHourFormat
    End If
End Sub

'/ <summary>
'/ Set the minimum label spacing between two labels on the time axis
'/ </summary>
'/ <param name="labelSpacing">The minimum label spacing in pixels.</param>
Public Sub setDateLabelSpacing(labelSpacing)
    If labelSpacing > 0 Then
        m_timeLabelSpacing = labelSpacing
    Else
         m_timeLabelSpacing = 0
    End If
End Sub

'/ <summary>
'/ Set the tool tip formats for display date/time
'/ </summary>
'/ <param name="monthFormat">The tool tip format to use if the data point spacing is one
'/ or more months (more than 30 days).</param>
'/ <param name="dayFormat">The tool tip format to use if the data point spacing is 1 day
'/ to less than 30 days.</param>
'/ <param name="hourFormat">The tool tip format to use if the data point spacing is less
'/ than 1 day.</param>
Public Sub setToolTipDateFormat(monthFormat, dayFormat, hourFormat)
    If monthFormat <> "" Then
        m_toolTipMonthFormat = monthFormat
    End If
    If dayFormat <> "" Then
        m_toolTipDayFormat = dayFormat
    End If
    If hourFormat <> "" Then
        m_toolTipHourFormat = hourFormat
    End If
End Sub

'/ <summary>
'/ Get the tool tip format for display date/time
'/ </summary>
'/ <returns>The tool tip format string.</returns>
Public Function getToolTipDateFormat()
    If UBound(m_timeStamps) < 0 Then
        getToolTipDateFormat = m_toolTipHourFormat
        Exit Function
    End If
    If UBound(m_timeStamps) + 1 <= m_extraPoints Then
        getToolTipDateFormat = m_toolTipHourFormat
        Exit Function
    End If
    Dim resolution As Double
    resolution = (m_timeStamps(UBound(m_timeStamps)) - m_timeStamps(0)) / (UBound(m_timeStamps) +1)
    If resolution >= 30 * 86400 Then
        getToolTipDateFormat = m_toolTipMonthFormat
        Exit Function
    ElseIf resolution >= 86400 Then
        getToolTipDateFormat = m_toolTipDayFormat
        Exit Function
    Else
        getToolTipDateFormat = m_toolTipHourFormat
        Exit Function
    End If
End Function

'/ <summary>
'/ Set the number format for use in displaying values in legend keys and tool tips.
'/ </summary>
'/ <param name="formatString">The default number format.</param>
Public Sub setNumberLabelFormat(formatString)
    If formatString <> "" Then
        m_generalFormat = formatString
    End If
End Sub

'/ <summary>
'/ A utility function to compute triangular moving averages
'/ </summary>
'/ <param name="data">An array of numbers as input.</param>
'/ <param name="period">The moving average period.</param>
'/ <returns>An array representing the triangular moving average of the input array.</returns>
Private Function computeTriMovingAvg(data, period)
    Dim p As Long
    p = period / 2 + 1
    computeTriMovingAvg = cd.ArrayMath(data).movAvg(p).movAvg(p).result()
    Exit Function
End Function

'/ <summary>
'/ A utility function to compute weighted moving averages
'/ </summary>
'/ <param name="data">An array of numbers as input.</param>
'/ <param name="period">The moving average period.</param>
'/ <returns>An array representing the weighted moving average of the input array.</returns>
Private Function computeWeightedMovingAvg(data, period)
    Dim acc As Object
    Set acc = cd.ArrayMath(data)
    Dim i As Long
    For i = 2 To period
        Call acc.add(cd.ArrayMath(data).movAvg(i).mul(i).result())
    Next
    computeWeightedMovingAvg = acc.div((1 + period) * period / 2).result()
    Exit Function
End Function

'/ <summary>
'/ A utility function to obtain the first visible closing price.
'/ </summary>
'/ <returns>The first closing price.
'/ are cd.NoValue.</returns>
Private Function firstCloseValue()
    Dim i As Long
    For i = m_extraPoints To UBound(m_closeData)
        If (m_closeData(i) <> cd.NoValue) And (m_closeData(i) <> 0) Then
            firstCloseValue = m_closeData(i)
            Exit Function
        End If
    Next
    firstCloseValue = cd.NoValue
    Exit Function
End Function

'/ <summary>
'/ A utility function to obtain the last valid position (that is, position not
'/ containing cd.NoValue) of a data series.
'/ </summary>
'/ <param name="data">An array of numbers as input.</param>
'/ <returns>The last valid position in the input array, or -1 if all positions
'/ are cd.NoValue.</returns>
Private Function lastIndex(data)
    Dim i As Long
    i = UBound(data)
    Do While i >= 0
        If data(i) <> cd.NoValue Then
            Exit Do
        End If
        i = i - 1
    Loop
    lastIndex = i
    Exit Function
End Function

'/ <summary>
'/ Set the data used in the chart. If some of the data are not available, some artifical
'/ values should be used. For example, if the high and low values are not available, you
'/ may use closeData as highData and lowData.
'/ </summary>
'/ <param name="timeStamps">An array of dates/times for the time intervals.</param>
'/ <param name="highData">The high values in the time intervals.</param>
'/ <param name="lowData">The low values in the time intervals.</param>
'/ <param name="openData">The open values in the time intervals.</param>
'/ <param name="closeData">The close values in the time intervals.</param>
'/ <param name="volData">The volume values in the time intervals.</param>
'/ <param name="extraPoints">The number of leading time intervals that are not
'/ displayed in the chart. These intervals are typically used for computing
'/ indicators that require extra leading data, such as moving averages.</param>
Public Sub setData(timeStamps, highData, lowData, openData, closeData, volData, extraPoints)
    m_timeStamps = cd.CTime(timeStamps)
    m_highData = highData
    m_lowData = lowData
    m_openData = openData
    m_closeData = closeData
    If extraPoints > 0 Then
        m_extraPoints = extraPoints
    Else
        m_extraPoints = 0
    End If

    '///////////////////////////////////////////////////////////////////////
    ' Auto-detect volume units
    '///////////////////////////////////////////////////////////////////////
    Dim maxVol As Double
    maxVol = cd.ArrayMath(volData).max()
    Dim units()
    units = Array("", "K", "M", "B")
    Dim unitIndex As Long
    unitIndex = UBound(units)
    Do While (unitIndex > 0) And (maxVol < 1000 ^ unitIndex)
        unitIndex = unitIndex - 1
    Loop

    m_volData = cd.ArrayMath(volData).div(1000 ^ unitIndex).result()
    m_volUnit = units(unitIndex)
End Sub

'////////////////////////////////////////////////////////////////////////////
' Format x-axis labels
'////////////////////////////////////////////////////////////////////////////
Private Sub setXLabels(a)
    Call a.setLabels2(m_timeStamps)
    If m_extraPoints < UBound(m_timeStamps) + 1 Then
        Dim tickStep As Long
        tickStep = Int((UBound(m_timeStamps) + 1 - m_extraPoints) * m_timeLabelSpacing / ( _
            m_totalWidth - m_leftMargin - m_rightMargin)) + 1
        Dim timeRangeInSeconds As Double
        timeRangeInSeconds = m_timeStamps(UBound(m_timeStamps)) - m_timeStamps(m_extraPoints)
        Dim secondsBetweenTicks As Double
        secondsBetweenTicks = timeRangeInSeconds / (m_totalWidth - m_leftMargin - m_rightMargin) * _
            m_timeLabelSpacing

        If secondsBetweenTicks * (UBound(m_timeStamps) + 1 - m_extraPoints) <= timeRangeInSeconds _
             Then
            tickStep = 1
            If UBound(m_timeStamps) + 1 > 1 Then
                secondsBetweenTicks = m_timeStamps(UBound(m_timeStamps)) - m_timeStamps( _
                    UBound(m_timeStamps) + 1 - 2)
            Else
                secondsBetweenTicks = 86400
            End If
        End If

        If (secondsBetweenTicks > 360 * 86400) Or ((secondsBetweenTicks > 90 * 86400) And ( _
            timeRangeInSeconds >= 720 * 86400)) Then
            'yearly ticks
            Call a.setMultiFormat2(cd.StartOfYearFilter(), m_yearFormat, tickStep)
        ElseIf (secondsBetweenTicks >= 30 * 86400) Or ((secondsBetweenTicks > 7 * 86400) And ( _
            timeRangeInSeconds >= 60 * 86400)) Then
            'monthly ticks
            Dim monthBetweenTicks As Long
            monthBetweenTicks = Int(secondsBetweenTicks / 31 / 86400) + 1
            Call a.setMultiFormat(cd.StartOfYearFilter(), m_firstMonthFormat, _
                cd.StartOfMonthFilter(monthBetweenTicks), m_otherMonthFormat)
            Call a.setMultiFormat2(cd.StartOfMonthFilter(), "-", 1, False)
        ElseIf (secondsBetweenTicks >= 86400) Or ((secondsBetweenTicks > 6 * 3600) And ( _
            timeRangeInSeconds >= 86400)) Then
            'daily ticks
            Call a.setMultiFormat(cd.StartOfMonthFilter(), m_firstDayFormat, cd.StartOfDayFilter( _
                1, 0.5), m_otherDayFormat, tickStep)
        Else
            'hourly ticks
            Call a.setMultiFormat(cd.StartOfDayFilter(1, 0.5), m_firstHourFormat, _
                cd.StartOfHourFilter(1, 0.5), m_otherHourFormat, tickStep)
        End If
    End If
End Sub

'////////////////////////////////////////////////////////////////////////////
' Create tool tip format string for showing OHLC data
'////////////////////////////////////////////////////////////////////////////
Private Function getHLOCToolTipFormat()
    getHLOCToolTipFormat = "title='" & getToolTipDateFormat() & " Op:{open|" & m_generalFormat & _
        "}, Hi:{high|" & m_generalFormat & "}, Lo:{low|" & m_generalFormat & "}, Cl:{close|" & _
        m_generalFormat & "}'"
    Exit Function
End Function

'/ <summary>
'/ Add the main chart - the chart that shows the HLOC data.
'/ </summary>
'/ <param name="height">The height of the main chart in pixels.</param>
'/ <returns>An XYChart object representing the main chart created.</returns>
Public Function addMainChart(height)
    Set m_mainChart = addIndicator(height)
    Call m_mainChart.yAxis().setMargin(2 * m_yAxisMargin)
    If m_logScale Then
        Call m_mainChart.yAxis().setLogScale()
    Else
        Call m_mainChart.yAxis().setLinearScale()
    End If
    Set addMainChart = m_mainChart
    Exit Function
End Function

'/ <summary>
'/ Add a candlestick layer to the main chart.
'/ </summary>
'/ <param name="upColor">The candle color for an up day.</param>
'/ <param name="downColor">The candle color for a down day.</param>
'/ <returns>The CandleStickLayer created.</returns>
Public Function addCandleStick(upColor, downColor)
    Call addOHLCLabel(upColor, downColor, True)
    Dim ret As Object
    Set ret = m_mainChart.addCandleStickLayer(m_highData, m_lowData, m_openData, m_closeData, _
        upColor, downColor)
    Call ret.setHTMLImageMap("", "", getHLOCToolTipFormat())
    If UBound(m_highData) + 1 - m_extraPoints > 60 Then
        Call ret.setDataGap(0)
    End If

    If UBound(m_highData) + 1 > m_extraPoints Then
        Dim expectedWidth As Long
        expectedWidth = Int((m_totalWidth - m_leftMargin - m_rightMargin) / (UBound(m_highData) + _
            1 - m_extraPoints))
        If expectedWidth <= 5 Then
            Call ret.setDataWidth(expectedWidth + 1 - expectedWidth Mod 2)
        End If
    End If

    Set addCandleStick = ret
    Exit Function
End Function

'/ <summary>
'/ Add a HLOC layer to the main chart.
'/ </summary>
'/ <param name="upColor">The color of the HLOC symbol for an up day.</param>
'/ <param name="downColor">The color of the HLOC symbol for a down day.</param>
'/ <returns>The HLOCLayer created.</returns>
Public Function addHLOC(upColor, downColor)
    Call addOHLCLabel(upColor, downColor, False)
    Dim ret As Object
    Set ret = m_mainChart.addHLOCLayer(m_highData, m_lowData, m_openData, m_closeData)
    Call ret.setColorMethod(cd.HLOCUpDown, upColor, downColor)
    Call ret.setHTMLImageMap("", "", getHLOCToolTipFormat())
    Call ret.setDataGap(0)
    Set addHLOC = ret
    Exit Function
End Function

Private Sub addOHLCLabel(upColor, downColor, candleStickMode)
    Dim i As Long
    i = lastIndex(m_closeData)
    If i >= 0 Then
        Dim openValue As Double
        openValue = cd.NoValue
        Dim closeValue As Double
        closeValue = cd.NoValue
        Dim highValue As Double
        highValue = cd.NoValue
        Dim lowValue As Double
        lowValue = cd.NoValue

        If i < UBound(m_openData) + 1 Then
            openValue = m_openData(i)
        End If
        If i < UBound(m_closeData) + 1 Then
            closeValue = m_closeData(i)
        End If
        If i < UBound(m_highData) + 1 Then
            highValue = m_highData(i)
        End If
        If i < UBound(m_lowData) + 1 Then
            lowValue = m_lowData(i)
        End If

        Dim openLabel As String
        openLabel = ""
        Dim closeLabel As String
        closeLabel = ""
        Dim highLabel As String
        highLabel = ""
        Dim lowLabel As String
        lowLabel = ""
        Dim delim As String
        delim = ""
        If openValue <> cd.NoValue Then
            openLabel = "Op:" & formatValue(openValue, m_generalFormat)
            delim = ", "
        End If
        If highValue <> cd.NoValue Then
            highLabel = delim & "Hi:" & formatValue(highValue, m_generalFormat)
            delim = ", "
        End If
        If lowValue <> cd.NoValue Then
            lowLabel = delim & "Lo:" & formatValue(lowValue, m_generalFormat)
            delim = ", "
        End If
        If closeValue <> cd.NoValue Then
            closeLabel = delim & "Cl:" & formatValue(closeValue, m_generalFormat)
            delim = ", "
        End If
        Dim label As String
        label = openLabel & highLabel & lowLabel & closeLabel

        Dim useUpColor As Boolean
        useUpColor = (closeValue >= openValue)
        If candleStickMode <> True Then
            Dim closeChanges()
            closeChanges = cd.ArrayMath(m_closeData).delta().result()
            Dim lastChangeIndex As Long
            lastChangeIndex = lastIndex(closeChanges)
            useUpColor = (lastChangeIndex < 0)
            If useUpColor <> True Then
                useUpColor = (closeChanges(lastChangeIndex) >= 0)
            End If
        End If

        Dim udcolor As Long
        udcolor = downColor
        If useUpColor Then
            udcolor = upColor
        End If
        Call m_mainChart.getLegend().addKey(label, udcolor)
    End If
End Sub

'/ <summary>
'/ Add a closing price line on the main chart.
'/ </summary>
'/ <param name="color">The color of the line.</param>
'/ <returns>The LineLayer object representing the line created.</returns>
Public Function addCloseLine(color)
    Set addCloseLine = addLineIndicator2(m_mainChart, m_closeData, color, "Closing Price")
    Exit Function
End Function

'/ <summary>
'/ Add a weight close line on the main chart.
'/ </summary>
'/ <param name="color">The color of the line.</param>
'/ <returns>The LineLayer object representing the line created.</returns>
Public Function addWeightedClose(color)
    Set addWeightedClose = addLineIndicator2(m_mainChart, cd.ArrayMath(m_highData).add(m_lowData _
        ).add(m_closeData).add(m_closeData).div(4).result(), color, "Weighted Close")
    Exit Function
End Function

'/ <summary>
'/ Add a typical price line on the main chart.
'/ </summary>
'/ <param name="color">The color of the line.</param>
'/ <returns>The LineLayer object representing the line created.</returns>
Public Function addTypicalPrice(color)
    Set addTypicalPrice = addLineIndicator2(m_mainChart, cd.ArrayMath(m_highData).add(m_lowData _
        ).add(m_closeData).div(3).result(), color, "Typical Price")
    Exit Function
End Function

'/ <summary>
'/ Add a median price line on the main chart.
'/ </summary>
'/ <param name="color">The color of the line.</param>
'/ <returns>The LineLayer object representing the line created.</returns>
Public Function addMedianPrice(color)
    Set addMedianPrice = addLineIndicator2(m_mainChart, cd.ArrayMath(m_highData).add(m_lowData _
        ).div(2).result(), color, "Median Price")
    Exit Function
End Function

'/ <summary>
'/ Add a simple moving average line on the main chart.
'/ </summary>
'/ <param name="period">The moving average period</param>
'/ <param name="color">The color of the line.</param>
'/ <returns>The LineLayer object representing the line created.</returns>
Public Function addSimpleMovingAvg(period, color)
    Dim label As String
    label = "SMA (" & period & ")"
    Set addSimpleMovingAvg = addLineIndicator2(m_mainChart, cd.ArrayMath(m_closeData).movAvg( _
        period).result(), color, label)
    Exit Function
End Function

'/ <summary>
'/ Add an exponential moving average line on the main chart.
'/ </summary>
'/ <param name="period">The moving average period</param>
'/ <param name="color">The color of the line.</param>
'/ <returns>The LineLayer object representing the line created.</returns>
Public Function addExpMovingAvg(period, color)
    Dim label As String
    label = "EMA (" & period & ")"
    Set addExpMovingAvg = addLineIndicator2(m_mainChart, cd.ArrayMath(m_closeData).expAvg(2.0 / ( _
        period + 1)).result(), color, label)
    Exit Function
End Function

'/ <summary>
'/ Add a triangular moving average line on the main chart.
'/ </summary>
'/ <param name="period">The moving average period</param>
'/ <param name="color">The color of the line.</param>
'/ <returns>The LineLayer object representing the line created.</returns>
Public Function addTriMovingAvg(period, color)
    Dim label As String
    label = "TMA (" & period & ")"
    Set addTriMovingAvg = addLineIndicator2(m_mainChart, cd.ArrayMath(computeTriMovingAvg( _
        m_closeData, period)).result(), color, label)
    Exit Function
End Function

'/ <summary>
'/ Add a weighted moving average line on the main chart.
'/ </summary>
'/ <param name="period">The moving average period</param>
'/ <param name="color">The color of the line.</param>
'/ <returns>The LineLayer object representing the line created.</returns>
Public Function addWeightedMovingAvg(period, color)
    Dim label As String
    label = "WMA (" & period & ")"
    Set addWeightedMovingAvg = addLineIndicator2(m_mainChart, cd.ArrayMath( _
        computeWeightedMovingAvg(m_closeData, period)).result(), color, label)
    Exit Function
End Function

'/ <summary>
'/ Add a parabolic SAR indicator to the main chart.
'/ </summary>
'/ <param name="accInitial">Initial acceleration factor</param>
'/ <param name="accIncrement">Acceleration factor increment</param>
'/ <param name="accMaximum">Maximum acceleration factor</param>
'/ <param name="symbolType">The symbol used to plot the parabolic SAR</param>
'/ <param name="symbolSize">The symbol size in pixels</param>
'/ <param name="fillColor">The fill color of the symbol</param>
'/ <param name="edgeColor">The edge color of the symbol</param>
'/ <returns>The LineLayer object representing the layer created.</returns>
Public Function addParabolicSAR(accInitial, accIncrement, accMaximum, symbolType, symbolSize, _
    fillColor, edgeColor)
    Dim isLong As Boolean
    isLong = True
    Dim acc As Double
    acc = accInitial
    Dim extremePoint As Double
    extremePoint = 0
    ReDim psar(UBound(m_lowData))

    Dim i_1 As Long
    i_1 = -1
    Dim i_2 As Long
    i_2 = -1

    Dim i As Long
    For i = 0 To UBound(m_lowData)
        psar(i) = cd.NoValue
        If (m_lowData(i) <> cd.NoValue) And (m_highData(i) <> cd.NoValue) Then
            If (i_1 >= 0) And (i_2 < 0) Then
                If m_lowData(i_1) <= m_lowData(i) Then
                    psar(i) = m_lowData(i_1)
                    isLong = True
                    If m_highData(i_1) > m_highData(i) Then
                        extremePoint = m_highData(i_1)
                    Else
                        extremePoint = m_highData(i)
                    End If
                Else
                    extremePoint = m_lowData(i)
                    isLong = False
                    If m_highData(i_1) > m_highData(i) Then
                        psar(i) = m_highData(i_1)
                    Else
                        psar(i) = m_highData(i)
                    End If
                End If
            ElseIf (i_1 >= 0) And (i_2 >= 0) Then
                If acc > accMaximum Then
                    acc = accMaximum
                End If

                psar(i) = psar(i_1) + acc * (extremePoint - psar(i_1))

                If isLong Then
                    If m_lowData(i) < psar(i) Then
                        isLong = False
                        psar(i) = extremePoint
                        extremePoint = m_lowData(i)
                        acc = accInitial
                    Else
                        If m_highData(i) > extremePoint Then
                            extremePoint = m_highData(i)
                            acc = acc + accIncrement
                        End If

                        If m_lowData(i_1) < psar(i) Then
                            psar(i) = m_lowData(i_1)
                        End If
                        If m_lowData(i_2) < psar(i) Then
                            psar(i) = m_lowData(i_2)
                        End If
                    End If
                Else
                    If m_highData(i) > psar(i) Then
                        isLong = True
                        psar(i) = extremePoint
                        extremePoint = m_highData(i)
                        acc = accInitial
                    Else
                        If m_lowData(i) < extremePoint Then
                            extremePoint = m_lowData(i)
                            acc = acc + accIncrement
                        End If

                        If m_highData(i_1) > psar(i) Then
                            psar(i) = m_highData(i_1)
                        End If
                        If m_highData(i_2) > psar(i) Then
                            psar(i) = m_highData(i_2)
                        End If
                    End If
                End If
            End If

            i_2 = i_1
            i_1 = i
        End If
    Next

    Dim ret As Object
    Set ret = addLineIndicator2(m_mainChart, psar, fillColor, "Parabolic SAR")
    Call ret.setLineWidth(0)

    Set ret = addLineIndicator2(m_mainChart, psar, fillColor, "")
    Call ret.setLineWidth(0)
    Call ret.getDataSet(0).setDataSymbol(symbolType, symbolSize, fillColor, edgeColor)
    Set addParabolicSAR = ret
    Exit Function
End Function

'/ <summary>
'/ Add a comparison line to the main price chart.
'/ </summary>
'/ <param name="data">The data series to compare to</param>
'/ <param name="color">The color of the comparison line</param>
'/ <param name="name">The name of the comparison line</param>
'/ <returns>The LineLayer object representing the line layer created.</returns>
Public Function addComparison(data, color, name)
    Dim firstIndex As Long
    firstIndex = m_extraPoints
    Do While (firstIndex < UBound(data) + 1) And (firstIndex < UBound(m_closeData) + 1)
        If (data(firstIndex) <> cd.NoValue) And (m_closeData(firstIndex) <> cd.NoValue) And (data( _
            firstIndex) <> 0) And (m_closeData(firstIndex) <> 0) Then
            Exit Do
        End If
        firstIndex = firstIndex + 1
    Loop
    If (firstIndex >= UBound(data) + 1) Or (firstIndex >= UBound(m_closeData) + 1) Then
        Set addComparison = Nothing
        Exit Function
    End If

    Dim scaleFactor As Double
    scaleFactor = m_closeData(firstIndex) / data(firstIndex)
    Dim layer As Object
    Set layer = m_mainChart.addLineLayer(cd.ArrayMath(data).mul(scaleFactor).result(), _
        cd.Transparent)
    Call layer.setHTMLImageMap("{disable}")

    Dim a As Object
    Set a = m_mainChart.addAxis(cd.Right, 0)
    Call a.setColors(cd.Transparent, cd.Transparent)
    Call a.syncAxis(m_mainChart.yAxis(), 1 / scaleFactor, 0)

    Dim ret As Object
    Set ret = addLineIndicator2(m_mainChart, data, color, name)
    Call ret.setUseYAxis(a)
    Set addComparison = ret
    Exit Function
End Function

'/ <summary>
'/ Display percentage axis scale
'/ </summary>
'/ <returns>The Axis object representing the percentage axis.</returns>
Public Function setPercentageAxis()
    Dim firstClose As Double
    firstClose = firstCloseValue()
    If firstClose = cd.NoValue Then
        Set setPercentageAxis = Nothing
        Exit Function
    End If

    Dim axisAlign As Long
    axisAlign = cd.Left
    If m_axisOnRight Then
        axisAlign = cd.Right
    End If

    Dim ret As Object
    Set ret = m_mainChart.addAxis(axisAlign, 0)
    Call configureYAxis(ret, 300)
    Call ret.syncAxis(m_mainChart.yAxis(), 100 / firstClose)
    Call ret.setRounding(False, False)
    Call ret.setLabelFormat("{={value}-100|@}%")
    Call m_mainChart.yAxis().setColors(cd.Transparent, cd.Transparent)
    Call m_mainChart.getPlotArea().setGridAxis(Empty, ret)
    Set setPercentageAxis = ret
    Exit Function
End Function

'/ <summary>
'/ Add a generic band to the main finance chart. This method is used internally by other methods to add
'/ various bands (eg. Bollinger band, Donchian channels, etc).
'/ </summary>
'/ <param name="upperLine">The data series for the upper band line.</param>
'/ <param name="lowerLine">The data series for the lower band line.</param>
'/ <param name="lineColor">The color of the upper and lower band line.</param>
'/ <param name="fillColor">The color to fill the region between the upper and lower band lines.</param>
'/ <param name="name">The name of the band.</param>
'/ <returns>An InterLineLayer object representing the filled region.</returns>
Public Function addBand(upperLine, lowerLine, lineColor, fillColor, name)
    Dim i As Long
    i = UBound(upperLine)
    If i >= UBound(lowerLine) + 1 Then
        i = UBound(lowerLine)
    End If

    Do While i >= 0
        If (upperLine(i) <> cd.NoValue) And (lowerLine(i) <> cd.NoValue) Then
            name = name & ": " & formatValue(lowerLine(i), m_generalFormat) & " - " & formatValue( _
                upperLine(i), m_generalFormat)
            Exit Do
        End If
        i = i - 1
    Loop

    Dim layer As Object
    Set layer = m_mainChart.addLineLayer2()
    Call layer.addDataSet(upperLine, lineColor, name)
    Call layer.addDataSet(lowerLine, lineColor)
    Set addBand = m_mainChart.addInterLineLayer(layer.getLine(0), layer.getLine(1), fillColor)
    Exit Function
End Function

'/ <summary>
'/ Add a Bollinger band on the main chart.
'/ </summary>
'/ <param name="period">The period to compute the band.</param>
'/ <param name="bandWidth">The half-width of the band in terms multiples of standard deviation. Typically 2 is used.</param>
'/ <param name="lineColor">The color of the lines defining the upper and lower limits.</param>
'/ <param name="fillColor">The color to fill the regional within the band.</param>
'/ <returns>The InterLineLayer object representing the band created.</returns>
Public Function addBollingerBand(period, bandWidth, lineColor, fillColor)
    'Bollinger Band is moving avg +/- (width * moving std deviation)
    Dim stdDev()
    stdDev = cd.ArrayMath(m_closeData).movStdDev(period).mul(bandWidth).result()
    Dim movAvg()
    movAvg = cd.ArrayMath(m_closeData).movAvg(period).result()
    Dim label As String
    label = "Bollinger (" & period & ", " & bandWidth & ")"
    Set addBollingerBand = addBand(cd.ArrayMath(movAvg).add(stdDev).result(), cd.ArrayMath(movAvg _
        ).subtract(stdDev).selectGTZ(Empty, 0).result(), lineColor, fillColor, label)
    Exit Function
End Function

'/ <summary>
'/ Add a Donchian channel on the main chart.
'/ </summary>
'/ <param name="period">The period to compute the band.</param>
'/ <param name="lineColor">The color of the lines defining the upper and lower limits.</param>
'/ <param name="fillColor">The color to fill the regional within the band.</param>
'/ <returns>The InterLineLayer object representing the band created.</returns>
Public Function addDonchianChannel(period, lineColor, fillColor)
    'Donchian Channel is the zone between the moving max and moving min
    Dim label As String
    label = "Donchian (" & period & ")"
    Set addDonchianChannel = addBand(cd.ArrayMath(m_highData).movMax(period).result(), _
        cd.ArrayMath(m_lowData).movMin(period).result(), lineColor, fillColor, label)
    Exit Function
End Function

'/ <summary>
'/ Add a price envelop on the main chart. The price envelop is a defined as a ratio around a
'/ moving average. For example, a ratio of 0.2 means 20% above and below the moving average.
'/ </summary>
'/ <param name="period">The period for the moving average.</param>
'/ <param name="range">The ratio above and below the moving average.</param>
'/ <param name="lineColor">The color of the lines defining the upper and lower limits.</param>
'/ <param name="fillColor">The color to fill the regional within the band.</param>
'/ <returns>The InterLineLayer object representing the band created.</returns>
Public Function addEnvelop(period, range, lineColor, fillColor)
    'Envelop is moving avg +/- percentage
    Dim movAvg()
    movAvg = cd.ArrayMath(m_closeData).movAvg(period).result()
    Dim label As String
    label = "Envelop (SMA " & period & " +/- " & Int(range * 100) & "%)"
    Set addEnvelop = addBand(cd.ArrayMath(movAvg).mul(1 + range).result(), cd.ArrayMath(movAvg _
        ).mul(1 - range).result(), lineColor, fillColor, label)
    Exit Function
End Function

'/ <summary>
'/ Add a volume bar chart layer on the main chart.
'/ </summary>
'/ <param name="height">The height of the bar chart layer in pixels.</param>
'/ <param name="upColor">The color to used on an 'up' day. An 'up' day is a day where
'/ the closing price is higher than that of the previous day.</param>
'/ <param name="downColor">The color to used on a 'down' day. A 'down' day is a day
'/ where the closing price is lower than that of the previous day.</param>
'/ <param name="flatColor">The color to used on a 'flat' day. A 'flat' day is a day
'/ where the closing price is the same as that of the previous day.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addVolBars(height, upColor, downColor, flatColor)
    Set addVolBars = addVolBars2(m_mainChart, height, upColor, downColor, flatColor)
    Exit Function
End Function

Private Function addVolBars2(c, height, upColor, downColor, flatColor)
    Dim barLayer As Object
    Set barLayer = c.addBarLayer2(cd.Overlay)
    Call barLayer.setBorderColor(cd.Transparent)

    If c Is m_mainChart Then
        Call configureYAxis(c.yAxis2(), height)
        Dim topMargin As Long
        topMargin = c.getDrawArea().getHeight() - m_topMargin - m_bottomMargin - height + _
            m_yAxisMargin
        If topMargin < 0 Then
            topMargin = 0
        End If
        Call c.yAxis2().setTopMargin(topMargin)
        Call barLayer.setUseYAxis2()
    End If

    Dim a As Object
    Set a = c.yAxis2()
    If Not c Is m_mainChart Then
        Set a = c.yAxis()
    End If
    If cd.ArrayMath(m_volData).max() < 10 Then
        Call a.setLabelFormat("{value|1}" & m_volUnit)
    Else
        Call a.setLabelFormat("{value}" & m_volUnit)
    End If

    Dim closeChange()
    closeChange = cd.ArrayMath(m_closeData).delta().replace(cd.NoValue, 0).result()
    Dim i As Long
    i = lastIndex(m_volData)
    Dim label As String
    label = "Vol"
    If i >= 0 Then
        label = label & ": " & formatValue(m_volData(i), m_generalFormat) & m_volUnit
    End If

    Dim upDS As Object
    Set upDS = barLayer.addDataSet(cd.ArrayMath(m_volData).selectGTZ(closeChange).result(), _
        upColor)
    Dim dnDS As Object
    Set dnDS = barLayer.addDataSet(cd.ArrayMath(m_volData).selectLTZ(closeChange).result(), _
        downColor)
    Dim flatDS As Object
    Set flatDS = barLayer.addDataSet(cd.ArrayMath(m_volData).selectEQZ(closeChange).result(), _
        flatColor)

    If (i < 0) Or (closeChange(i) = 0) Or (closeChange(i) = cd.NoValue) Then
        Call flatDS.setDataName(label)
    ElseIf closeChange(i) > 0 Then
        Call upDS.setDataName(label)
    Else
        Call dnDS.setDataName(label)
    End If

    Set addVolBars2 = barLayer
    Exit Function
End Function

'/ <summary>
'/ Add a blank indicator chart to the finance chart. Used internally to add other indicators.
'/ Override to change the default formatting (eg. axis fonts, etc.) of the various indicators.
'/ </summary>
'/ <param name="height">The height of the chart in pixels.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addIndicator(height)
    'create a new chart object
    Dim ret As Object
    Set ret = cd.XYChart(m_totalWidth, height + m_topMargin + m_bottomMargin, cd.Transparent)
    Call ret.setTrimData(m_extraPoints)

    If Not m_currentChart Is Nothing Then
        'if there is a chart before the newly created chart, disable its x-axis, and copy
        'its x-axis labels to the new chart
        Call m_currentChart.xAxis().setColors(cd.Transparent, cd.Transparent)
        Call ret.xAxis().copyAxis(m_currentChart.xAxis())

        'add chart to MultiChart and update the total height
        Call addChart(0, m_totalHeight + m_plotAreaGap, ret)
        m_totalHeight = m_totalHeight + height + 1 + m_plotAreaGap
    Else
        'no existing chart - create the x-axis labels from scratch
        Call setXLabels(ret.xAxis())

        'add chart to MultiChart and update the total height
        Call addChart(0, m_totalHeight, ret)
        m_totalHeight = m_totalHeight + height + 1
    End If

    'the newly created chart becomes the current chart
    Set m_currentChart = ret

    'update the size
    Call setSize(m_totalWidth, m_totalHeight + m_topMargin + m_bottomMargin)

    'configure the plot area
    Call ret.setPlotArea(m_leftMargin, m_topMargin, m_totalWidth - m_leftMargin - m_rightMargin, _
        height, m_plotAreaBgColor, -1, m_plotAreaBorder).setGridColor(m_majorHGridColor, _
        m_majorVGridColor, m_minorHGridColor, m_minorVGridColor)
    Call ret.setAntiAlias(m_antiAlias)

    'configure legend box
    If m_legendFontColor <> cd.Transparent Then
        Dim box As Object
        Set box = ret.addLegend(m_leftMargin, m_topMargin, False, m_legendFont, m_legendFontSize)
        Call box.setFontColor(m_legendFontColor)
        Call box.setBackground(m_legendBgColor)
        Call box.setMargin2(5, 0, 2, 1)
        Call box.setSize(m_totalWidth - m_leftMargin - m_rightMargin + 1, 0)
    End If

    'configure x-axis
    Dim a As Object
    Set a = ret.xAxis()
    Call a.setIndent(True)
    Call a.setTickLength(2, 0)
    Call a.setColors(cd.Transparent, m_xAxisFontColor, m_xAxisFontColor, m_xAxisFontColor)
    Call a.setLabelStyle(m_xAxisFont, m_xAxisFontSize, m_xAxisFontColor, m_xAxisFontAngle)

    'configure y-axis
    Call ret.setYAxisOnRight(m_axisOnRight)
    Call configureYAxis(ret.yAxis(), height)

    Set addIndicator = ret
    Exit Function
End Function

Private Sub configureYAxis(a, height)
    Call a.setAutoScale(0, 0.05, 0)
    If height < 100 Then
        Call a.setTickDensity(15)
    End If
    Call a.setMargin(m_yAxisMargin)
    Call a.setLabelStyle(m_yAxisFont, m_yAxisFontSize, m_yAxisFontColor, 0)
    Call a.setTickLength(-4, -2)
    Call a.setColors(cd.Transparent, m_yAxisFontColor, m_yAxisFontColor, m_yAxisFontColor)
End Sub

'/ <summary>
'/ Add a generic line indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="data">The data series of the indicator line.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <param name="name">The name of the indicator.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addLineIndicator(height, data, color, name)
    Dim c As Object
    Set c = addIndicator(height)
    Call addLineIndicator2(c, data, color, name)
    Set addLineIndicator = c
    Exit Function
End Function

'/ <summary>
'/ Add a line to an existing indicator chart.
'/ </summary>
'/ <param name="c">The indicator chart to add the line to.</param>
'/ <param name="data">The data series of the indicator line.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <param name="name">The name of the indicator.</param>
'/ <returns>The LineLayer object representing the line created.</returns>
Public Function addLineIndicator2(c, data, color, name)
    Set addLineIndicator2 = c.addLineLayer(data, color, formatIndicatorLabel(name, data))
    Exit Function
End Function

'/ <summary>
'/ Add a generic bar indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="data">The data series of the indicator bars.</param>
'/ <param name="color">The color of the indicator bars.</param>
'/ <param name="name">The name of the indicator.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addBarIndicator(height, data, color, name)
    Dim c As Object
    Set c = addIndicator(height)
    Call addBarIndicator2(c, data, color, name)
    Set addBarIndicator = c
    Exit Function
End Function

'/ <summary>
'/ Add a bar layer to an existing indicator chart.
'/ </summary>
'/ <param name="c">The indicator chart to add the bar layer to.</param>
'/ <param name="data">The data series of the indicator bars.</param>
'/ <param name="color">The color of the indicator bars.</param>
'/ <param name="name">The name of the indicator.</param>
'/ <returns>The BarLayer object representing the bar layer created.</returns>
Public Function addBarIndicator2(c, data, color, name)
    Dim layer As Object
    Set layer = c.addBarLayer(data, color, formatIndicatorLabel(name, data))
    Call layer.setBorderColor(cd.Transparent)
    Set addBarIndicator2 = layer
    Exit Function
End Function

'/ <summary>
'/ Add an upper/lower threshold range to an existing indicator chart.
'/ </summary>
'/ <param name="c">The indicator chart to add the threshold range to.</param>
'/ <param name="layer">The line layer that the threshold range applies to.</param>
'/ <param name="topRange">The upper threshold.</param>
'/ <param name="topColor">The color to fill the region of the line that is above the
'/ upper threshold.</param>
'/ <param name="bottomRange">The lower threshold.</param>
'/ <param name="bottomColor">The color to fill the region of the line that is below
'/ the lower threshold.</param>
Public Sub addThreshold(c, layer, topRange, topColor, bottomRange, bottomColor)
    Dim topMark As Object
    Set topMark = c.yAxis().addMark(topRange, topColor, formatValue(topRange, m_generalFormat))
    Dim bottomMark As Object
    Set bottomMark = c.yAxis().addMark(bottomRange, bottomColor, formatValue(bottomRange, _
        m_generalFormat))

    Call c.addInterLineLayer(layer.getLine(), topMark.getLine(), topColor, cd.Transparent)
    Call c.addInterLineLayer(layer.getLine(), bottomMark.getLine(), cd.Transparent, bottomColor)
End Sub

Private Function formatIndicatorLabel(name, data)
    Dim i As Long
    i = lastIndex(data)
    If name = "" Then
        formatIndicatorLabel = name
        Exit Function
    End If
    If (name = "") Or (i < 0) Then
        formatIndicatorLabel = name
        Exit Function
    End If
    Dim ret As String
    ret = name & ": " & formatValue(data(i), m_generalFormat)
    formatIndicatorLabel = ret
    Exit Function
End Function

'/ <summary>
'/ Add an Accumulation/Distribution indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addAccDist(height, color)
    'Close Location Value = ((C - L) - (H - C)) / (H - L)
    'Accumulation Distribution Line = Accumulation of CLV * volume
    Dim range()
    range = cd.ArrayMath(m_highData).subtract(m_lowData).result()
    Set addAccDist = addLineIndicator(height, cd.ArrayMath(m_closeData).mul(2).subtract(m_lowData _
        ).subtract(m_highData).mul(m_volData).financeDiv(range, 0).acc().result(), color, _
        "Accumulation/Distribution")
    Exit Function
End Function

Private Function computeAroonUp(period)
    ReDim aroonUp(UBound(m_highData))
    Dim i As Long
    For i = 0 To UBound(m_highData)
        Dim highValue As Double
        highValue = m_highData(i)
        If highValue = cd.NoValue Then
            aroonUp(i) = cd.NoValue
        Else
            Dim currentIndex As Long
            currentIndex = i
            Dim highCount As Long
            highCount = period
            Dim count As Long
            count = period

            Do While (count > 0) And (currentIndex >= count)
                currentIndex = currentIndex - 1
                Dim currentValue As Double
                currentValue = m_highData(currentIndex)
                If currentValue <> cd.NoValue Then
                    count = count - 1
                    If currentValue > highValue Then
                        highValue = currentValue
                        highCount = count
                    End If
                End If
            Loop

            If count > 0 Then
                aroonUp(i) = cd.NoValue
            Else
                aroonUp(i) = highCount * 100.0 / period
            End If
        End If
    Next

    computeAroonUp = aroonUp
    Exit Function
End Function

Private Function computeAroonDn(period)
    ReDim aroonDn(UBound(m_lowData))
    Dim i As Long
    For i = 0 To UBound(m_lowData)
        Dim lowValue As Double
        lowValue = m_lowData(i)
        If lowValue = cd.NoValue Then
            aroonDn(i) = cd.NoValue
        Else
            Dim currentIndex As Long
            currentIndex = i
            Dim lowCount As Long
            lowCount = period
            Dim count As Long
            count = period

            Do While (count > 0) And (currentIndex >= count)
                currentIndex = currentIndex - 1
                Dim currentValue As Double
                currentValue = m_lowData(currentIndex)
                If currentValue <> cd.NoValue Then
                    count = count - 1
                    If currentValue < lowValue Then
                        lowValue = currentValue
                        lowCount = count
                    End If
                End If
            Loop

            If count > 0 Then
                aroonDn(i) = cd.NoValue
            Else
                aroonDn(i) = lowCount * 100.0 / period
            End If
        End If
    Next

    computeAroonDn = aroonDn
    Exit Function
End Function

'/ <summary>
'/ Add an Aroon Up/Down indicators chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicators.</param>
'/ <param name="upColor">The color of the Aroon Up indicator line.</param>
'/ <param name="downColor">The color of the Aroon Down indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addAroon(height, period, upColor, downColor)
    Dim c As Object
    Set c = addIndicator(height)
    Call addLineIndicator2(c, computeAroonUp(period), upColor, "Aroon Up")
    Call addLineIndicator2(c, computeAroonDn(period), downColor, "Aroon Down")
    Call c.yAxis().setLinearScale(0, 100)
    Set addAroon = c
    Exit Function
End Function

'/ <summary>
'/ Add an Aroon Oscillator indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addAroonOsc(height, period, color)
    Dim label As String
    label = "Aroon Oscillator (" & period & ")"
    Dim c As Object
    Set c = addLineIndicator(height, cd.ArrayMath(computeAroonUp(period)).subtract(computeAroonDn( _
        period)).result(), color, label)
    Call c.yAxis().setLinearScale(-100, 100)
    Set addAroonOsc = c
    Exit Function
End Function

Private Function computeTrueRange()
    Dim previousClose()
    previousClose = cd.ArrayMath(m_closeData).shift().result()
    Dim ret()
    ret = cd.ArrayMath(m_highData).subtract(m_lowData).result()
    Dim temp As Double
    temp = 0

    Dim i As Long
    For i = 0 To UBound(m_highData)
        If (ret(i) <> cd.NoValue) And (previousClose(i) <> cd.NoValue) Then
            temp = Abs(m_highData(i) - previousClose(i))
            If temp > ret(i) Then
                ret(i) = temp
            End If
            temp = Abs(previousClose(i) - m_lowData(i))
            If temp > ret(i) Then
                ret(i) = temp
            End If
        End If
    Next

    computeTrueRange = ret
    Exit Function
End Function

'/ <summary>
'/ Add an Average Directional Index indicators chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="posColor">The color of the Positive Directional Index line.</param>
'/ <param name="negColor">The color of the Negatuve Directional Index line.</param>
'/ <param name="color">The color of the Average Directional Index line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addADX(height, period, posColor, negColor, color)
    'pos/neg directional movement
    Dim pos As Object
    Set pos = cd.ArrayMath(m_highData).delta().selectGTZ()
    Dim neg As Object
    Set neg = cd.ArrayMath(m_lowData).delta().mul(-1).selectGTZ()
    Dim delta()
    delta = cd.ArrayMath(pos.result()).subtract(neg.result()).result()
    Call pos.selectGTZ(delta)
    Call neg.selectLTZ(delta)

    'initial value
    Dim posData()
    posData = pos.result()
    Dim negData()
    negData = neg.result()
    If (UBound(posData) + 1 > 1) And (posData(1) <> cd.NoValue) And (negData(1) <> cd.NoValue) _
         Then
        posData(1) = (posData(1) * 2 + negData(1)) / 3
        negData(1) = (negData(1) + posData(1)) / 2
        Set pos = cd.ArrayMath(posData)
        Set neg = cd.ArrayMath(negData)
    End If

    'pos/neg directional index
    Dim tr()
    tr = computeTrueRange()
    tr = cd.ArrayMath(tr).expAvg(1.0 / period).result()
    Call pos.expAvg(1.0 / period).financeDiv(tr, 0).mul(100)
    Call neg.expAvg(1.0 / period).financeDiv(tr, 0).mul(100)

    'directional movement index ??? what happen if division by zero???
    Dim totalDM()
    totalDM = cd.ArrayMath(pos.result()).add(neg.result()).result()
    Dim dx As Object
    Set dx = cd.ArrayMath(pos.result()).subtract(neg.result()).absolute().financeDiv(totalDM, 0 _
        ).mul(100).expAvg(1.0 / period)

    Dim c As Object
    Set c = addIndicator(height)
    Dim label1 As String
    label1 = "+DI (" & period & ")"
    Dim label2 As String
    label2 = "-DI (" & period & ")"
    Dim label3 As String
    label3 = "ADX (" & period & ")"
    Call addLineIndicator2(c, pos.result(), posColor, label1)
    Call addLineIndicator2(c, neg.result(), negColor, label2)
    Call addLineIndicator2(c, dx.result(), color, label3)
    Set addADX = c
    Exit Function
End Function

'/ <summary>
'/ Add an Average True Range indicators chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="color1">The color of the True Range line.</param>
'/ <param name="color2">The color of the Average True Range line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addATR(height, period, color1, color2)
    Dim trueRange()
    trueRange = computeTrueRange()
    Dim c As Object
    Set c = addLineIndicator(height, trueRange, color1, "True Range")
    Dim label As String
    label = "Average True Range (" & period & ")"
    Call addLineIndicator2(c, cd.ArrayMath(trueRange).expAvg(2.0 / (period + 1)).result(), color2, _
        label)
    Set addATR = c
    Exit Function
End Function

'/ <summary>
'/ Add a Bollinger Band Width indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="width">The band width to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addBollingerWidth(height, period, width, color)
    Dim label As String
    label = "Bollinger Width (" & period & ", " & width & ")"
    Set addBollingerWidth = addLineIndicator(height, cd.ArrayMath(m_closeData).movStdDev(period _
        ).mul(width * 2).result(), color, label)
    Exit Function
End Function

'/ <summary>
'/ Add a Community Channel Index indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <param name="deviation">The distance beween the middle line and the upper and lower threshold lines.</param>
'/ <param name="upColor">The fill color when the indicator exceeds the upper threshold line.</param>
'/ <param name="downColor">The fill color when the indicator falls below the lower threshold line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addCCI(height, period, color, deviation, upColor, downColor)
    'typical price
    Dim tp()
    tp = cd.ArrayMath(m_highData).add(m_lowData).add(m_closeData).div(3).result()

    'simple moving average of typical price
    Dim smvtp()
    smvtp = cd.ArrayMath(tp).movAvg(period).result()

    'compute mean deviation
    ReDim movMeanDev(UBound(smvtp))
    Dim i As Long
    For i = 0 To UBound(smvtp)
        Dim avg As Double
        avg = smvtp(i)
        If avg = cd.NoValue Then
            movMeanDev(i) = cd.NoValue
        Else
            Dim currentIndex As Long
            currentIndex = i
            Dim count As Long
            count = period - 1
            Dim acc As Double
            acc = 0

            Do While (count >= 0) And (currentIndex >= count)
                Dim currentValue As Double
                currentValue = tp(currentIndex)
                currentIndex = currentIndex - 1
                If currentValue <> cd.NoValue Then
                    count = count - 1
                    acc = acc + Abs(avg - currentValue)
                End If
            Loop

            If count > 0 Then
                movMeanDev(i) = cd.NoValue
            Else
                movMeanDev(i) = acc / period
            End If
        End If
    Next

    Dim c As Object
    Set c = addIndicator(height)
    Dim label As String
    label = "CCI (" & period & ")"
    Dim layer As Object
    Set layer = addLineIndicator2(c, cd.ArrayMath(tp).subtract(smvtp).financeDiv(movMeanDev, 0 _
        ).div(0.015).result(), color, label)
    Call addThreshold(c, layer, deviation, upColor, -deviation, downColor)
    Set addCCI = c
    Exit Function
End Function

'/ <summary>
'/ Add a Chaikin Money Flow indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addChaikinMoneyFlow(height, period, color)
    Dim range()
    range = cd.ArrayMath(m_highData).subtract(m_lowData).result()
    Dim volAvg()
    volAvg = cd.ArrayMath(m_volData).movAvg(period).result()
    Dim label As String
    label = "Chaikin Money Flow (" & period & ")"
    Set addChaikinMoneyFlow = addBarIndicator(height, cd.ArrayMath(m_closeData).mul(2).subtract( _
        m_lowData).subtract(m_highData).mul(m_volData).financeDiv(range, 0).movAvg(period _
        ).financeDiv(volAvg, 0).result(), color, label)
    Exit Function
End Function

'/ <summary>
'/ Add a Chaikin Oscillator indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addChaikinOscillator(height, color)
    'first compute acc/dist line
    Dim range()
    range = cd.ArrayMath(m_highData).subtract(m_lowData).result()
    Dim accdist()
    accdist = cd.ArrayMath(m_closeData).mul(2).subtract(m_lowData).subtract(m_highData).mul( _
        m_volData).financeDiv(range, 0).acc().result()

    'chaikin osc = exp3(accdist) - exp10(accdist)
    Dim expAvg10()
    expAvg10 = cd.ArrayMath(accdist).expAvg(2.0 / (10 + 1)).result()
    Set addChaikinOscillator = addLineIndicator(height, cd.ArrayMath(accdist).expAvg(2.0 / (3 + 1) _
        ).subtract(expAvg10).result(), color, "Chaikin Oscillator")
    Exit Function
End Function

'/ <summary>
'/ Add a Chaikin Volatility indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period1">The period to smooth the range.</param>
'/ <param name="period2">The period to compute the rate of change of the smoothed range.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addChaikinVolatility(height, period1, period2, color)
    Dim label As String
    label = "Chaikin Volatility (" & period1 & ", " & period2 & ")"
    Set addChaikinVolatility = addLineIndicator(height, cd.ArrayMath(m_highData).subtract( _
        m_lowData).expAvg(2.0 / (period1 + 1)).rate(period2).subtract(1).mul(100).result(), color, _
        label)
    Exit Function
End Function

'/ <summary>
'/ Add a Close Location Value indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addCLV(height, color)
    'Close Location Value = ((C - L) - (H - C)) / (H - L)
    Dim range()
    range = cd.ArrayMath(m_highData).subtract(m_lowData).result()
    Set addCLV = addLineIndicator(height, cd.ArrayMath(m_closeData).mul(2).subtract(m_lowData _
        ).subtract(m_highData).financeDiv(range, 0).result(), color, "Close Location Value")
    Exit Function
End Function

'/ <summary>
'/ Add a Detrended Price Oscillator indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addDPO(height, period, color)
    Dim label As String
    label = "DPO (" & period & ")"
    Set addDPO = addLineIndicator(height, cd.ArrayMath(m_closeData).movAvg(period).shift(period / _
        2 + 1).subtract(m_closeData).mul(-1).result(), color, label)
    Exit Function
End Function

'/ <summary>
'/ Add a Donchian Channel Width indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addDonchianWidth(height, period, color)
    Dim label As String
    label = "Donchian Width (" & period & ")"
    Set addDonchianWidth = addLineIndicator(height, cd.ArrayMath(m_highData).movMax(period _
        ).subtract(cd.ArrayMath(m_lowData).movMin(period).result()).result(), color, label)
    Exit Function
End Function

'/ <summary>
'/ Add a Ease of Movement indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to smooth the indicator.</param>
'/ <param name="color1">The color of the indicator line.</param>
'/ <param name="color2">The color of the smoothed indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addEaseOfMovement(height, period, color1, color2)
    Dim boxRatioInverted()
    boxRatioInverted = cd.ArrayMath(m_highData).subtract(m_lowData).financeDiv(m_volData, 0 _
        ).result()
    Dim result()
    result = cd.ArrayMath(m_highData).add(m_lowData).div(2).delta().mul(boxRatioInverted).result()

    Dim c As Object
    Set c = addLineIndicator(height, result, color1, "EMV")
    Dim label As String
    label = "EMV EMA (" & period & ")"
    Call addLineIndicator2(c, cd.ArrayMath(result).movAvg(period).result(), color2, label)
    Set addEaseOfMovement = c
    Exit Function
End Function

'/ <summary>
'/ Add a Fast Stochastic indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period1">The period to compute the %K line.</param>
'/ <param name="period2">The period to compute the %D line.</param>
'/ <param name="color1">The color of the %K line.</param>
'/ <param name="color2">The color of the %D line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addFastStochastic(height, period1, period2, color1, color2)
    Dim movLow()
    movLow = cd.ArrayMath(m_lowData).movMin(period1).result()
    Dim movRange()
    movRange = cd.ArrayMath(m_highData).movMax(period1).subtract(movLow).result()
    Dim stochastic()
    stochastic = cd.ArrayMath(m_closeData).subtract(movLow).financeDiv(movRange, 0.5).mul(100 _
        ).result()

    Dim label1 As String
    label1 = "Fast Stochastic %K (" & period1 & ")"
    Dim c As Object
    Set c = addLineIndicator(height, stochastic, color1, label1)
    Dim label2 As String
    label2 = "%D (" & period2 & ")"
    Call addLineIndicator2(c, cd.ArrayMath(stochastic).movAvg(period2).result(), color2, label2)

    Call c.yAxis().setLinearScale(0, 100)
    Set addFastStochastic = c
    Exit Function
End Function

'/ <summary>
'/ Add a MACD indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period1">The first moving average period to compute the indicator.</param>
'/ <param name="period2">The second moving average period to compute the indicator.</param>
'/ <param name="period3">The moving average period of the signal line.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <param name="signalColor">The color of the signal line.</param>
'/ <param name="divColor">The color of the divergent bars.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addMACD(height, period1, period2, period3, color, signalColor, divColor)
    Dim c As Object
    Set c = addIndicator(height)

    'MACD is defined as the difference between two exponential averages (typically 12/26 days)
    Dim expAvg1()
    expAvg1 = cd.ArrayMath(m_closeData).expAvg(2.0 / (period1 + 1)).result()
    Dim macd()
    macd = cd.ArrayMath(m_closeData).expAvg(2.0 / (period2 + 1)).subtract(expAvg1).result()

    'Add the MACD line
    Dim label1 As String
    label1 = "MACD (" & period1 & ", " & period2 & ")"
    Call addLineIndicator2(c, macd, color, label1)

    'MACD signal line
    Dim macdSignal()
    macdSignal = cd.ArrayMath(macd).expAvg(2.0 / (period3 + 1)).result()
    Dim label2 As String
    label2 = "EXP (" & period3 & ")"
    Call addLineIndicator2(c, macdSignal, signalColor, label2)

    'Divergence
    Call addBarIndicator2(c, cd.ArrayMath(macd).subtract(macdSignal).result(), divColor, _
        "Divergence")

    Set addMACD = c
    Exit Function
End Function

'/ <summary>
'/ Add a Mass Index indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <param name="upColor">The fill color when the indicator exceeds the upper threshold line.</param>
'/ <param name="downColor">The fill color when the indicator falls below the lower threshold line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addMassIndex(height, color, upColor, downColor)
    'Mass Index
    Dim f As Double
    f = 2.0 / (10)
    Dim exp9()
    exp9 = cd.ArrayMath(m_highData).subtract(m_lowData).expAvg(f).result()
    Dim exp99()
    exp99 = cd.ArrayMath(exp9).expAvg(f).result()

    Dim c As Object
    Set c = addLineIndicator(height, cd.ArrayMath(exp9).financeDiv(exp99, 1).movAvg(25).mul(25 _
        ).result(), color, "Mass Index")
    Call c.yAxis().addMark(27, upColor)
    Call c.yAxis().addMark(26.5, downColor)
    Set addMassIndex = c
    Exit Function
End Function

'/ <summary>
'/ Add a Money Flow Index indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <param name="range">The distance beween the middle line and the upper and lower threshold lines.</param>
'/ <param name="upColor">The fill color when the indicator exceeds the upper threshold line.</param>
'/ <param name="downColor">The fill color when the indicator falls below the lower threshold line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addMFI(height, period, color, range, upColor, downColor)
    'Money Flow Index
    Dim typicalPrice()
    typicalPrice = cd.ArrayMath(m_highData).add(m_lowData).add(m_closeData).div(3).result()
    Dim moneyFlow()
    moneyFlow = cd.ArrayMath(typicalPrice).mul(m_volData).result()

    Dim selector()
    selector = cd.ArrayMath(typicalPrice).delta().result()
    Dim posMoneyFlow()
    posMoneyFlow = cd.ArrayMath(moneyFlow).selectGTZ(selector).movAvg(period).result()
    Dim posNegMoneyFlow()
    posNegMoneyFlow = cd.ArrayMath(moneyFlow).selectLTZ(selector).movAvg(period).add(posMoneyFlow _
        ).result()

    Dim c As Object
    Set c = addIndicator(height)
    Dim label As String
    label = "Money Flow Index (" & period & ")"
    Dim layer As Object
    Set layer = addLineIndicator2(c, cd.ArrayMath(posMoneyFlow).financeDiv(posNegMoneyFlow, 0.5 _
        ).mul(100).result(), color, label)
    Call addThreshold(c, layer, 50 + range, upColor, 50 - range, downColor)

    Call c.yAxis().setLinearScale(0, 100)
    Set addMFI = c
    Exit Function
End Function

'/ <summary>
'/ Add a Momentum indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addMomentum(height, period, color)
    Dim label As String
    label = "Momentum (" & period & ")"
    Set addMomentum = addLineIndicator(height, cd.ArrayMath(m_closeData).delta(period).result(), _
        color, label)
    Exit Function
End Function

'/ <summary>
'/ Add a Negative Volume Index indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the signal line.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <param name="signalColor">The color of the signal line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addNVI(height, period, color, signalColor)
    ReDim nvi(UBound(m_volData))

    Dim previousNVI As Double
    previousNVI = 100
    Dim previousVol As Double
    previousVol = cd.NoValue
    Dim previousClose As Double
    previousClose = cd.NoValue
    Dim i As Long
    For i = 0 To UBound(m_volData)
        If m_volData(i) = cd.NoValue Then
            nvi(i) = cd.NoValue
        Else
            If (previousVol <> cd.NoValue) And (m_volData(i) < previousVol) And (previousClose <> _
                cd.NoValue) And (m_closeData(i) <> cd.NoValue) Then
                nvi(i) = previousNVI + previousNVI * (m_closeData(i) - previousClose) / _
                    previousClose
            Else
                nvi(i) = previousNVI
            End If

            previousNVI = nvi(i)
            previousVol = m_volData(i)
            previousClose = m_closeData(i)
        End If
    Next

    Dim c As Object
    Set c = addLineIndicator(height, nvi, color, "NVI")
    If UBound(nvi) + 1 > period Then
        Dim label As String
        label = "NVI SMA (" & period & ")"
        Call addLineIndicator2(c, cd.ArrayMath(nvi).movAvg(period).result(), signalColor, label)
    End If
    Set addNVI = c
    Exit Function
End Function

'/ <summary>
'/ Add an On Balance Volume indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addOBV(height, color)
    Dim closeChange()
    closeChange = cd.ArrayMath(m_closeData).delta().result()
    Dim upVolume()
    upVolume = cd.ArrayMath(m_volData).selectGTZ(closeChange).result()
    Dim downVolume()
    downVolume = cd.ArrayMath(m_volData).selectLTZ(closeChange).result()

    Set addOBV = addLineIndicator(height, cd.ArrayMath(upVolume).subtract(downVolume).acc( _
        ).result(), color, "OBV")
    Exit Function
End Function

'/ <summary>
'/ Add a Performance indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addPerformance(height, color)
    Dim closeValue As Double
    closeValue = firstCloseValue()
    If closeValue <> cd.NoValue Then
        Set addPerformance = addLineIndicator(height, cd.ArrayMath(m_closeData).mul(100 / _
            closeValue).subtract(100).result(), color, "Performance")
        Exit Function
    Else
        'chart is empty !!!
        Set addPerformance = addIndicator(height)
        Exit Function
    End If
End Function

'/ <summary>
'/ Add a Percentage Price Oscillator indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period1">The first moving average period to compute the indicator.</param>
'/ <param name="period2">The second moving average period to compute the indicator.</param>
'/ <param name="period3">The moving average period of the signal line.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <param name="signalColor">The color of the signal line.</param>
'/ <param name="divColor">The color of the divergent bars.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addPPO(height, period1, period2, period3, color, signalColor, divColor)
    Dim expAvg1()
    expAvg1 = cd.ArrayMath(m_closeData).expAvg(2.0 / (period1 + 1)).result()
    Dim expAvg2()
    expAvg2 = cd.ArrayMath(m_closeData).expAvg(2.0 / (period2 + 1)).result()
    Dim ppo As Object
    Set ppo = cd.ArrayMath(expAvg2).subtract(expAvg1).financeDiv(expAvg2, 0).mul(100)
    Dim ppoSignal()
    ppoSignal = cd.ArrayMath(ppo.result()).expAvg(2.0 / (period3 + 1)).result()

    Dim label1 As String
    label1 = "PPO (" & period1 & ", " & period2 & ")"
    Dim label2 As String
    label2 = "EMA (" & period3 & ")"
    Dim c As Object
    Set c = addLineIndicator(height, ppo.result(), color, label1)
    Call addLineIndicator2(c, ppoSignal, signalColor, label2)
    Call addBarIndicator2(c, ppo.subtract(ppoSignal).result(), divColor, "Divergence")
    Set addPPO = c
    Exit Function
End Function

'/ <summary>
'/ Add a Positive Volume Index indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the signal line.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <param name="signalColor">The color of the signal line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addPVI(height, period, color, signalColor)
    'Positive Volume Index
    ReDim pvi(UBound(m_volData))

    Dim previousPVI As Double
    previousPVI = 100
    Dim previousVol As Double
    previousVol = cd.NoValue
    Dim previousClose As Double
    previousClose = cd.NoValue
    Dim i As Long
    For i = 0 To UBound(m_volData)
        If m_volData(i) = cd.NoValue Then
            pvi(i) = cd.NoValue
        Else
            If (previousVol <> cd.NoValue) And (m_volData(i) > previousVol) And (previousClose <> _
                cd.NoValue) And (m_closeData(i) <> cd.NoValue) Then
                pvi(i) = previousPVI + previousPVI * (m_closeData(i) - previousClose) / _
                    previousClose
            Else
                pvi(i) = previousPVI
            End If

            previousPVI = pvi(i)
            previousVol = m_volData(i)
            previousClose = m_closeData(i)
        End If
    Next

    Dim c As Object
    Set c = addLineIndicator(height, pvi, color, "PVI")
    If UBound(pvi) + 1 > period Then
        Dim label As String
        label = "PVI SMA (" & period & ")"
        Call addLineIndicator2(c, cd.ArrayMath(pvi).movAvg(period).result(), signalColor, label)
    End If
    Set addPVI = c
    Exit Function
End Function

'/ <summary>
'/ Add a Percentage Volume Oscillator indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period1">The first moving average period to compute the indicator.</param>
'/ <param name="period2">The second moving average period to compute the indicator.</param>
'/ <param name="period3">The moving average period of the signal line.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <param name="signalColor">The color of the signal line.</param>
'/ <param name="divColor">The color of the divergent bars.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addPVO(height, period1, period2, period3, color, signalColor, divColor)
    Dim expAvg1()
    expAvg1 = cd.ArrayMath(m_volData).expAvg(2.0 / (period1 + 1)).result()
    Dim expAvg2()
    expAvg2 = cd.ArrayMath(m_volData).expAvg(2.0 / (period2 + 1)).result()
    Dim pvo As Object
    Set pvo = cd.ArrayMath(expAvg2).subtract(expAvg1).financeDiv(expAvg2, 0).mul(100)
    Dim pvoSignal()
    pvoSignal = cd.ArrayMath(pvo.result()).expAvg(2.0 / (period3 + 1)).result()

    Dim label1 As String
    label1 = "PVO (" & period1 & ", " & period2 & ")"
    Dim label2 As String
    label2 = "EMA (" & period3 & ")"
    Dim c As Object
    Set c = addLineIndicator(height, pvo.result(), color, label1)
    Call addLineIndicator2(c, pvoSignal, signalColor, label2)
    Call addBarIndicator2(c, pvo.subtract(pvoSignal).result(), divColor, "Divergence")
    Set addPVO = c
    Exit Function
End Function

'/ <summary>
'/ Add a Price Volumne Trend indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addPVT(height, color)
    Set addPVT = addLineIndicator(height, cd.ArrayMath(m_closeData).rate().subtract(1).mul( _
        m_volData).acc().result(), color, "PVT")
    Exit Function
End Function

'/ <summary>
'/ Add a Rate of Change indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addROC(height, period, color)
    Dim label As String
    label = "ROC (" & period & ")"
    Set addROC = addLineIndicator(height, cd.ArrayMath(m_closeData).rate(period).subtract(1).mul( _
        100).result(), color, label)
    Exit Function
End Function

Private Function RSIMovAvg(data, period)
    'The "moving average" in classical RSI is based on a formula that mixes simple
    'and exponential moving averages.

    If period <= 0 Then
        period = 1
    End If

    Dim count As Long
    count = 0
    Dim acc As Double
    acc = 0

    Dim i As Long
    For i = 0 To UBound(data)
        If Abs(data(i) / cd.NoValue - 1) > 1e-005 Then
            count = count + 1
            acc = acc + data(i)
            If count < period Then
                data(i) = cd.NoValue
            Else
                data(i) = acc / period
                acc = data(i) * (period - 1)
            End If
        End If
    Next

    RSIMovAvg = data
    Exit Function
End Function

Private Function computeRSI(period)
    'RSI is defined as the average up changes for the last 14 days, divided by the
    'average absolute changes for the last 14 days, expressed as a percentage.

    Dim absChange()
    absChange = RSIMovAvg(cd.ArrayMath(m_closeData).delta().absolute().result(), period)
    Dim absUpChange()
    absUpChange = RSIMovAvg(cd.ArrayMath(m_closeData).delta().selectGTZ().result(), period)
    computeRSI = cd.ArrayMath(absUpChange).financeDiv(absChange, 0.5).mul(100).result()
    Exit Function
End Function

'/ <summary>
'/ Add a Relative Strength Index indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <param name="range">The distance beween the middle line and the upper and lower threshold lines.</param>
'/ <param name="upColor">The fill color when the indicator exceeds the upper threshold line.</param>
'/ <param name="downColor">The fill color when the indicator falls below the lower threshold line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addRSI(height, period, color, range, upColor, downColor)
    Dim c As Object
    Set c = addIndicator(height)
    Dim label As String
    label = "RSI (" & period & ")"
    Dim layer As Object
    Set layer = addLineIndicator2(c, computeRSI(period), color, label)

    'Add range if given
    If (range > 0) And (range < 50) Then
        Call addThreshold(c, layer, 50 + range, upColor, 50 - range, downColor)
    End If
    Call c.yAxis().setLinearScale(0, 100)
    Set addRSI = c
    Exit Function
End Function

'/ <summary>
'/ Add a Slow Stochastic indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period1">The period to compute the %K line.</param>
'/ <param name="period2">The period to compute the %D line.</param>
'/ <param name="color1">The color of the %K line.</param>
'/ <param name="color2">The color of the %D line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addSlowStochastic(height, period1, period2, color1, color2)
    Dim movLow()
    movLow = cd.ArrayMath(m_lowData).movMin(period1).result()
    Dim movRange()
    movRange = cd.ArrayMath(m_highData).movMax(period1).subtract(movLow).result()
    Dim stochastic As Object
    Set stochastic = cd.ArrayMath(m_closeData).subtract(movLow).financeDiv(movRange, 0.5).mul(100 _
        ).movAvg(3)

    Dim label1 As String
    label1 = "Slow Stochastic %K (" & period1 & ")"
    Dim label2 As String
    label2 = "%D (" & period2 & ")"
    Dim c As Object
    Set c = addLineIndicator(height, stochastic.result(), color1, label1)
    Call addLineIndicator2(c, stochastic.movAvg(period2).result(), color2, label2)

    Call c.yAxis().setLinearScale(0, 100)
    Set addSlowStochastic = c
    Exit Function
End Function

'/ <summary>
'/ Add a Moving Standard Deviation indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addStdDev(height, period, color)
    Dim label As String
    label = "Moving StdDev (" & period & ")"
    Set addStdDev = addLineIndicator(height, cd.ArrayMath(m_closeData).movStdDev(period).result(), _
        color, label)
    Exit Function
End Function

'/ <summary>
'/ Add a Stochastic RSI indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <param name="range">The distance beween the middle line and the upper and lower threshold lines.</param>
'/ <param name="upColor">The fill color when the indicator exceeds the upper threshold line.</param>
'/ <param name="downColor">The fill color when the indicator falls below the lower threshold line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addStochRSI(height, period, color, range, upColor, downColor)
    Dim rsi()
    rsi = computeRSI(period)
    Dim movLow()
    movLow = cd.ArrayMath(rsi).movMin(period).result()
    Dim movRange()
    movRange = cd.ArrayMath(rsi).movMax(period).subtract(movLow).result()

    Dim c As Object
    Set c = addIndicator(height)
    Dim label As String
    label = "StochRSI (" & period & ")"
    Dim layer As Object
    Set layer = addLineIndicator2(c, cd.ArrayMath(rsi).subtract(movLow).financeDiv(movRange, 0.5 _
        ).mul(100).result(), color, label)

    'Add range if given
    If (range > 0) And (range < 50) Then
        Call addThreshold(c, layer, 50 + range, upColor, 50 - range, downColor)
    End If
    Call c.yAxis().setLinearScale(0, 100)
    Set addStochRSI = c
    Exit Function
End Function

'/ <summary>
'/ Add a TRIX indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addTRIX(height, period, color)
    Dim f As Double
    f = 2.0 / (period + 1)
    Dim label As String
    label = "TRIX (" & period & ")"
    Set addTRIX = addLineIndicator(height, cd.ArrayMath(m_closeData).expAvg(f).expAvg(f).expAvg(f _
        ).rate().subtract(1).mul(100).result(), color, label)
    Exit Function
End Function

Private Function computeTrueLow()
    'the lower of today's low or yesterday's close.
    Dim previousClose()
    previousClose = cd.ArrayMath(m_closeData).shift().result()
    ReDim ret(UBound(m_lowData))
    Dim i As Long
    For i = 0 To UBound(m_lowData)
        If (m_lowData(i) <> cd.NoValue) And (previousClose(i) <> cd.NoValue) Then
            If m_lowData(i) < previousClose(i) Then
                ret(i) = m_lowData(i)
            Else
                ret(i) = previousClose(i)
            End If
        Else
            ret(i) = cd.NoValue
        End If
    Next

    computeTrueLow = ret
    Exit Function
End Function

'/ <summary>
'/ Add an Ultimate Oscillator indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period1">The first moving average period to compute the indicator.</param>
'/ <param name="period2">The second moving average period to compute the indicator.</param>
'/ <param name="period3">The third moving average period to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <param name="range">The distance beween the middle line and the upper and lower threshold lines.</param>
'/ <param name="upColor">The fill color when the indicator exceeds the upper threshold line.</param>
'/ <param name="downColor">The fill color when the indicator falls below the lower threshold line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addUltimateOscillator(height, period1, period2, period3, color, range, upColor, _
    downColor)
    Dim trueLow()
    trueLow = computeTrueLow()
    Dim buyingPressure()
    buyingPressure = cd.ArrayMath(m_closeData).subtract(trueLow).result()
    Dim trueRange()
    trueRange = computeTrueRange()

    Dim rawUO1()
    rawUO1 = cd.ArrayMath(buyingPressure).movAvg(period1).financeDiv(cd.ArrayMath(trueRange _
        ).movAvg(period1).result(), 0.5).mul(4).result()
    Dim rawUO2()
    rawUO2 = cd.ArrayMath(buyingPressure).movAvg(period2).financeDiv(cd.ArrayMath(trueRange _
        ).movAvg(period2).result(), 0.5).mul(2).result()
    Dim rawUO3()
    rawUO3 = cd.ArrayMath(buyingPressure).movAvg(period3).financeDiv(cd.ArrayMath(trueRange _
        ).movAvg(period3).result(), 0.5).mul(1).result()

    Dim c As Object
    Set c = addIndicator(height)
    Dim label As String
    label = "Ultimate Oscillator (" & period1 & ", " & period2 & ", " & period3 & ")"
    Dim layer As Object
    Set layer = addLineIndicator2(c, cd.ArrayMath(rawUO1).add(rawUO2).add(rawUO3).mul(100.0 / 7 _
        ).result(), color, label)
    Call addThreshold(c, layer, 50 + range, upColor, 50 - range, downColor)

    Call c.yAxis().setLinearScale(0, 100)
    Set addUltimateOscillator = c
    Exit Function
End Function

'/ <summary>
'/ Add a Volume indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="upColor">The color to used on an 'up' day. An 'up' day is a day where
'/ the closing price is higher than that of the previous day.</param>
'/ <param name="downColor">The color to used on a 'down' day. A 'down' day is a day
'/ where the closing price is lower than that of the previous day.</param>
'/ <param name="flatColor">The color to used on a 'flat' day. A 'flat' day is a day
'/ where the closing price is the same as that of the previous day.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addVolIndicator(height, upColor, downColor, flatColor)
    Dim c As Object
    Set c = addIndicator(height)
    Call addVolBars2(c, height, upColor, downColor, flatColor)
    Set addVolIndicator = c
    Exit Function
End Function

'/ <summary>
'/ Add a William %R indicator chart.
'/ </summary>
'/ <param name="height">The height of the indicator chart in pixels.</param>
'/ <param name="period">The period to compute the indicator.</param>
'/ <param name="color">The color of the indicator line.</param>
'/ <param name="range">The distance beween the middle line and the upper and lower threshold lines.</param>
'/ <param name="upColor">The fill color when the indicator exceeds the upper threshold line.</param>
'/ <param name="downColor">The fill color when the indicator falls below the lower threshold line.</param>
'/ <returns>The XYChart object representing the chart created.</returns>
Public Function addWilliamR(height, period, color, range, upColor, downColor)
    Dim movLow()
    movLow = cd.ArrayMath(m_lowData).movMin(period).result()
    Dim movHigh()
    movHigh = cd.ArrayMath(m_highData).movMax(period).result()
    Dim movRange()
    movRange = cd.ArrayMath(movHigh).subtract(movLow).result()

    Dim c As Object
    Set c = addIndicator(height)
    Dim layer As Object
    Set layer = addLineIndicator2(c, cd.ArrayMath(movHigh).subtract(m_closeData).financeDiv( _
        movRange, 0.5).mul(-100).result(), color, "William %R")
    Call addThreshold(c, layer, -50 + range, upColor, -50 - range, downColor)
    Call c.yAxis().setLinearScale(-100, 0)
    Set addWilliamR = c
    Exit Function
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'	As VB/COM does not support inheritance, we need to copy the API for the
'	base class MultiChart here for inheritance
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub addChart(x, y, c)
    Call Base.addChart(x, y, c)
End Sub
Sub setMainChart(c)
    Call Base.setMainChart(c)
End Sub
Sub enableVectorOutput()
    Call Base.enableVectorOutput()
End Sub
Sub setSize(width, height)
    Call Base.setSize(width, height)
End Sub
Function getWidth()
    getWidth = Base.getWidth()
End Function
Function getHeight()
    getHeight = Base.getHeight()
End Function
Sub setBorder(color)
    Call Base.setBorder(color)
End Sub
Sub setBackground(bgColor, Optional edgeColor = -1, Optional raisedEffect = 0)
    Call Base.setBackground(bgColor, edgeColor, raisedEffect)
End Sub
Sub setWallpaper(img)
    Call Base.setWallpaper(img)
End Sub
Sub setBgImage(img, Optional align = 5)
    Call Base.setBgImage(img, align)
End Sub
Sub setRoundedFrame(Optional extColor = &HFFFFFF, Optional r1 = 10, Optional r2 = -1, Optional r3 = -1, Optional r4 = -1)
    Call Base.setRoundedFrame(extColor, r1, r2, r3, r4)
End Sub
Sub setDropShadow(Optional color = &HAAAAAA, Optional offsetX = 5, Optional offsetY = &H7FFFFFFF, Optional blurRadius = 5)
    Call Base.setDropShadow(color, offsetX, offsetY, blurRadius)
End Sub
Function getChartMetrics()
    getChartMetrics = Base.getChartMetrics()
End Function
Sub setTransparentColor(c)
    Call Base.setTransparentColor(c)
End Sub
Sub setAntiAlias(Optional antiAliasShape = True, Optional antiAliasText = 2)
    Call Base.setAntiAlias(antiAliasShape, antiAliasText)
End Sub
Sub setSearchPath(path)
    Call Base.setSearchPath(path)
End Sub
Function addTitle2(alignment, text, Optional font = "", Optional fontSize = 12, Optional fontcolor = &HFFFF0002, Optional bgColor = &HFF000000, Optional edgeColor = &HFF000000)
    Set addTitle2 = Base.addTitle2(alignment, text, font, fontSize, fontcolor, bgColor, edgeColor)
End Function
Function addTitle(text, Optional font = "", Optional fontSize = 12, Optional fontcolor = &HFFFF0002, Optional bgColor = &HFF000000, Optional edgeColor = &HFF000000)
    Set addTitle = Base.addTitle(text, font, fontSize, fontcolor, bgColor, edgeColor)
End Function
Function addLegend(x, y, Optional vertical = True, Optional font = "", Optional fontSize = 10)
    Set addLegend = Base.addLegend(x, y, vertical, font, fontSize)
End Function
Function getLegend()
    Set getLegend = Base.getLegend()
End Function
Function getDrawArea()
    Set getDrawArea = Base.getDrawArea()
End Function
Function addText(x, y, text, Optional font = "", Optional fontSize = 8, Optional fontcolor = &HFFFF0002, Optional alignment = 7, Optional angle = 0, Optional vertical = False)
    Set addText = Base.addText(x, y, text, font, fontSize, fontcolor, alignment, angle, vertical)
End Function
Function addLine(x1, y1, x2, y2, Optional color = &HFFFF0001, Optional lineWidth = 1)
    Set addLine = Base.addLine(x1, y1, x2, y2, color, lineWidth)
End Function
Function addTable(x, y, alignment, col, row)
    Set addTable = Base.addTable(x, y, alignment, col, row)
End Function
Sub setColor(paletteEntry, color)
    Call Base.setColor(paletteEntry, color)
End Sub
Sub setColors(colors)
    Call Base.setColors(colors)
End Sub
Sub setColors2(paletteEntry, colors)
    Call Base.setColors2(paletteEntry, colors)
End Sub
Function getColor(paletteEntry)
    getColor = Base.getColor(paletteEntry)
End Function
Function halfColor()
    halfColor = Base.halfColor()
End Function
Function adjustBrightness(c, brightness)
    adjustBrightness = Base.adjustBrightness(c, brightness)
End Function
Function autoColor()
    autoColor = Base.autoColor()
End Function
Function dashLineColor(color, patternCode)
    dashLineColor = Base.dashLineColor(color, patternCode)
End Function
Function gradientColor(startX, startY, endX, endY, startColor, endColor)
    gradientColor = Base.gradientColor(startX, startY, endX, endY, startColor, endColor)
End Function
Function gradientColor2(c, Optional angle = 90, Optional scale1 = 1, Optional startX = 0, Optional startY = 0)
    gradientColor2 = Base.gradientColor2(c, angle, scale1, startX, startY)
End Function
Function linearGradientColor(startX, startY, endX, endY, startColor, endColor, Optional periodic = False)
    linearGradientColor = Base.linearGradientColor(startX, startY, endX, endY, startColor, endColor, periodic)
End Function
Function linearGradientColor2(startX, startY, endX, endY, c, Optional periodic = False)
    linearGradientColor2 = Base.linearGradientColor2(startX, startY, endX, endY, c, periodic)
End Function
Function radialGradientColor(cx, cy, rx, ry, startColor, endColor, Optional periodic = False)
    radialGradientColor = Base.radialGradientColor(cx, cy, rx, ry, startColor, endColor, periodic)
End Function
Function radialGradientColor2(cx, cy, rx, ry, c, Optional periodic = False)
    radialGradientColor2 = Base.radialGradientColor2(cx, cy, rx, ry, c, periodic)
End Function
Function patternColor(c, h, Optional startX, Optional startY)
    patternColor = Base.patternColor(c, h, startX, startY)
End Function
Function patternColor2(fileName, Optional startX = 0, Optional startY = 0)
    patternColor2 = Base.patternColor2(fileName, startX, startY)
End Function
Sub setDefaultFonts(normal, Optional bold, Optional italic, Optional boldItalic)
    Call Base.setDefaultFonts(normal, bold, italic, boldItalic)
End Sub
Sub setFontTable(index, font)
    Call Base.setFontTable(index, font)
End Sub
Sub setNumberFormat(Optional thousandSeparator = "~", Optional decimalPointChar = ".", Optional signChar = "-")
    Call Base.setNumberFormat(thousandSeparator, decimalPointChar, signChar)
End Sub
Sub setMonthNames(names)
    Call Base.setMonthNames(names)
End Sub
Sub setWeekDayNames(names)
    Call Base.setWeekDayNames(names)
End Sub
Sub setAMPM(AM, PM)
    Call Base.setAMPM(AM, PM)
End Sub
Sub layout()
    Call Base.layout()
End Sub
Function makeChart(fileName)
    makeChart = Base.makeChart(fileName)
End Function
Function makeChart2(format)
    makeChart2 = Base.makeChart2(format)
End Function
Function makeChart3()
    Set makeChart3 = Base.makeChart3()
End Function
Function makePicture() As IPicture
    Set makePicture = Base.makePicture()
End Function
Function makeSession(sess, id, Optional imageType = 0)
    makeSession = Base.makeSession(sess, id, imageType)
End Function
Function makeTmpFile(dirname, Optional imageType = 0, Optional timeout = 600)
	makeTmpFile = Base.makeTmpFile(dirname, imageType, timeout)
End Function
Function getHTMLImageMap(url, Optional queryFormat, Optional extraAttr, Optional offsetX, Optional offsetY)
    getHTMLImageMap = Base.getHTMLImageMap(url, queryFormat, extraAttr, offsetX, offsetY)
End Function
Sub addExtraField(texts)
    Call Base.addExtraField(texts)
End Sub
Sub addExtraField2(numbers)
    Call Base.addExtraField2(numbers)
End Sub
Function addLegend2(x, y, noOfCols, Optional font = "", Optional fontHeight = 10)
    Set addLegend2 = Base.addLegend2(x, y, noOfCols, font, fontHeight)
End Function
Function formatValue(value, formatString)
    formatValue = Base.formatValue(value, formatString)
End Function
Function layoutLegend()
    Set layoutLegend = Base.layoutLegend()
End Function

Function getAbsOffsetX()
    getAbsOffsetX = Base.getAbsOffsetX()
End Function
Function getAbsOffsetY()
    getAbsOffsetY = Base.getAbsOffsetY()
End Function
Function initDynamicLayer()
    Set initDynamicLayer = Base.initDynamicLayer()
End Function
Sub removeDynamicLayer()
    Call Base.removeDynamicLayer()
End Sub
Function getJsChartModel(Optional options = "")
    getJsChartModel = Base.getJsChartModel(options)
End Function