#/ Represents a Financial Chart #/ class FinanceChart extends MultiChart { var $m_totalWidth = 0; var $m_totalHeight = 0; var $m_antiAlias = true; var $m_logScale = false; var $m_axisOnRight = true; var $m_leftMargin = 40; var $m_rightMargin = 40; var $m_topMargin = 30; var $m_bottomMargin = 35; var $m_plotAreaBgColor = 0xfffff0; var $m_majorHGridColor = 0xdddddd; var $m_minorHGridColor = 0xdddddd; var $m_majorVGridColor = 0xdddddd; var $m_minorVGridColor = 0xdddddd; var $m_legendFont = "normal"; var $m_legendFontSize = 8; var $m_legendFontColor = TextColor; var $m_legendBgColor = 0x80ccccff; var $m_yAxisFont = "normal"; var $m_yAxisFontSize = 8; var $m_yAxisFontColor = TextColor; var $m_yAxisMargin = 13; var $m_xAxisFont = "normal"; var $m_xAxisFontSize = 8; var $m_xAxisFontColor = TextColor; var $m_xAxisFontAngle = 0; var $m_timeStamps = null; var $m_highData = null; var $m_lowData = null; var $m_openData = null; var $m_closeData = null; var $m_volData = null; var $m_volUnit = ""; var $m_extraPoints = 0; var $m_yearFormat = "{value|yyyy}"; var $m_firstMonthFormat = "<*font=bold*>{value|mmm yy}"; var $m_otherMonthFormat = "{value|mmm}"; var $m_firstDayFormat = "<*font=bold*>{value|d mmm}"; var $m_otherDayFormat = "{value|d}"; var $m_firstHourFormat = "<*font=bold*>{value|d mmm\nh:nna}"; var $m_otherHourFormat = "{value|h:nna}"; var $m_timeLabelSpacing = 50; var $m_generalFormat = "G"; var $m_toolTipMonthFormat = "[{xLabel|mmm yyyy}]"; var $m_toolTipDayFormat = "[{xLabel|mmm d, yyyy}]"; var $m_toolTipHourFormat = "[{xLabel|mmm d, yyyy hh:nn:ss}]"; var $m_mainChart = null; var $m_currentChart = null; #/ #/ Create a FinanceChart with a given width. The height will be automatically determined #/ as the chart is built. #/ #/ Width of the chart in pixels function FinanceChart($width) { $this->MultiChart($width, 1); $this->m_totalWidth = $width; } #/ #/ 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. #/ #/ True to enable anti-alias. False to disable anti-alias. function enableAntiAlias($antiAlias) { $this->m_antiAlias = $antiAlias; } #/ #/ Set the margins around the plot area. #/ #/ The distance between the plot area and the chart left edge. #/ The distance between the plot area and the chart top edge. #/ The distance between the plot area and the chart right edge. #/ The distance between the plot area and the chart bottom edge. function setMargins($leftMargin, $topMargin, $rightMargin, $bottomMargin) { $this->m_leftMargin = $leftMargin; $this->m_rightMargin = $rightMargin; $this->m_topMargin = $topMargin; $this->m_bottomMargin = $bottomMargin; } #/ #/ Add a text title above the plot area. You may add multiple title above the plot area by #/ calling this method multiple times. #/ #/ The alignment with respect to the region that is on top of the #/ plot area. #/ The text to add. #/ The TextBox object representing the text box above the plot area. function addPlotAreaTitle($alignment, $text) { $ret = $this->addText($this->m_leftMargin, 0, $text, "bold", 10, TextColor, $alignment); $ret->setSize($this->m_totalWidth - $this->m_leftMargin - $this->m_rightMargin + 1, $this->m_topMargin - 1); $ret->setMargin(0); return $ret; } #/ #/ Set the plot area style. The default is to use pale yellow 0xfffff0 as the background, #/ and light grey 0xdddddd as the grid lines. #/ #/ The plot area background color. #/ Major horizontal grid color. #/ Major vertical grid color. #/ Minor horizontal grid color. In current version, minor #/ horizontal grid is not used. #/ Minor vertical grid color. function setPlotAreaStyle($bgColor, $majorHGridColor, $majorVGridColor, $minorHGridColor, $minorVGridColor) { $this->m_plotAreaBgColor = $bgColor; $this->m_majorHGridColor = $majorHGridColor; $this->m_majorVGridColor = $majorVGridColor; $this->m_minorHGridColor = $minorHGridColor; $this->m_minorVGridColor = $minorVGridColor; } #/ #/ Set legend style. The default is Arial 8 pt black color, with light grey background. #/ #/ The font of the legend text. #/ The font size of the legend text in points. #/ The color of the legend text. #/ The background color of the legend box. function setLegendStyle($font, $fontSize, $fontColor, $bgColor) { $this->m_legendFont = $font; $this->m_legendFontSize = $fontSize; $this->m_legendFontColor = $fontColor; $this->m_legendBgColor = $bgColor; } #/ #/ Set x-axis label style. The default is Arial 8 pt black color no rotation. #/ #/ The font of the axis labels. #/ The font size of the axis labels in points. #/ The color of the axis labels. #/ The rotation of the axis labels. function setXAxisStyle($font, $fontSize, $fontColor, $fontAngle) { $this->m_xAxisFont = $font; $this->m_xAxisFontSize = $fontSize; $this->m_xAxisFontColor = $fontColor; $this->m_xAxisFontAngle = $fontAngle; } #/ #/ Set y-axis label style. The default is Arial 8 pt black color, with 13 pixels margin. #/ #/ The font of the axis labels. #/ The font size of the axis labels in points. #/ The color of the axis labels. #/ The margin at the top of the y-axis in pixels (to leave #/ space for the legend box). function setYAxisStyle($font, $fontSize, $fontColor, $axisMargin) { $this->m_yAxisFont = $font; $this->m_yAxisFontSize = $fontSize; $this->m_yAxisFontColor = $fontColor; $this->m_yAxisMargin = $axisMargin; } #/ #/ Set whether the main y-axis is on right of left side of the plot area. The default is #/ on right. #/ #/ True if the y-axis is on right. False if the y-axis is on left. function setAxisOnRight($b) { $this->m_axisOnRight = $b; } #/ #/ Determines if log scale should be used for the main chart. The default is linear scale. #/ #/ True for using log scale. False for using linear scale. function setLogScale($b) { $this->m_logScale = $b; if ($this->m_mainChart != null) { if ($this->m_logScale) { $this->m_mainChart->yAxis->setLogScale(); } else { $this->m_mainChart->yAxis->setLinearScale(); } } } #/ #/ Set the date/time formats to use for the x-axis labels under various cases. #/ #/ The format for displaying labels on an axis with yearly ticks. The #/ default is "yyyy". #/ 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. #/ 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. #/ 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. #/ 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. #/ 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. #/ 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. function setDateLabelFormat($yearFormat, $firstMonthFormat, $otherMonthFormat, $firstDayFormat, $otherDayFormat, $firstHourFormat, $otherHourFormat) { if ($yearFormat != null) { $this->m_yearFormat = $yearFormat; } if ($firstMonthFormat != null) { $this->m_firstMonthFormat = $firstMonthFormat; } if ($otherMonthFormat != null) { $this->m_otherMonthFormat = $otherMonthFormat; } if ($firstDayFormat != null) { $this->m_firstDayFormat = $firstDayFormat; } if ($otherDayFormat != null) { $this->m_otherDayFormat = $otherDayFormat; } if ($firstHourFormat != null) { $this->m_firstHourFormat = $firstHourFormat; } if ($otherHourFormat != null) { $this->m_otherHourFormat = $otherHourFormat; } } #/ #/ Set the minimum label spacing between two labels on the time axis #/ #/ The minimum label spacing in pixels. function setDateLabelSpacing($labelSpacing) { if ($labelSpacing > 0) { $this->m_timeLabelSpacing = $labelSpacing; } else { $this->m_timeLabelSpacing = 0; } } #/ #/ Set the tool tip formats for display date/time #/ #/ The tool tip format to use if the data point spacing is one #/ or more months (more than 30 days). #/ The tool tip format to use if the data point spacing is 1 day #/ to less than 30 days. #/ The tool tip format to use if the data point spacing is less #/ than 1 day. function setToolTipDateFormat($monthFormat, $dayFormat, $hourFormat) { if ($monthFormat != null) { $this->m_toolTipMonthFormat = $monthFormat; } if ($dayFormat != null) { $this->m_toolTipDayFormat = $dayFormat; } if ($hourFormat != null) { $this->m_toolTipHourFormat = $hourFormat; } } #/ #/ Get the tool tip format for display date/time #/ #/ The tool tip format string. function getToolTipDateFormat() { if ($this->m_timeStamps == null) { return $this->m_toolTipHourFormat; } if (count($this->m_timeStamps) <= $this->m_extraPoints) { return $this->m_toolTipHourFormat; } $resolution = ($this->m_timeStamps[count($this->m_timeStamps) - 1] - $this->m_timeStamps[0]) / count($this->m_timeStamps); if ($resolution >= 30 * 86400) { return $this->m_toolTipMonthFormat; } else if ($resolution >= 86400) { return $this->m_toolTipDayFormat; } else { return $this->m_toolTipHourFormat; } } #/ #/ Set the number format for use in displaying values in legend keys and tool tips. #/ #/ The default number format. function setNumberLabelFormat($formatString) { if ($formatString != null) { $this->m_generalFormat = $formatString; } } #/ #/ A utility function to compute triangular moving averages #/ #/ An array of numbers as input. #/ The moving average period. #/ An array representing the triangular moving average of the input array. function computeTriMovingAvg($data, $period) { $p = $period / 2 + 1; $tmpArrayMath1 = new ArrayMath($data); $tmpArrayMath1->movAvg($p); $tmpArrayMath1->movAvg($p); return $tmpArrayMath1->result(); } #/ #/ A utility function to compute weighted moving averages #/ #/ An array of numbers as input. #/ The moving average period. #/ An array representing the weighted moving average of the input array. function computeWeightedMovingAvg($data, $period) { $acc = new ArrayMath($data); for($i = 2; $i < $period + 1; ++$i) { $tmpArrayMath1 = new ArrayMath($data); $tmpArrayMath1->movAvg($i); $tmpArrayMath1->mul($i); $acc->add($tmpArrayMath1->result()); } $divObj = $acc->div((1 + $period) * $period / 2); return $divObj->result(); } #/ #/ A utility function to obtain the last valid position (that is, position not #/ containing cd.NoValue) of a data series. #/ #/ An array of numbers as input. #/ The last valid position in the input array, or -1 if all positions #/ are cd.NoValue. function lastIndex($data) { $i = count($data) - 1; while ($i >= 0) { if ($data[$i] != NoValue) { break; } $i = $i - 1; } return $i; } #/ #/ 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. #/ #/ An array of dates/times for the time intervals. #/ The high values in the time intervals. #/ The low values in the time intervals. #/ The open values in the time intervals. #/ The close values in the time intervals. #/ The volume values in the time intervals. #/ 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. function setData($timeStamps, $highData, $lowData, $openData, $closeData, $volData, $extraPoints ) { $this->m_timeStamps = $timeStamps; $this->m_highData = $highData; $this->m_lowData = $lowData; $this->m_openData = $openData; $this->m_closeData = $closeData; if ($extraPoints > 0) { $this->m_extraPoints = $extraPoints; } else { $this->m_extraPoints = 0; } #/////////////////////////////////////////////////////////////////////// # Auto-detect volume units #/////////////////////////////////////////////////////////////////////// $tmpArrayMath1 = new ArrayMath($volData); $maxVol = $tmpArrayMath1->max(); $units = array("", "K", "M", "B"); $unitIndex = count($units) - 1; while (($unitIndex > 0) && ($maxVol < pow(1000, $unitIndex))) { $unitIndex = $unitIndex - 1; } $tmpArrayMath1 = new ArrayMath($volData); $tmpArrayMath1->div(pow(1000, $unitIndex)); $this->m_volData = $tmpArrayMath1->result(); $this->m_volUnit = $units[$unitIndex]; } #//////////////////////////////////////////////////////////////////////////// # Format x-axis labels #//////////////////////////////////////////////////////////////////////////// function setXLabels(&$a) { $a->setLabels2($this->m_timeStamps); if ($this->m_extraPoints < count($this->m_timeStamps)) { $tickStep = (int)((count($this->m_timeStamps) - $this->m_extraPoints) * $this->m_timeLabelSpacing / ($this->m_totalWidth - $this->m_leftMargin - $this->m_rightMargin)) + 1; $timeRangeInSeconds = $this->m_timeStamps[count($this->m_timeStamps) - 1] - $this->m_timeStamps[$this->m_extraPoints]; $secondsBetweenTicks = $timeRangeInSeconds / ($this->m_totalWidth - $this->m_leftMargin - $this->m_rightMargin) * $this->m_timeLabelSpacing; if ($secondsBetweenTicks * (count($this->m_timeStamps) - $this->m_extraPoints) <= $timeRangeInSeconds) { $tickStep = 1; if (count($this->m_timeStamps) > 1) { $secondsBetweenTicks = $this->m_timeStamps[count($this->m_timeStamps) - 1] - $this->m_timeStamps[count($this->m_timeStamps) - 2]; } else { $secondsBetweenTicks = 86400; } } if (($secondsBetweenTicks > 360 * 86400) || (($secondsBetweenTicks > 90 * 86400) && ( $timeRangeInSeconds >= 720 * 86400))) { #yearly ticks $a->setMultiFormat2(StartOfYearFilter(), $this->m_yearFormat, $tickStep); } else if (($secondsBetweenTicks >= 30 * 86400) || (($secondsBetweenTicks > 7 * 86400) && ($timeRangeInSeconds >= 60 * 86400))) { #monthly ticks $monthBetweenTicks = (int)($secondsBetweenTicks / 31 / 86400) + 1; $a->setMultiFormat(StartOfYearFilter(), $this->m_firstMonthFormat, StartOfMonthFilter($monthBetweenTicks), $this->m_otherMonthFormat); $a->setMultiFormat2(StartOfMonthFilter(), "-", 1, false); } else if (($secondsBetweenTicks >= 86400) || (($secondsBetweenTicks > 6 * 3600) && ( $timeRangeInSeconds >= 86400))) { #daily ticks $a->setMultiFormat(StartOfMonthFilter(), $this->m_firstDayFormat, StartOfDayFilter( 1, 0.5), $this->m_otherDayFormat, $tickStep); } else { #hourly ticks $a->setMultiFormat(StartOfDayFilter(1, 0.5), $this->m_firstHourFormat, StartOfHourFilter(1, 0.5), $this->m_otherHourFormat, $tickStep); } } } #//////////////////////////////////////////////////////////////////////////// # Create tool tip format string for showing OHLC data #//////////////////////////////////////////////////////////////////////////// function getHLOCToolTipFormat() { return sprintf("title='%s Op:{open|%s}, Hi:{high|%s}, Lo:{low|%s}, Cl:{close|%s}'", $this->getToolTipDateFormat(), $this->m_generalFormat, $this->m_generalFormat, $this->m_generalFormat, $this->m_generalFormat); } #/ #/ Add the main chart - the chart that shows the HLOC data. #/ #/ The height of the main chart in pixels. #/ An XYChart object representing the main chart created. function addMainChart($height) { $this->m_mainChart = $this->addIndicator($height); $this->setMainChart($this->m_mainChart); $this->m_mainChart->yAxis->setMargin(2 * $this->m_yAxisMargin); if ($this->m_logScale) { $this->m_mainChart->yAxis->setLogScale(); } else { $this->m_mainChart->yAxis->setLinearScale(); } return $this->m_mainChart; } #/ #/ Add a candlestick layer to the main chart. #/ #/ The candle color for an up day. #/ The candle color for a down day. #/ The CandleStickLayer created. function addCandleStick($upColor, $downColor) { $this->addOHLCLabel($upColor, $downColor, true); $ret = $this->m_mainChart->addCandleStickLayer($this->m_highData, $this->m_lowData, $this->m_openData, $this->m_closeData, $upColor, $downColor); $ret->setHTMLImageMap("", "", $this->getHLOCToolTipFormat()); if (count($this->m_highData) - $this->m_extraPoints > 60) { $ret->setDataGap(0); } if (count($this->m_highData) > $this->m_extraPoints) { $expectedWidth = ($this->m_totalWidth - $this->m_leftMargin - $this->m_rightMargin) / ( count($this->m_highData) - $this->m_extraPoints); if ($expectedWidth <= 5) { $ret->setDataWidth($expectedWidth + 1 - $expectedWidth % 2); } } return $ret; } #/ #/ Add a HLOC layer to the main chart. #/ #/ The color of the HLOC symbol for an up day. #/ The color of the HLOC symbol for a down day. #/ The HLOCLayer created. function addHLOC($upColor, $downColor) { $this->addOHLCLabel($upColor, $downColor, false); $ret = $this->m_mainChart->addHLOCLayer($this->m_highData, $this->m_lowData, $this->m_openData, $this->m_closeData); $ret->setColorMethod(HLOCUpDown, $upColor, $downColor); $ret->setHTMLImageMap("", "", $this->getHLOCToolTipFormat()); $ret->setDataGap(0); return $ret; } function addOHLCLabel($upColor, $downColor, $candleStickMode) { $i = $this->lastIndex($this->m_closeData); if ($i >= 0) { $openValue = NoValue; $closeValue = NoValue; $highValue = NoValue; $lowValue = NoValue; if ($i < count($this->m_openData)) { $openValue = $this->m_openData[$i]; } if ($i < count($this->m_closeData)) { $closeValue = $this->m_closeData[$i]; } if ($i < count($this->m_highData)) { $highValue = $this->m_highData[$i]; } if ($i < count($this->m_lowData)) { $lowValue = $this->m_lowData[$i]; } $openLabel = ""; $closeLabel = ""; $highLabel = ""; $lowLabel = ""; $delim = ""; if ($openValue != NoValue) { $openLabel = sprintf("Op:%s", $this->formatValue($openValue, $this->m_generalFormat) ); $delim = ", "; } if ($highValue != NoValue) { $highLabel = sprintf("%sHi:%s", $delim, $this->formatValue($highValue, $this->m_generalFormat)); $delim = ", "; } if ($lowValue != NoValue) { $lowLabel = sprintf("%sLo:%s", $delim, $this->formatValue($lowValue, $this->m_generalFormat)); $delim = ", "; } if ($closeValue != NoValue) { $closeLabel = sprintf("%sCl:%s", $delim, $this->formatValue($closeValue, $this->m_generalFormat)); $delim = ", "; } $label = "$openLabel$highLabel$lowLabel$closeLabel"; $useUpColor = ($closeValue >= $openValue); if ($candleStickMode != true) { $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->delta(); $closeChanges = $tmpArrayMath1->result(); $lastChangeIndex = $this->lastIndex($closeChanges); $useUpColor = ($lastChangeIndex < 0); if ($useUpColor != true) { $useUpColor = ($closeChanges[$lastChangeIndex] >= 0); } } $udcolor = $downColor; if ($useUpColor) { $udcolor = $upColor; } $legendObj = $this->m_mainChart->getLegend(); $legendObj->addKey($label, $udcolor); } } #/ #/ Add a closing price line on the main chart. #/ #/ The color of the line. #/ The LineLayer object representing the line created. function addCloseLine($color) { return $this->addLineIndicator2($this->m_mainChart, $this->m_closeData, $color, "Closing Price"); } #/ #/ Add a weight close line on the main chart. #/ #/ The color of the line. #/ The LineLayer object representing the line created. function addWeightedClose($color) { $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->add($this->m_lowData); $tmpArrayMath1->add($this->m_closeData); $tmpArrayMath1->add($this->m_closeData); $tmpArrayMath1->div(4); return $this->addLineIndicator2($this->m_mainChart, $tmpArrayMath1->result(), $color, "Weighted Close"); } #/ #/ Add a typical price line on the main chart. #/ #/ The color of the line. #/ The LineLayer object representing the line created. function addTypicalPrice($color) { $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->add($this->m_lowData); $tmpArrayMath1->add($this->m_closeData); $tmpArrayMath1->div(3); return $this->addLineIndicator2($this->m_mainChart, $tmpArrayMath1->result(), $color, "Typical Price"); } #/ #/ Add a median price line on the main chart. #/ #/ The color of the line. #/ The LineLayer object representing the line created. function addMedianPrice($color) { $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->add($this->m_lowData); $tmpArrayMath1->div(2); return $this->addLineIndicator2($this->m_mainChart, $tmpArrayMath1->result(), $color, "Median Price"); } #/ #/ Add a simple moving average line on the main chart. #/ #/ The moving average period #/ The color of the line. #/ The LineLayer object representing the line created. function addSimpleMovingAvg($period, $color) { $label = "SMA ($period)"; $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->movAvg($period); return $this->addLineIndicator2($this->m_mainChart, $tmpArrayMath1->result(), $color, $label ); } #/ #/ Add an exponential moving average line on the main chart. #/ #/ The moving average period #/ The color of the line. #/ The LineLayer object representing the line created. function addExpMovingAvg($period, $color) { $label = "EMA ($period)"; $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->expAvg(2.0 / ($period + 1)); return $this->addLineIndicator2($this->m_mainChart, $tmpArrayMath1->result(), $color, $label ); } #/ #/ Add a triangular moving average line on the main chart. #/ #/ The moving average period #/ The color of the line. #/ The LineLayer object representing the line created. function addTriMovingAvg($period, $color) { $label = "TMA ($period)"; $tmpArrayMath1 = new ArrayMath($this->computeTriMovingAvg($this->m_closeData, $period)); return $this->addLineIndicator2($this->m_mainChart, $tmpArrayMath1->result(), $color, $label ); } #/ #/ Add a weighted moving average line on the main chart. #/ #/ The moving average period #/ The color of the line. #/ The LineLayer object representing the line created. function addWeightedMovingAvg($period, $color) { $label = "WMA ($period)"; $tmpArrayMath1 = new ArrayMath($this->computeWeightedMovingAvg($this->m_closeData, $period)) ; return $this->addLineIndicator2($this->m_mainChart, $tmpArrayMath1->result(), $color, $label ); } #/ #/ 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). #/ #/ The data series for the upper band line. #/ The data series for the lower band line. #/ The color of the upper and lower band line. #/ The color to fill the region between the upper and lower band lines. #/ The name of the band. #/ An InterLineLayer object representing the filled region. function addBand($upperLine, $lowerLine, $lineColor, $fillColor, $name) { $i = count($upperLine) - 1; if ($i >= count($lowerLine)) { $i = count($lowerLine) - 1; } while ($i >= 0) { if (($upperLine[$i] != NoValue) && ($lowerLine[$i] != NoValue)) { $name = sprintf("%s: %s - %s", $name, $this->formatValue($lowerLine[$i], $this->m_generalFormat), $this->formatValue($upperLine[$i], $this->m_generalFormat)); break; } $i = $i - 1; } $uLayer = $this->m_mainChart->addLineLayer($upperLine, $lineColor, $name); $lLayer = $this->m_mainChart->addLineLayer($lowerLine, $lineColor); return $this->m_mainChart->addInterLineLayer($uLayer->getLine(), $lLayer->getLine(), $fillColor); } #/ #/ Add a Bollinger band on the main chart. #/ #/ The period to compute the band. #/ The half-width of the band in terms multiples of standard deviation. Typically 2 is used. #/ The color of the lines defining the upper and lower limits. #/ The color to fill the regional within the band. #/ The InterLineLayer object representing the band created. function addBollingerBand($period, $bandWidth, $lineColor, $fillColor) { #Bollinger Band is moving avg +/- (width * moving std deviation) $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->movStdDev($period); $tmpArrayMath1->mul($bandWidth); $stdDev = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->movAvg($period); $movAvg = $tmpArrayMath1->result(); $label = "Bollinger ($period, $bandWidth)"; $tmpArrayMath1 = new ArrayMath($movAvg); $tmpArrayMath1->add($stdDev); $tmpArrayMath2 = new ArrayMath($movAvg); $tmpArrayMath2->sub($stdDev); $tmpArrayMath2->selectGTZ(null, 0); return $this->addBand($tmpArrayMath1->result(), $tmpArrayMath2->result(), $lineColor, $fillColor, $label); } #/ #/ Add a Donchian channel on the main chart. #/ #/ The period to compute the band. #/ The color of the lines defining the upper and lower limits. #/ The color to fill the regional within the band. #/ The InterLineLayer object representing the band created. function addDonchianChannel($period, $lineColor, $fillColor) { #Donchian Channel is the zone between the moving max and moving min $label = "Donchian ($period)"; $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->movMax($period); $tmpArrayMath2 = new ArrayMath($this->m_lowData); $tmpArrayMath2->movMin($period); return $this->addBand($tmpArrayMath1->result(), $tmpArrayMath2->result(), $lineColor, $fillColor, $label); } #/ #/ 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. #/ #/ The period for the moving average. #/ The ratio above and below the moving average. #/ The color of the lines defining the upper and lower limits. #/ The color to fill the regional within the band. #/ The InterLineLayer object representing the band created. function addEnvelop($period, $range, $lineColor, $fillColor) { #Envelop is moving avg +/- percentage $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->movAvg($period); $movAvg = $tmpArrayMath1->result(); $label = sprintf("Envelop (SMA %s +/- %s%%)", $period, (int)($range * 100)); $tmpArrayMath1 = new ArrayMath($movAvg); $tmpArrayMath1->mul(1 + $range); $tmpArrayMath2 = new ArrayMath($movAvg); $tmpArrayMath2->mul(1 - $range); return $this->addBand($tmpArrayMath1->result(), $tmpArrayMath2->result(), $lineColor, $fillColor, $label); } #/ #/ Add a volume bar chart layer on the main chart. #/ #/ The height of the bar chart layer in pixels. #/ 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. #/ 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. #/ 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. #/ The XYChart object representing the chart created. function addVolBars($height, $upColor, $downColor, $flatColor) { return $this->addVolBars2($this->m_mainChart, $height, $upColor, $downColor, $flatColor); } function addVolBars2(&$c, $height, $upColor, $downColor, $flatColor) { #Compute an array to represent the closing price changes $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->delta(); $closeChange = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_volData); $tmpArrayMath1->selectGTZ($closeChange); $upLayer = $this->addBarIndicator2($c, $tmpArrayMath1->result(), $upColor, ""); $tmpArrayMath1 = new ArrayMath($this->m_volData); $tmpArrayMath1->selectLTZ($closeChange); $dnLayer = $this->addBarIndicator2($c, $tmpArrayMath1->result(), $downColor, ""); $tmpArrayMath1 = new ArrayMath($this->m_volData); $tmpArrayMath1->selectEQZ($closeChange); $flatLayer = $this->addBarIndicator2($c, $tmpArrayMath1->result(), $flatColor, ""); $tmpArrayMath1 = new ArrayMath($this->m_volData); $maxVol = $tmpArrayMath1->max(); if ($c == $this->m_mainChart) { $res_yAxis2=$c->yAxis2(); $this->configureYAxis($res_yAxis2, $height); $drawAreaObj = $c->getDrawArea(); $topMargin = $drawAreaObj->getHeight() - $this->m_topMargin - $this->m_bottomMargin - $height + $this->m_yAxisMargin; if ($topMargin < 0) { $topMargin = 0; } $c->yAxis2->setTopMargin($topMargin); $upLayer->setUseYAxis2(); $dnLayer->setUseYAxis2(); $flatLayer->setUseYAxis2(); } $a = $c->yAxis2; if ($c != $this->m_mainChart) { $a = $c->yAxis; } $volFormat = ""; if ($maxVol < 10) { $volFormat = sprintf("{value|1}%s", $this->m_volUnit); } else { $volFormat = sprintf("{value}%s", $this->m_volUnit); } $a->setLabelFormat($volFormat); $i = $this->lastIndex($this->m_volData); $label = "Vol"; if ($i >= 0) { $label = sprintf("Vol: %s%s", $this->formatValue($this->m_volData[$i], $this->m_generalFormat), $this->m_volUnit); } $selectedLayer = null; if (($i < 0) || ($closeChange[$i] == 0) || ($closeChange[$i] == NoValue)) { $selectedLayer = $flatLayer; } else if ($closeChange[$i] > 0) { $selectedLayer = $upLayer; } else { $selectedLayer = $dnLayer; } $dataSetObj = $selectedLayer->getDataSet(0); $dataSetObj->setDataName($label); return $selectedLayer; } #/ #/ 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. #/ #/ The height of the chart in pixels. #/ The XYChart object representing the chart created. function addIndicator($height) { #create a new chart object $ret = new XYChart($this->m_totalWidth, $height + $this->m_topMargin + $this->m_bottomMargin, Transparent); $ret->setTrimData($this->m_extraPoints); if ($this->m_currentChart != null) { #if there is a chart before the newly created chart, disable its x-axis, and copy #its x-axis labels to the new chart $this->m_currentChart->xAxis->setColors(LineColor, Transparent); $ret->xAxis->copyAxis($this->m_currentChart->xAxis()); } else { #no existing chart - create the x-axis labels from scratch $res_xAxis=$ret->xAxis(); $this->setXLabels($res_xAxis); } #the newly created chart becomes the current chart $this->m_currentChart = $ret; #add chart to MultiChart and update the total height $this->addChart(0, $this->m_totalHeight, $ret); $this->m_totalHeight = $this->m_totalHeight + $height + 1; $this->setSize($this->m_totalWidth, $this->m_totalHeight + $this->m_topMargin + $this->m_bottomMargin); #configure the plot area $plotAreaObj = $ret->setPlotArea($this->m_leftMargin, $this->m_topMargin, $this->m_totalWidth - $this->m_leftMargin - $this->m_rightMargin, $height, $this->m_plotAreaBgColor); $plotAreaObj->setGridColor($this->m_majorHGridColor, $this->m_majorVGridColor, $this->m_minorHGridColor, $this->m_minorVGridColor); $ret->setAntiAlias($this->m_antiAlias); #configure legend box $box = $ret->addLegend($this->m_leftMargin, $this->m_topMargin, false, $this->m_legendFont, $this->m_legendFontSize); $box->setBackground($this->m_legendBgColor); $box->setMargin2(5, 0, 2, 0); $box->setSize($this->m_totalWidth - $this->m_leftMargin - $this->m_rightMargin, 0); #configure x-axis $a = $ret->xAxis; $a->setIndent(true); $a->setTickLength(2, 0); $a->setLabelStyle($this->m_xAxisFont, $this->m_xAxisFontSize, $this->m_xAxisFontColor, $this->m_xAxisFontAngle); #configure y-axis $ret->setYAxisOnRight($this->m_axisOnRight); $res_yAxis=$ret->yAxis(); $this->configureYAxis($res_yAxis, $height); return $ret; } function configureYAxis(&$a, $height) { $a->setAutoScale(0, 0.05, 0); if ($height < 100) { $a->setTickDensity(15); } $a->setMargin($this->m_yAxisMargin); $a->setLabelStyle($this->m_yAxisFont, $this->m_yAxisFontSize, $this->m_yAxisFontColor, 0); $a->setTickLength(-4, -2); } #/ #/ Add a generic line indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The data series of the indicator line. #/ The color of the indicator line. #/ The name of the indicator. #/ The XYChart object representing the chart created. function addLineIndicator($height, $data, $color, $name) { $c = $this->addIndicator($height); $this->addLineIndicator2($c, $data, $color, $name); return $c; } #/ #/ Add a line to an existing indicator chart. #/ #/ The indicator chart to add the line to. #/ The data series of the indicator line. #/ The color of the indicator line. #/ The name of the indicator. #/ The LineLayer object representing the line created. function addLineIndicator2(&$c, $data, $color, $name) { return $c->addLineLayer($data, $color, $this->formatIndicatorLabel($name, $data)); } #/ #/ Add a generic bar indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The data series of the indicator bars. #/ The color of the indicator bars. #/ The name of the indicator. #/ The XYChart object representing the chart created. function addBarIndicator($height, $data, $color, $name) { $c = $this->addIndicator($height); $this->addBarIndicator2($c, $data, $color, $name); return $c; } #/ #/ Add a bar layer to an existing indicator chart. #/ #/ The indicator chart to add the bar layer to. #/ The data series of the indicator bars. #/ The color of the indicator bars. #/ The name of the indicator. #/ The BarLayer object representing the bar layer created. function addBarIndicator2(&$c, $data, $color, $name) { $layer = $c->addBarLayer($data, $color, $this->formatIndicatorLabel($name, $data)); $layer->setBorderColor(Transparent); return $layer; } #/ #/ Add an upper/lower threshold range to an existing indicator chart. #/ #/ The indicator chart to add the threshold range to. #/ The line layer that the threshold range applies to. #/ The upper threshold. #/ The color to fill the region of the line that is above the #/ upper threshold. #/ The lower threshold. #/ The color to fill the region of the line that is below #/ the lower threshold. function addThreshold(&$c, &$layer, $topRange, $topColor, $bottomRange, $bottomColor) { $topMark = $c->yAxis->addMark($topRange, $topColor, $this->formatValue($topRange, $this->m_generalFormat)); $bottomMark = $c->yAxis->addMark($bottomRange, $bottomColor, $this->formatValue( $bottomRange, $this->m_generalFormat)); $c->addInterLineLayer($layer->getLine(), $topMark->getLine(), $topColor, Transparent); $c->addInterLineLayer($layer->getLine(), $bottomMark->getLine(), Transparent, $bottomColor); } function formatIndicatorLabel($name, $data) { $i = $this->lastIndex($data); if ($name == null) { return $name; } if (($name == "") || ($i < 0)) { return $name; } $ret = sprintf("%s: %s", $name, $this->formatValue($data[$i], $this->m_generalFormat)); return $ret; } #/ #/ Add an Accumulation/Distribution indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addAccDist($height, $color) { #Close Location Value = ((C - L) - (H - C)) / (H - L) #Accumulation Distribution Line = Accumulation of CLV * volume $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->sub($this->m_lowData); $range = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->mul(2); $tmpArrayMath1->sub($this->m_lowData); $tmpArrayMath1->sub($this->m_highData); $tmpArrayMath1->mul($this->m_volData); $tmpArrayMath1->financeDiv($range, 0); $tmpArrayMath1->acc(); return $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, "Accumulation/Distribution"); } function computeAroonUp($period) { $aroonUp = array_pad(array(), count($this->m_highData), 0); for($i = 0; $i < count($this->m_highData); ++$i) { $highValue = $this->m_highData[$i]; if ($highValue == NoValue) { $aroonUp[$i] = NoValue; } else { $currentIndex = $i; $highCount = $period; $count = $period; while (($count > 0) && ($currentIndex >= $count)) { $currentIndex = $currentIndex - 1; $currentValue = $this->m_highData[$currentIndex]; if ($currentValue != NoValue) { $count = $count - 1; if ($currentValue > $highValue) { $highValue = $currentValue; $highCount = $count; } } } if ($count > 0) { $aroonUp[$i] = NoValue; } else { $aroonUp[$i] = $highCount * 100.0 / $period; } } } return $aroonUp; } function computeAroonDn($period) { $aroonDn = array_pad(array(), count($this->m_lowData), 0); for($i = 0; $i < count($this->m_lowData); ++$i) { $lowValue = $this->m_lowData[$i]; if ($lowValue == NoValue) { $aroonDn[$i] = NoValue; } else { $currentIndex = $i; $lowCount = $period; $count = $period; while (($count > 0) && ($currentIndex >= $count)) { $currentIndex = $currentIndex - 1; $currentValue = $this->m_lowData[$currentIndex]; if ($currentValue != NoValue) { $count = $count - 1; if ($currentValue < $lowValue) { $lowValue = $currentValue; $lowCount = $count; } } } if ($count > 0) { $aroonDn[$i] = NoValue; } else { $aroonDn[$i] = $lowCount * 100.0 / $period; } } } return $aroonDn; } #/ #/ Add an Aroon Up/Down indicators chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicators. #/ The color of the Aroon Up indicator line. #/ The color of the Aroon Down indicator line. #/ The XYChart object representing the chart created. function addAroon($height, $period, $upColor, $downColor) { $c = $this->addIndicator($height); $this->addLineIndicator2($c, $this->computeAroonUp($period), $upColor, "Aroon Up"); $this->addLineIndicator2($c, $this->computeAroonDn($period), $downColor, "Aroon Down"); $c->yAxis->setLinearScale(0, 100); return $c; } #/ #/ Add an Aroon Oscillator indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addAroonOsc($height, $period, $color) { $label = "Aroon Oscillator ($period)"; $tmpArrayMath1 = new ArrayMath($this->computeAroonUp($period)); $tmpArrayMath1->sub($this->computeAroonDn($period)); $c = $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, $label); $c->yAxis->setLinearScale(-100, 100); return $c; } function computeTrueRange() { $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->shift(); $previousClose = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->sub($this->m_lowData); $ret = $tmpArrayMath1->result(); $temp = 0; for($i = 0; $i < count($this->m_highData); ++$i) { if (($ret[$i] != NoValue) && ($previousClose[$i] != NoValue)) { $temp = abs($this->m_highData[$i] - $previousClose[$i]); if ($temp > $ret[$i]) { $ret[$i] = $temp; } $temp = abs($previousClose[$i] - $this->m_lowData[$i]); if ($temp > $ret[$i]) { $ret[$i] = $temp; } } } return $ret; } #/ #/ Add an Average Directional Index indicators chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the Positive Directional Index line. #/ The color of the Negatuve Directional Index line. #/ The color of the Average Directional Index line. #/ The XYChart object representing the chart created. function addADX($height, $period, $posColor, $negColor, $color) { #pos/neg directional movement $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->delta(); $pos = $tmpArrayMath1->selectGTZ(); $tmpArrayMath1 = new ArrayMath($this->m_lowData); $tmpArrayMath1->delta(); $tmpArrayMath1->mul(-1); $neg = $tmpArrayMath1->selectGTZ(); $tmpArrayMath1 = new ArrayMath($pos->result()); $tmpArrayMath1->sub($neg->result()); $delta = $tmpArrayMath1->result(); $pos->selectGTZ($delta); $neg->selectLTZ($delta); #pos/neg directional index $tr = $this->computeTrueRange(); $financeDivObj = $pos->financeDiv($tr, 0.25); $mulObj = $financeDivObj->mul(100); $mulObj->expAvg(2.0 / ($period + 1)); $financeDivObj = $neg->financeDiv($tr, 0.25); $mulObj = $financeDivObj->mul(100); $mulObj->expAvg(2.0 / ($period + 1)); #directional movement index ??? what happen if division by zero??? $tmpArrayMath1 = new ArrayMath($pos->result()); $tmpArrayMath1->add($neg->result()); $totalDM = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($pos->result()); $tmpArrayMath1->sub($neg->result()); $tmpArrayMath1->abs(); $tmpArrayMath1->financeDiv($totalDM, 0); $tmpArrayMath1->mul(100); $dx = $tmpArrayMath1->expAvg(2.0 / ($period + 1)); $c = $this->addIndicator($height); $label1 = "+DI ($period)"; $label2 = "-DI ($period)"; $label3 = "ADX ($period)"; $this->addLineIndicator2($c, $pos->result(), $posColor, $label1); $this->addLineIndicator2($c, $neg->result(), $negColor, $label2); $this->addLineIndicator2($c, $dx->result(), $color, $label3); return $c; } #/ #/ Add an Average True Range indicators chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the True Range line. #/ The color of the Average True Range line. #/ The XYChart object representing the chart created. function addATR($height, $period, $color1, $color2) { $trueRange = $this->computeTrueRange(); $c = $this->addLineIndicator($height, $trueRange, $color1, "True Range"); $label = "Average True Range ($period)"; $tmpArrayMath1 = new ArrayMath($trueRange); $tmpArrayMath1->expAvg(2.0 / ($period + 1)); $this->addLineIndicator2($c, $tmpArrayMath1->result(), $color2, $label); return $c; } #/ #/ Add a Bollinger Band Width indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The band width to compute the indicator. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addBollingerWidth($height, $period, $width, $color) { $label = "Bollinger Width ($period, $width)"; $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->movStdDev($period); $tmpArrayMath1->mul($width * 2); return $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, $label); } #/ #/ Add a Community Channel Index indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the indicator line. #/ The distance beween the middle line and the upper and lower threshold lines. #/ The fill color when the indicator exceeds the upper threshold line. #/ The fill color when the indicator falls below the lower threshold line. #/ The XYChart object representing the chart created. function addCCI($height, $period, $color, $range, $upColor, $downColor) { #typical price $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->add($this->m_lowData); $tmpArrayMath1->add($this->m_closeData); $tmpArrayMath1->div(3); $tp = $tmpArrayMath1->result(); #simple moving average of typical price $tmpArrayMath1 = new ArrayMath($tp); $tmpArrayMath1->movAvg($period); $smvtp = $tmpArrayMath1->result(); #compute mean deviation $movMeanDev = array_pad(array(), count($smvtp), 0); for($i = 0; $i < count($smvtp); ++$i) { $avg = $smvtp[$i]; if ($avg == NoValue) { $movMeanDev[$i] = NoValue; } else { $currentIndex = $i; $count = $period - 1; $acc = 0; while (($count > 0) && ($currentIndex >= $count)) { $currentIndex = $currentIndex - 1; $currentValue = $tp[$currentIndex]; if ($currentValue != NoValue) { $count = $count - 1; $acc = $acc + abs($avg - $currentValue); } } if ($count > 0) { $movMeanDev[$i] = NoValue; } else { $movMeanDev[$i] = $acc / $period; } } } $c = $this->addIndicator($height); $label = "CCI ($period)"; $tmpArrayMath1 = new ArrayMath($tp); $tmpArrayMath1->sub($smvtp); $tmpArrayMath1->financeDiv($movMeanDev, 0); $tmpArrayMath1->div(0.015); $layer = $this->addLineIndicator2($c, $tmpArrayMath1->result(), $color, $label); $this->addThreshold($c, $layer, $range, $upColor, -$range, $downColor); return $c; } #/ #/ Add a Chaikin Money Flow indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addChaikinMoneyFlow($height, $period, $color) { $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->sub($this->m_lowData); $range = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_volData); $tmpArrayMath1->movAvg($period); $volAvg = $tmpArrayMath1->result(); $label = "Chaikin Money Flow ($period)"; $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->mul(2); $tmpArrayMath1->sub($this->m_lowData); $tmpArrayMath1->sub($this->m_highData); $tmpArrayMath1->mul($this->m_volData); $tmpArrayMath1->financeDiv($range, 0); $tmpArrayMath1->movAvg($period); $tmpArrayMath1->financeDiv($volAvg, 0); return $this->addBarIndicator($height, $tmpArrayMath1->result(), $color, $label); } #/ #/ Add a Chaikin Oscillator indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addChaikinOscillator($height, $color) { #first compute acc/dist line $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->sub($this->m_lowData); $range = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->mul(2); $tmpArrayMath1->sub($this->m_lowData); $tmpArrayMath1->sub($this->m_highData); $tmpArrayMath1->mul($this->m_volData); $tmpArrayMath1->financeDiv($range, 0); $tmpArrayMath1->acc(); $accdist = $tmpArrayMath1->result(); #chaikin osc = exp3(accdist) - exp10(accdist) $tmpArrayMath1 = new ArrayMath($accdist); $tmpArrayMath1->expAvg(2.0 / (11)); $expAvg10 = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($accdist); $tmpArrayMath1->expAvg(2.0 / (4)); $tmpArrayMath1->sub($expAvg10); return $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, "Chaikin Oscillator"); } #/ #/ Add a Chaikin Volatility indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to smooth the range. #/ The period to compute the rate of change of the smoothed range. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addChaikinVolatility($height, $period1, $period2, $color) { $label = "Chaikin Volatility ($period1, $period2)"; $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->sub($this->m_lowData); $tmpArrayMath1->expAvg(2.0 / ($period1 + 1)); $tmpArrayMath1->rate($period2); $tmpArrayMath1->sub(1); $tmpArrayMath1->mul(100); return $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, $label); } #/ #/ Add a Close Location Value indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addCLV($height, $color) { #Close Location Value = ((C - L) - (H - C)) / (H - L) $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->sub($this->m_lowData); $range = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->mul(2); $tmpArrayMath1->sub($this->m_lowData); $tmpArrayMath1->sub($this->m_highData); $tmpArrayMath1->financeDiv($range, 0); return $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, "Close Location Value"); } #/ #/ Add a Detrended Price Oscillator indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addDPO($height, $period, $color) { $label = "DPO ($period)"; $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->movAvg($period); $tmpArrayMath1->shift($period / 2 + 1); $tmpArrayMath1->sub($this->m_closeData); $tmpArrayMath1->mul(-1); return $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, $label); } #/ #/ Add a Donchian Channel Width indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addDonchianWidth($height, $period, $color) { $label = "Donchian Width ($period)"; $tmpArrayMath2 = new ArrayMath($this->m_lowData); $tmpArrayMath2->movMin($period); $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->movMax($period); $tmpArrayMath1->sub($tmpArrayMath2->result()); return $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, $label); } #/ #/ Add a Ease of Movement indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to smooth the indicator. #/ The color of the indicator line. #/ The color of the smoothed indicator line. #/ The XYChart object representing the chart created. function addEaseOfMovement($height, $period, $color1, $color2) { $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->sub($this->m_lowData); $tmpArrayMath1->financeDiv($this->m_volData, 0); $boxRatioInverted = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->add($this->m_lowData); $tmpArrayMath1->div(2); $tmpArrayMath1->delta(); $tmpArrayMath1->mul($boxRatioInverted); $result = $tmpArrayMath1->result(); $c = $this->addLineIndicator($height, $result, $color1, "EMV"); $label = "EMV EMA ($period)"; $tmpArrayMath1 = new ArrayMath($result); $tmpArrayMath1->movAvg($period); $this->addLineIndicator2($c, $tmpArrayMath1->result(), $color2, $label); return $c; } #/ #/ Add a Fast Stochastic indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the %K line. #/ The period to compute the %D line. #/ The color of the %K line. #/ The color of the %D line. #/ The XYChart object representing the chart created. function addFastStochastic($height, $period1, $period2, $color1, $color2) { $tmpArrayMath1 = new ArrayMath($this->m_lowData); $tmpArrayMath1->movMin($period1); $movLow = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->movMax($period1); $tmpArrayMath1->sub($movLow); $movRange = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->sub($movLow); $tmpArrayMath1->financeDiv($movRange, 0.5); $tmpArrayMath1->mul(100); $stochastic = $tmpArrayMath1->result(); $label1 = "Fast Stochastic %K ($period1)"; $c = $this->addLineIndicator($height, $stochastic, $color1, $label1); $label2 = "%D ($period2)"; $tmpArrayMath1 = new ArrayMath($stochastic); $tmpArrayMath1->movAvg($period2); $this->addLineIndicator2($c, $tmpArrayMath1->result(), $color2, $label2); $c->yAxis->setLinearScale(0, 100); return $c; } #/ #/ Add a MACD indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The first moving average period to compute the indicator. #/ The second moving average period to compute the indicator. #/ The moving average period of the signal line. #/ The color of the indicator line. #/ The color of the signal line. #/ The color of the divergent bars. #/ The XYChart object representing the chart created. function addMACD($height, $period1, $period2, $period3, $color, $signalColor, $divColor) { $c = $this->addIndicator($height); #MACD is defined as the difference between two exponential averages (typically 12/26 days) $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->expAvg(2.0 / ($period1 + 1)); $expAvg1 = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->expAvg(2.0 / ($period2 + 1)); $tmpArrayMath1->sub($expAvg1); $macd = $tmpArrayMath1->result(); #Add the MACD line $label1 = "MACD ($period1, $period2)"; $this->addLineIndicator2($c, $macd, $color, $label1); #MACD signal line $tmpArrayMath1 = new ArrayMath($macd); $tmpArrayMath1->expAvg(2.0 / ($period3 + 1)); $macdSignal = $tmpArrayMath1->result(); $label2 = "EXP ($period3)"; $this->addLineIndicator2($c, $macdSignal, $signalColor, $label2); #Divergence $tmpArrayMath1 = new ArrayMath($macd); $tmpArrayMath1->sub($macdSignal); $this->addBarIndicator2($c, $tmpArrayMath1->result(), $divColor, "Divergence"); return $c; } #/ #/ Add a Mass Index indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The color of the indicator line. #/ The fill color when the indicator exceeds the upper threshold line. #/ The fill color when the indicator falls below the lower threshold line. #/ The XYChart object representing the chart created. function addMassIndex($height, $color, $upColor, $downColor) { #Mass Index $f = 2.0 / (10); $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->sub($this->m_lowData); $tmpArrayMath1->expAvg($f); $exp9 = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($exp9); $tmpArrayMath1->expAvg($f); $exp99 = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($exp9); $tmpArrayMath1->financeDiv($exp99, 1); $tmpArrayMath1->movAvg(25); $tmpArrayMath1->mul(25); $c = $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, "Mass Index"); $c->yAxis->addMark(27, $upColor); $c->yAxis->addMark(26.5, $downColor); return $c; } #/ #/ Add a Money Flow Index indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the indicator line. #/ The distance beween the middle line and the upper and lower threshold lines. #/ The fill color when the indicator exceeds the upper threshold line. #/ The fill color when the indicator falls below the lower threshold line. #/ The XYChart object representing the chart created. function addMFI($height, $period, $color, $range, $upColor, $downColor) { #Money Flow Index $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->add($this->m_lowData); $tmpArrayMath1->add($this->m_closeData); $tmpArrayMath1->div(3); $typicalPrice = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($typicalPrice); $tmpArrayMath1->mul($this->m_volData); $moneyFlow = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($typicalPrice); $tmpArrayMath1->delta(); $selector = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($moneyFlow); $tmpArrayMath1->selectGTZ($selector); $tmpArrayMath1->movAvg($period); $posMoneyFlow = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($moneyFlow); $tmpArrayMath1->selectLTZ($selector); $tmpArrayMath1->movAvg($period); $tmpArrayMath1->add($posMoneyFlow); $posNegMoneyFlow = $tmpArrayMath1->result(); $c = $this->addIndicator($height); $label = "Money Flow Index ($period)"; $tmpArrayMath1 = new ArrayMath($posMoneyFlow); $tmpArrayMath1->financeDiv($posNegMoneyFlow, 0.5); $tmpArrayMath1->mul(100); $layer = $this->addLineIndicator2($c, $tmpArrayMath1->result(), $color, $label); $this->addThreshold($c, $layer, 50 + $range, $upColor, 50 - $range, $downColor); $c->yAxis->setLinearScale(0, 100); return $c; } #/ #/ Add a Momentum indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addMomentum($height, $period, $color) { $label = "Momentum ($period)"; $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->delta($period); return $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, $label); } #/ #/ Add a Negative Volume Index indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the signal line. #/ The color of the indicator line. #/ The color of the signal line. #/ The XYChart object representing the chart created. function addNVI($height, $period, $color, $signalColor) { $nvi = array_pad(array(), count($this->m_volData), 0); $previousNVI = 100; $previousVol = NoValue; $previousClose = NoValue; for($i = 0; $i < count($this->m_volData); ++$i) { if ($this->m_volData[$i] == NoValue) { $nvi[$i] = NoValue; } else { if (($previousVol != NoValue) && ($this->m_volData[$i] < $previousVol) && ( $previousClose != NoValue) && ($this->m_closeData[$i] != NoValue)) { $nvi[$i] = $previousNVI + $previousNVI * ($this->m_closeData[$i] - $previousClose) / $previousClose; } else { $nvi[$i] = $previousNVI; } $previousNVI = $nvi[$i]; $previousVol = $this->m_volData[$i]; $previousClose = $this->m_closeData[$i]; } } $c = $this->addLineIndicator($height, $nvi, $color, "NVI"); if (count($nvi) > $period) { $label = "NVI SMA ($period)"; $tmpArrayMath1 = new ArrayMath($nvi); $tmpArrayMath1->movAvg($period); $this->addLineIndicator2($c, $tmpArrayMath1->result(), $signalColor, $label); } return $c; } #/ #/ Add an On Balance Volume indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addOBV($height, $color) { $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->delta(); $closeChange = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_volData); $tmpArrayMath1->selectGTZ($closeChange); $upVolume = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_volData); $tmpArrayMath1->selectLTZ($closeChange); $downVolume = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($upVolume); $tmpArrayMath1->sub($downVolume); $tmpArrayMath1->acc(); return $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, "OBV"); } #/ #/ Add a Performance indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addPerformance($height, $color) { $firstCloseIndex = $this->m_extraPoints; while ($firstCloseIndex < count($this->m_closeData)) { if (($this->m_closeData[$firstCloseIndex] != NoValue) && ($this->m_closeData[ $firstCloseIndex] != 0)) { break; } $firstCloseIndex = $firstCloseIndex + 1; } if ($firstCloseIndex < count($this->m_closeData)) { $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->div($this->m_closeData[$firstCloseIndex]); $tmpArrayMath1->sub(1); $tmpArrayMath1->mul(100); return $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, "Performance") ; } else { #chart is empty !!! return $this->addIndicator($height); } } #/ #/ Add a Percentage Price Oscillator indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The first moving average period to compute the indicator. #/ The second moving average period to compute the indicator. #/ The moving average period of the signal line. #/ The color of the indicator line. #/ The color of the signal line. #/ The color of the divergent bars. #/ The XYChart object representing the chart created. function addPPO($height, $period1, $period2, $period3, $color, $signalColor, $divColor) { $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->expAvg(2.0 / ($period1 + 1)); $expAvg1 = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->expAvg(2.0 / ($period2 + 1)); $expAvg2 = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($expAvg2); $tmpArrayMath1->sub($expAvg1); $tmpArrayMath1->financeDiv($expAvg2, 0); $ppo = $tmpArrayMath1->mul(100); $tmpArrayMath1 = new ArrayMath($ppo->result()); $tmpArrayMath1->expAvg(2.0 / ($period3 + 1)); $ppoSignal = $tmpArrayMath1->result(); $label1 = "PPO ($period1, $period2)"; $label2 = "EMA ($period3)"; $c = $this->addLineIndicator($height, $ppo->result(), $color, $label1); $this->addLineIndicator2($c, $ppoSignal, $signalColor, $label2); $subtractObj = $ppo->sub($ppoSignal); $this->addBarIndicator2($c, $subtractObj->result(), $divColor, "Divergence"); return $c; } #/ #/ Add a Positive Volume Index indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the signal line. #/ The color of the indicator line. #/ The color of the signal line. #/ The XYChart object representing the chart created. function addPVI($height, $period, $color, $signalColor) { #Positive Volume Index $pvi = array_pad(array(), count($this->m_volData), 0); $previousPVI = 100; $previousVol = NoValue; $previousClose = NoValue; for($i = 0; $i < count($this->m_volData); ++$i) { if ($this->m_volData[$i] == NoValue) { $pvi[$i] = NoValue; } else { if (($previousVol != NoValue) && ($this->m_volData[$i] > $previousVol) && ( $previousClose != NoValue) && ($this->m_closeData[$i] != NoValue)) { $pvi[$i] = $previousPVI + $previousPVI * ($this->m_closeData[$i] - $previousClose) / $previousClose; } else { $pvi[$i] = $previousPVI; } $previousPVI = $pvi[$i]; $previousVol = $this->m_volData[$i]; $previousClose = $this->m_closeData[$i]; } } $c = $this->addLineIndicator($height, $pvi, $color, "PVI"); if (count($pvi) > $period) { $label = "PVI SMA ($period)"; $tmpArrayMath1 = new ArrayMath($pvi); $tmpArrayMath1->movAvg($period); $this->addLineIndicator2($c, $tmpArrayMath1->result(), $signalColor, $label); } return $c; } #/ #/ Add a Percentage Volume Oscillator indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The first moving average period to compute the indicator. #/ The second moving average period to compute the indicator. #/ The moving average period of the signal line. #/ The color of the indicator line. #/ The color of the signal line. #/ The color of the divergent bars. #/ The XYChart object representing the chart created. function addPVO($height, $period1, $period2, $period3, $color, $signalColor, $divColor) { $tmpArrayMath1 = new ArrayMath($this->m_volData); $tmpArrayMath1->expAvg(2.0 / ($period1 + 1)); $expAvg1 = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_volData); $tmpArrayMath1->expAvg(2.0 / ($period2 + 1)); $expAvg2 = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($expAvg2); $tmpArrayMath1->sub($expAvg1); $tmpArrayMath1->financeDiv($expAvg2, 0); $pvo = $tmpArrayMath1->mul(100); $tmpArrayMath1 = new ArrayMath($pvo->result()); $tmpArrayMath1->expAvg(2.0 / ($period3 + 1)); $pvoSignal = $tmpArrayMath1->result(); $label1 = "PVO ($period1, $period2)"; $label2 = "EMA ($period3)"; $c = $this->addLineIndicator($height, $pvo->result(), $color, $label1); $this->addLineIndicator2($c, $pvoSignal, $signalColor, $label2); $subtractObj = $pvo->sub($pvoSignal); $this->addBarIndicator2($c, $subtractObj->result(), $divColor, "Divergence"); return $c; } #/ #/ Add a Price Volumne Trend indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addPVT($height, $color) { $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->rate(); $tmpArrayMath1->sub(1); $tmpArrayMath1->mul($this->m_volData); $tmpArrayMath1->acc(); return $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, "PVT"); } #/ #/ Add a Rate of Change indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addROC($height, $period, $color) { $label = "ROC ($period)"; $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->rate($period); $tmpArrayMath1->sub(1); $tmpArrayMath1->mul(100); return $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, $label); } 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. $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->delta(); $tmpArrayMath1->abs(); $tmpArrayMath1->movAvg($period); $absChange = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->delta(); $tmpArrayMath1->selectGTZ(); $tmpArrayMath1->movAvg($period); $tmpArrayMath1->financeDiv($absChange, 0.5); $tmpArrayMath1->mul(100); return $tmpArrayMath1->result(); } #/ #/ Add a Relative Strength Index indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the indicator line. #/ The distance beween the middle line and the upper and lower threshold lines. #/ The fill color when the indicator exceeds the upper threshold line. #/ The fill color when the indicator falls below the lower threshold line. #/ The XYChart object representing the chart created. function addRSI($height, $period, $color, $range, $upColor, $downColor) { $c = $this->addIndicator($height); $label = "RSI ($period)"; $layer = $this->addLineIndicator2($c, $this->computeRSI($period), $color, $label); #Add range if given if (($range > 0) && ($range < 50)) { $this->addThreshold($c, $layer, 50 + $range, $upColor, 50 - $range, $downColor); } $c->yAxis->setLinearScale(0, 100); return $c; } #/ #/ Add a Slow Stochastic indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the %K line. #/ The period to compute the %D line. #/ The color of the %K line. #/ The color of the %D line. #/ The XYChart object representing the chart created. function addSlowStochastic($height, $period1, $period2, $color1, $color2) { $tmpArrayMath1 = new ArrayMath($this->m_lowData); $tmpArrayMath1->movMin($period1); $movLow = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->movMax($period1); $tmpArrayMath1->sub($movLow); $movRange = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->sub($movLow); $tmpArrayMath1->financeDiv($movRange, 0.5); $tmpArrayMath1->mul(100); $stochastic = $tmpArrayMath1->movAvg(3); $label1 = "Slow Stochastic %K ($period1)"; $label2 = "%D ($period2)"; $c = $this->addLineIndicator($height, $stochastic->result(), $color1, $label1); $movAvgObj = $stochastic->movAvg($period2); $this->addLineIndicator2($c, $movAvgObj->result(), $color2, $label2); $c->yAxis->setLinearScale(0, 100); return $c; } #/ #/ Add a Moving Standard Deviation indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addStdDev($height, $period, $color) { $label = "Moving StdDev ($period)"; $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->movStdDev($period); return $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, $label); } #/ #/ Add a Stochastic RSI indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the indicator line. #/ The distance beween the middle line and the upper and lower threshold lines. #/ The fill color when the indicator exceeds the upper threshold line. #/ The fill color when the indicator falls below the lower threshold line. #/ The XYChart object representing the chart created. function addStochRSI($height, $period, $color, $range, $upColor, $downColor) { $rsi = $this->computeRSI($period); $tmpArrayMath1 = new ArrayMath($rsi); $tmpArrayMath1->movMin($period); $movLow = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($rsi); $tmpArrayMath1->movMax($period); $tmpArrayMath1->sub($movLow); $movRange = $tmpArrayMath1->result(); $c = $this->addIndicator($height); $label = "StochRSI ($period)"; $tmpArrayMath1 = new ArrayMath($rsi); $tmpArrayMath1->sub($movLow); $tmpArrayMath1->financeDiv($movRange, 0.5); $tmpArrayMath1->mul(100); $layer = $this->addLineIndicator2($c, $tmpArrayMath1->result(), $color, $label); #Add range if given if (($range > 0) && ($range < 50)) { $this->addThreshold($c, $layer, 50 + $range, $upColor, 50 - $range, $downColor); } $c->yAxis->setLinearScale(0, 100); return $c; } #/ #/ Add a TRIX indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the indicator line. #/ The XYChart object representing the chart created. function addTRIX($height, $period, $color) { $f = 2.0 / ($period + 1); $label = "TRIX ($period)"; $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->expAvg($f); $tmpArrayMath1->expAvg($f); $tmpArrayMath1->expAvg($f); $tmpArrayMath1->rate(); return $this->addLineIndicator($height, $tmpArrayMath1->result(), $color, $label); } function computeTrueLow() { #the lower of today's low or yesterday's close. $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->shift(); $previousClose = $tmpArrayMath1->result(); $ret = array_pad(array(), count($this->m_lowData), 0); for($i = 0; $i < count($this->m_lowData); ++$i) { if (($this->m_lowData[$i] != NoValue) && ($previousClose[$i] != NoValue)) { if ($this->m_lowData[$i] < $previousClose[$i]) { $ret[$i] = $this->m_lowData[$i]; } else { $ret[$i] = $previousClose[$i]; } } else { $ret[$i] = NoValue; } } return $ret; } #/ #/ Add an Ultimate Oscillator indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The first moving average period to compute the indicator. #/ The second moving average period to compute the indicator. #/ The third moving average period to compute the indicator. #/ The color of the indicator line. #/ The distance beween the middle line and the upper and lower threshold lines. #/ The fill color when the indicator exceeds the upper threshold line. #/ The fill color when the indicator falls below the lower threshold line. #/ The XYChart object representing the chart created. function addUltimateOscillator($height, $period1, $period2, $period3, $color, $range, $upColor, $downColor) { $trueLow = $this->computeTrueLow(); $tmpArrayMath1 = new ArrayMath($this->m_closeData); $tmpArrayMath1->sub($trueLow); $buyingPressure = $tmpArrayMath1->result(); $trueRange = $this->computeTrueRange(); $tmpArrayMath2 = new ArrayMath($trueRange); $tmpArrayMath2->movAvg($period1); $tmpArrayMath1 = new ArrayMath($buyingPressure); $tmpArrayMath1->movAvg($period1); $tmpArrayMath1->financeDiv($tmpArrayMath2->result(), 0.5); $tmpArrayMath1->mul(4); $rawUO1 = $tmpArrayMath1->result(); $tmpArrayMath2 = new ArrayMath($trueRange); $tmpArrayMath2->movAvg($period2); $tmpArrayMath1 = new ArrayMath($buyingPressure); $tmpArrayMath1->movAvg($period2); $tmpArrayMath1->financeDiv($tmpArrayMath2->result(), 0.5); $tmpArrayMath1->mul(2); $rawUO2 = $tmpArrayMath1->result(); $tmpArrayMath2 = new ArrayMath($trueRange); $tmpArrayMath2->movAvg($period3); $tmpArrayMath1 = new ArrayMath($buyingPressure); $tmpArrayMath1->movAvg($period3); $tmpArrayMath1->financeDiv($tmpArrayMath2->result(), 0.5); $tmpArrayMath1->mul(1); $rawUO3 = $tmpArrayMath1->result(); $c = $this->addIndicator($height); $label = "Ultimate Oscillator ($period1, $period2, $period3)"; $tmpArrayMath1 = new ArrayMath($rawUO1); $tmpArrayMath1->add($rawUO2); $tmpArrayMath1->add($rawUO3); $tmpArrayMath1->mul(100.0 / 7); $layer = $this->addLineIndicator2($c, $tmpArrayMath1->result(), $color, $label); $this->addThreshold($c, $layer, 50 + $range, $upColor, 50 - $range, $downColor); $c->yAxis->setLinearScale(0, 100); return $c; } #/ #/ Add a Volume indicator chart. #/ #/ The height of the indicator chart in pixels. #/ 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. #/ 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. #/ 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. #/ The XYChart object representing the chart created. function addVolIndicator($height, $upColor, $downColor, $flatColor) { $c = $this->addIndicator($height); $this->addVolBars2($c, $height, $upColor, $downColor, $flatColor); return $c; } #/ #/ Add a William %R indicator chart. #/ #/ The height of the indicator chart in pixels. #/ The period to compute the indicator. #/ The color of the indicator line. #/ The distance beween the middle line and the upper and lower threshold lines. #/ The fill color when the indicator exceeds the upper threshold line. #/ The fill color when the indicator falls below the lower threshold line. #/ The XYChart object representing the chart created. function addWilliamR($height, $period, $color, $range, $upColor, $downColor) { $tmpArrayMath1 = new ArrayMath($this->m_lowData); $tmpArrayMath1->movMin($period); $movLow = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($this->m_highData); $tmpArrayMath1->movMax($period); $movHigh = $tmpArrayMath1->result(); $tmpArrayMath1 = new ArrayMath($movHigh); $tmpArrayMath1->sub($movLow); $movRange = $tmpArrayMath1->result(); $c = $this->addIndicator($height); $tmpArrayMath1 = new ArrayMath($movHigh); $tmpArrayMath1->sub($this->m_closeData); $tmpArrayMath1->financeDiv($movRange, 0.5); $tmpArrayMath1->mul(-100); $layer = $this->addLineIndicator2($c, $tmpArrayMath1->result(), $color, "William %R"); $this->addThreshold($c, $layer, -50 + $range, $upColor, -50 - $range, $downColor); $c->yAxis->setLinearScale(-100, 0); return $c; } }