| Code Coverage | ||||||||||
| Classes and Traits | Functions and Methods | Lines | ||||||||
| Total |  | 0.00% | 0 / 1 |  | 0.00% | 0 / 4 | CRAP |  | 84.17% | 117 / 139 | 
| LupeCode\phpTraderNative\TALib\Core\VolumeIndicators |  | 0.00% | 0 / 1 |  | 0.00% | 0 / 4 | 42.43 |  | 84.17% | 117 / 139 | 
| ad |  | 0.00% | 0 / 1 | 4.00 |  | 94.74% | 18 / 19 | |||
| adOsc |  | 0.00% | 0 / 1 | 16.86 |  | 85.00% | 51 / 60 | |||
| atr |  | 0.00% | 0 / 1 | 14.25 |  | 75.00% | 33 / 44 | |||
| obv |  | 0.00% | 0 / 1 | 5.01 |  | 93.75% | 15 / 16 | |||
| <?php | |
| /** | |
| * This is a PHP port of the Trader extension for PHP, which is a port of the TA-LIB C code. | |
| * | |
| * This port is written in PHP and without any other requirements. | |
| * The goal is that this library can be used by those whom cannot install the PHP Trader extension. | |
| * | |
| * Below is the copyright information for TA-LIB found in the source code. | |
| */ | |
| /* TA-LIB Copyright (c) 1999-2007, Mario Fortier | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or | |
| * without modification, are permitted provided that the following | |
| * conditions are met: | |
| * | |
| * - Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * | |
| * - Redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in | |
| * the documentation and/or other materials provided with the | |
| * distribution. | |
| * | |
| * - Neither name of author nor the names of its contributors | |
| * may be used to endorse or promote products derived from this | |
| * software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
| * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| namespace LupeCode\phpTraderNative\TALib\Core; | |
| use LupeCode\phpTraderNative\TALib\Enum\ReturnCode; | |
| use LupeCode\phpTraderNative\TALib\Enum\UnstablePeriodFunctionID; | |
| class VolumeIndicators extends Core | |
| { | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param float[] $inHigh | |
| * @param float[] $inLow | |
| * @param float[] $inClose | |
| * @param float[] $inVolume | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param float[] $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function ad(int $startIdx, int $endIdx, array $inHigh, array $inLow, array $inClose, array $inVolume, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $nbBar = $endIdx - $startIdx + 1; | |
| $outNBElement = $nbBar; | |
| $outBegIdx = $startIdx; | |
| $currentBar = $startIdx; | |
| $outIdx = 0; | |
| $ad = 0.0; | |
| while ($nbBar != 0) { | |
| $high = $inHigh[$currentBar]; | |
| $low = $inLow[$currentBar]; | |
| $tmp = $high - $low; | |
| $close = $inClose[$currentBar]; | |
| if ($tmp > 0.0) { | |
| $ad += ((($close - $low) - ($high - $close)) / $tmp) * ((double)$inVolume[$currentBar]); | |
| } | |
| $outReal[$outIdx++] = $ad; | |
| $currentBar++; | |
| $nbBar--; | |
| } | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param float[] $inHigh | |
| * @param float[] $inLow | |
| * @param float[] $inClose | |
| * @param float[] $inVolume | |
| * @param int $optInFastPeriod | |
| * @param int $optInSlowPeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param float[] $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function adOsc(int $startIdx, int $endIdx, array $inHigh, array $inLow, array $inClose, array $inVolume, int $optInFastPeriod, int $optInSlowPeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInFastPeriod == (PHP_INT_MIN)) { | |
| $optInFastPeriod = 3; | |
| } elseif (((int)$optInFastPeriod < 2) || ((int)$optInFastPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInSlowPeriod == (PHP_INT_MIN)) { | |
| $optInSlowPeriod = 10; | |
| } elseif (((int)$optInSlowPeriod < 2) || ((int)$optInSlowPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInFastPeriod < $optInSlowPeriod) { | |
| $slowestPeriod = $optInSlowPeriod; | |
| } else { | |
| $slowestPeriod = $optInFastPeriod; | |
| } | |
| $lookbackTotal = Lookback::emaLookback($slowestPeriod); | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outBegIdx = $startIdx; | |
| $today = $startIdx - $lookbackTotal; | |
| $ad = 0.0; | |
| $fastK = ((double)2.0 / ((double)($optInFastPeriod + 1))); | |
| $one_minus_fastK = 1.0 - $fastK; | |
| $slowK = ((double)2.0 / ((double)($optInSlowPeriod + 1))); | |
| $one_minus_slowK = 1.0 - $slowK; | |
| { | |
| $high = $inHigh[$today]; | |
| $low = $inLow[$today]; | |
| $tmp = $high - $low; | |
| $close = $inClose[$today]; | |
| if ($tmp > 0.0) { | |
| $ad += ((($close - $low) - ($high - $close)) / $tmp) * ((double)$inVolume[$today]); | |
| } | |
| $today++; | |
| }; | |
| $fastEMA = $ad; | |
| $slowEMA = $ad; | |
| while ($today < $startIdx) { | |
| { | |
| $high = $inHigh[$today]; | |
| $low = $inLow[$today]; | |
| $tmp = $high - $low; | |
| $close = $inClose[$today]; | |
| if ($tmp > 0.0) { | |
| $ad += ((($close - $low) - ($high - $close)) / $tmp) * ((double)$inVolume[$today]); | |
| } | |
| $today++; | |
| }; | |
| $fastEMA = ($fastK * $ad) + ($one_minus_fastK * $fastEMA); | |
| $slowEMA = ($slowK * $ad) + ($one_minus_slowK * $slowEMA); | |
| } | |
| $outIdx = 0; | |
| while ($today <= $endIdx) { | |
| { | |
| $high = $inHigh[$today]; | |
| $low = $inLow[$today]; | |
| $tmp = $high - $low; | |
| $close = $inClose[$today]; | |
| if ($tmp > 0.0) { | |
| $ad += ((($close - $low) - ($high - $close)) / $tmp) * ((double)$inVolume[$today]); | |
| } | |
| $today++; | |
| }; | |
| $fastEMA = ($fastK * $ad) + ($one_minus_fastK * $fastEMA); | |
| $slowEMA = ($slowK * $ad) + ($one_minus_slowK * $slowEMA); | |
| $outReal[$outIdx++] = $fastEMA - $slowEMA; | |
| } | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param float[] $inHigh | |
| * @param float[] $inLow | |
| * @param float[] $inClose | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param float[] $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function atr(int $startIdx, int $endIdx, array $inHigh, array $inLow, array $inClose, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $outBegIdx1 = 0; | |
| $outNbElement1 = 0; | |
| $prevATRTemp = static::double(1); | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 1) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| $lookbackTotal = Lookback::atrLookback($optInTimePeriod); | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| return ReturnCode::Success; | |
| } | |
| if ($optInTimePeriod <= 1) { | |
| return VolatilityIndicators::trueRange($startIdx, $endIdx, $inHigh, $inLow, $inClose, $outBegIdx, $outNBElement, $outReal); | |
| } | |
| $tempBuffer = static::double($lookbackTotal + ($endIdx - $startIdx) + 1); | |
| $retCode = VolatilityIndicators::trueRange(($startIdx - $lookbackTotal + 1), $endIdx, $inHigh, $inLow, $inClose, $outBegIdx1, $outNbElement1, $tempBuffer); | |
| if ($retCode != ReturnCode::Success) { | |
| return $retCode; | |
| } | |
| $retCode = static::TA_INT_SMA($optInTimePeriod - 1, $optInTimePeriod - 1, $tempBuffer, $optInTimePeriod, $outBegIdx1, $outNbElement1, $prevATRTemp); | |
| if ($retCode != ReturnCode::Success) { | |
| return $retCode; | |
| } | |
| $prevATR = $prevATRTemp[0]; | |
| $today = $optInTimePeriod; | |
| $outIdx = (static::$unstablePeriod[UnstablePeriodFunctionID::ATR]); | |
| while ($outIdx != 0) { | |
| $prevATR *= $optInTimePeriod - 1; | |
| $prevATR += $tempBuffer[$today++]; | |
| $prevATR /= $optInTimePeriod; | |
| $outIdx--; | |
| } | |
| $outIdx = 1; | |
| $outReal[0] = $prevATR; | |
| $nbATR = ($endIdx - $startIdx) + 1; | |
| while (--$nbATR != 0) { | |
| $prevATR *= $optInTimePeriod - 1; | |
| $prevATR += $tempBuffer[$today++]; | |
| $prevATR /= $optInTimePeriod; | |
| $outReal[$outIdx++] = $prevATR; | |
| } | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $outIdx; | |
| return $retCode; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param array $inVolume | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function obv(int $startIdx, int $endIdx, array $inReal, array &$inVolume, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $prevOBV = $inVolume[$startIdx]; | |
| $prevReal = $inReal[$startIdx]; | |
| $outIdx = 0; | |
| for ($i = $startIdx; $i <= $endIdx; $i++) { | |
| $tempReal = $inReal[$i]; | |
| if ($tempReal > $prevReal) { | |
| $prevOBV += $inVolume[$i]; | |
| } elseif ($tempReal < $prevReal) { | |
| $prevOBV -= $inVolume[$i]; | |
| } | |
| $outReal[$outIdx++] = $prevOBV; | |
| $prevReal = $tempReal; | |
| } | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| } |