Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 30 |
CRAP | |
74.64% |
1451 / 1944 |
| LupeCode\phpTraderNative\TALib\Core\MomentumIndicators | |
0.00% |
0 / 1 |
|
0.00% |
0 / 30 |
6308.04 | |
74.64% |
1451 / 1944 |
| adx | |
0.00% |
0 / 1 |
80.79 | |
75.18% |
106 / 141 |
|||
| adxr | |
0.00% |
0 / 1 |
10.58 | |
73.08% |
19 / 26 |
|||
| apo | |
0.00% |
0 / 1 |
11.64 | |
61.54% |
8 / 13 |
|||
| aroon | |
0.00% |
0 / 1 |
16.33 | |
89.09% |
49 / 55 |
|||
| aroonOsc | |
0.00% |
0 / 1 |
16.33 | |
89.09% |
49 / 55 |
|||
| bop | |
0.00% |
0 / 1 |
4.10 | |
81.82% |
9 / 11 |
|||
| cci | |
0.00% |
0 / 1 |
18.91 | |
81.25% |
39 / 48 |
|||
| cmo | |
0.00% |
0 / 1 |
97.85 | |
52.63% |
50 / 95 |
|||
| dx | |
0.00% |
0 / 1 |
39.08 | |
88.50% |
100 / 113 |
|||
| macd | |
0.00% |
0 / 1 |
14.00 | |
70.83% |
17 / 24 |
|||
| macdExt | |
0.00% |
0 / 1 |
46.93 | |
65.85% |
54 / 82 |
|||
| macdFix | |
0.00% |
0 / 1 |
5.16 | |
81.25% |
13 / 16 |
|||
| mfi | |
0.00% |
0 / 1 |
39.39 | |
70.10% |
68 / 97 |
|||
| minusDI | |
0.00% |
0 / 1 |
78.18 | |
67.21% |
82 / 122 |
|||
| minusDM | |
0.00% |
0 / 1 |
25.57 | |
78.21% |
61 / 78 |
|||
| mom | |
0.00% |
0 / 1 |
9.73 | |
70.00% |
14 / 20 |
|||
| plusDI | |
0.00% |
0 / 1 |
78.18 | |
67.21% |
82 / 122 |
|||
| plusDM | |
0.00% |
0 / 1 |
57.53 | |
56.41% |
44 / 78 |
|||
| ppo | |
0.00% |
0 / 1 |
8.66 | |
78.26% |
18 / 23 |
|||
| roc | |
0.00% |
0 / 1 |
11.01 | |
70.83% |
17 / 24 |
|||
| rocP | |
0.00% |
0 / 1 |
11.01 | |
70.83% |
17 / 24 |
|||
| rocR | |
0.00% |
0 / 1 |
11.01 | |
70.83% |
17 / 24 |
|||
| rocR100 | |
0.00% |
0 / 1 |
11.01 | |
70.83% |
17 / 24 |
|||
| rsi | |
0.00% |
0 / 1 |
95.33 | |
53.19% |
50 / 94 |
|||
| stoch | |
0.00% |
0 / 1 |
40.19 | |
80.00% |
76 / 95 |
|||
| stochF | |
0.00% |
0 / 1 |
34.61 | |
81.18% |
69 / 85 |
|||
| stochRsi | |
0.00% |
0 / 1 |
22.48 | |
73.33% |
44 / 60 |
|||
| trix | |
0.00% |
0 / 1 |
20.51 | |
70.97% |
44 / 62 |
|||
| ultOsc | |
0.00% |
0 / 1 |
48 | |
95.43% |
167 / 175 |
|||
| willR | |
0.00% |
0 / 1 |
17.51 | |
87.93% |
51 / 58 |
|||
| <?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\Classes\MoneyFlow; | |
| use LupeCode\phpTraderNative\TALib\Enum\Compatibility; | |
| use LupeCode\phpTraderNative\TALib\Enum\ReturnCode; | |
| use LupeCode\phpTraderNative\TALib\Enum\UnstablePeriodFunctionID; | |
| class MomentumIndicators extends Core | |
| { | |
| /** | |
| * @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 adx(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; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $lookbackTotal = (2 * $optInTimePeriod) + (static::$unstablePeriod[UnstablePeriodFunctionID::ADX]) - 1; | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outBegIdx = $today = $startIdx; | |
| $prevMinusDM = 0.0; | |
| $prevPlusDM = 0.0; | |
| $prevTR = 0.0; | |
| $today = $startIdx - $lookbackTotal; | |
| $prevHigh = $inHigh[$today]; | |
| $prevLow = $inLow[$today]; | |
| $prevClose = $inClose[$today]; | |
| $i = $optInTimePeriod - 1; | |
| while ($i-- > 0) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| $prevMinusDM += $diffM; | |
| } elseif (($diffP > 0) && ($diffP > $diffM)) { | |
| $prevPlusDM += $diffP; | |
| } | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| $prevTR += $tempReal; | |
| $prevClose = $inClose[$today]; | |
| } | |
| $sumDX = 0.0; | |
| $i = $optInTimePeriod; | |
| while ($i-- > 0) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| $prevMinusDM -= $prevMinusDM / $optInTimePeriod; | |
| $prevPlusDM -= $prevPlusDM / $optInTimePeriod; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| $prevMinusDM += $diffM; | |
| } elseif (($diffP > 0) && ($diffP > $diffM)) { | |
| $prevPlusDM += $diffP; | |
| } | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| $prevTR = $prevTR - ($prevTR / $optInTimePeriod) + $tempReal; | |
| $prevClose = $inClose[$today]; | |
| if (!(((-0.00000001) < $prevTR) && ($prevTR < 0.00000001))) { | |
| $minusDI = (100.0 * ($prevMinusDM / $prevTR)); | |
| $plusDI = (100.0 * ($prevPlusDM / $prevTR)); | |
| $tempReal = $minusDI + $plusDI; | |
| if (!(((-0.00000001) < $tempReal) && ($tempReal < 0.00000001))) { | |
| $sumDX += (100.0 * (abs($minusDI - $plusDI) / $tempReal)); | |
| } | |
| } | |
| } | |
| $prevADX = ($sumDX / $optInTimePeriod); | |
| $i = (static::$unstablePeriod[UnstablePeriodFunctionID::ADX]); | |
| while ($i-- > 0) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| $prevMinusDM -= $prevMinusDM / $optInTimePeriod; | |
| $prevPlusDM -= $prevPlusDM / $optInTimePeriod; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| $prevMinusDM += $diffM; | |
| } elseif (($diffP > 0) && ($diffP > $diffM)) { | |
| $prevPlusDM += $diffP; | |
| } | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| $prevTR = $prevTR - ($prevTR / $optInTimePeriod) + $tempReal; | |
| $prevClose = $inClose[$today]; | |
| if (!(((-0.00000001) < $prevTR) && ($prevTR < 0.00000001))) { | |
| $minusDI = (100.0 * ($prevMinusDM / $prevTR)); | |
| $plusDI = (100.0 * ($prevPlusDM / $prevTR)); | |
| $tempReal = $minusDI + $plusDI; | |
| if (!(((-0.00000001) < $tempReal) && ($tempReal < 0.00000001))) { | |
| $tempReal = (100.0 * (abs($minusDI - $plusDI) / $tempReal)); | |
| $prevADX = ((($prevADX * ($optInTimePeriod - 1)) + $tempReal) / $optInTimePeriod); | |
| } | |
| } | |
| } | |
| $outReal[0] = $prevADX; | |
| $outIdx = 1; | |
| while ($today < $endIdx) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| $prevMinusDM -= $prevMinusDM / $optInTimePeriod; | |
| $prevPlusDM -= $prevPlusDM / $optInTimePeriod; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| $prevMinusDM += $diffM; | |
| } elseif (($diffP > 0) && ($diffP > $diffM)) { | |
| $prevPlusDM += $diffP; | |
| } | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| $prevTR = $prevTR - ($prevTR / $optInTimePeriod) + $tempReal; | |
| $prevClose = $inClose[$today]; | |
| if (!(((-0.00000001) < $prevTR) && ($prevTR < 0.00000001))) { | |
| $minusDI = (100.0 * ($prevMinusDM / $prevTR)); | |
| $plusDI = (100.0 * ($prevPlusDM / $prevTR)); | |
| $tempReal = $minusDI + $plusDI; | |
| if (!(((-0.00000001) < $tempReal) && ($tempReal < 0.00000001))) { | |
| $tempReal = (100.0 * (abs($minusDI - $plusDI) / $tempReal)); | |
| $prevADX = ((($prevADX * ($optInTimePeriod - 1)) + $tempReal) / $optInTimePeriod); | |
| } | |
| } | |
| $outReal[$outIdx++] = $prevADX; | |
| } | |
| $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 adxr(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; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $adxrLookback = Lookback::adxrLookback($optInTimePeriod); | |
| if ($startIdx < $adxrLookback) { | |
| $startIdx = $adxrLookback; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $adx = static::double($endIdx - $startIdx + $optInTimePeriod); | |
| $ReturnCode = self::adx($startIdx - ($optInTimePeriod - 1), $endIdx, $inHigh, $inLow, $inClose, $optInTimePeriod, $outBegIdx, $outNBElement, $adx); | |
| if ($ReturnCode != ReturnCode::Success) { | |
| return $ReturnCode; | |
| } | |
| $i = $optInTimePeriod - 1; | |
| $j = 0; | |
| $outIdx = 0; | |
| $nbElement = $endIdx - $startIdx + 2; | |
| while (--$nbElement != 0) { | |
| $outReal[$outIdx++] = (($adx[$i++] + $adx[$j++]) / 2.0); | |
| } | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param float[] $inReal | |
| * @param int $optInFastPeriod | |
| * @param int $optInSlowPeriod | |
| * @param int $optInMAType | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param float[] $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function apo(int $startIdx, int $endIdx, array $inReal, int $optInFastPeriod, int $optInSlowPeriod, int $optInMAType, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInFastPeriod == (PHP_INT_MIN)) { | |
| $optInFastPeriod = 12; | |
| } elseif (((int)$optInFastPeriod < 2) || ((int)$optInFastPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInSlowPeriod == (PHP_INT_MIN)) { | |
| $optInSlowPeriod = 26; | |
| } elseif (((int)$optInSlowPeriod < 2) || ((int)$optInSlowPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $tempBuffer = static::double($endIdx - $startIdx + 1); | |
| $ReturnCode = static::TA_INT_PO($startIdx, $endIdx, $inReal, $optInFastPeriod, $optInSlowPeriod, $optInMAType, $outBegIdx, $outNBElement, $outReal, $tempBuffer, false); | |
| return $ReturnCode; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param float[] $inHigh | |
| * @param float[] $inLow | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param float[] $outAroonDown | |
| * @param float[] $outAroonUp | |
| * | |
| * @return int | |
| */ | |
| public static function aroon(int $startIdx, int $endIdx, array $inHigh, array $inLow, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outAroonDown, array &$outAroonUp): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($startIdx < $optInTimePeriod) { | |
| $startIdx = $optInTimePeriod; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| $today = $startIdx; | |
| $trailingIdx = $startIdx - $optInTimePeriod; | |
| $lowestIdx = -1; | |
| $highestIdx = -1; | |
| $lowest = 0.0; | |
| $highest = 0.0; | |
| $factor = (double)100.0 / (double)$optInTimePeriod; | |
| while ($today <= $endIdx) { | |
| $tmp = $inLow[$today]; | |
| if ($lowestIdx < $trailingIdx) { | |
| $lowestIdx = $trailingIdx; | |
| $lowest = $inLow[$lowestIdx]; | |
| $i = $lowestIdx; | |
| while (++$i <= $today) { | |
| $tmp = $inLow[$i]; | |
| if ($tmp <= $lowest) { | |
| $lowestIdx = $i; | |
| $lowest = $tmp; | |
| } | |
| } | |
| } elseif ($tmp <= $lowest) { | |
| $lowestIdx = $today; | |
| $lowest = $tmp; | |
| } | |
| $tmp = $inHigh[$today]; | |
| if ($highestIdx < $trailingIdx) { | |
| $highestIdx = $trailingIdx; | |
| $highest = $inHigh[$highestIdx]; | |
| $i = $highestIdx; | |
| while (++$i <= $today) { | |
| $tmp = $inHigh[$i]; | |
| if ($tmp >= $highest) { | |
| $highestIdx = $i; | |
| $highest = $tmp; | |
| } | |
| } | |
| } elseif ($tmp >= $highest) { | |
| $highestIdx = $today; | |
| $highest = $tmp; | |
| } | |
| $outAroonUp[$outIdx] = $factor * ($optInTimePeriod - ($today - $highestIdx)); | |
| $outAroonDown[$outIdx] = $factor * ($optInTimePeriod - ($today - $lowestIdx)); | |
| $outIdx++; | |
| $trailingIdx++; | |
| $today++; | |
| } | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param float[] $inHigh | |
| * @param float[] $inLow | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param float[] $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function aroonOsc(int $startIdx, int $endIdx, array $inHigh, array $inLow, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($startIdx < $optInTimePeriod) { | |
| $startIdx = $optInTimePeriod; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| $today = $startIdx; | |
| $trailingIdx = $startIdx - $optInTimePeriod; | |
| $lowestIdx = -1; | |
| $highestIdx = -1; | |
| $lowest = 0.0; | |
| $highest = 0.0; | |
| $factor = (double)100.0 / (double)$optInTimePeriod; | |
| while ($today <= $endIdx) { | |
| $tmp = $inLow[$today]; | |
| if ($lowestIdx < $trailingIdx) { | |
| $lowestIdx = $trailingIdx; | |
| $lowest = $inLow[$lowestIdx]; | |
| $i = $lowestIdx; | |
| while (++$i <= $today) { | |
| $tmp = $inLow[$i]; | |
| if ($tmp <= $lowest) { | |
| $lowestIdx = $i; | |
| $lowest = $tmp; | |
| } | |
| } | |
| } elseif ($tmp <= $lowest) { | |
| $lowestIdx = $today; | |
| $lowest = $tmp; | |
| } | |
| $tmp = $inHigh[$today]; | |
| if ($highestIdx < $trailingIdx) { | |
| $highestIdx = $trailingIdx; | |
| $highest = $inHigh[$highestIdx]; | |
| $i = $highestIdx; | |
| while (++$i <= $today) { | |
| $tmp = $inHigh[$i]; | |
| if ($tmp >= $highest) { | |
| $highestIdx = $i; | |
| $highest = $tmp; | |
| } | |
| } | |
| } elseif ($tmp >= $highest) { | |
| $highestIdx = $today; | |
| $highest = $tmp; | |
| } | |
| $aroon = $factor * ($highestIdx - $lowestIdx); | |
| $outReal[$outIdx] = $aroon; | |
| $outIdx++; | |
| $trailingIdx++; | |
| $today++; | |
| } | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param float[] $inOpen | |
| * @param float[] $inHigh | |
| * @param float[] $inLow | |
| * @param float[] $inClose | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param float[] $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function bop(int $startIdx, int $endIdx, array $inOpen, array $inHigh, array $inLow, array $inClose, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $outIdx = 0; | |
| for ($i = $startIdx; $i <= $endIdx; $i++) { | |
| $tempReal = $inHigh[$i] - $inLow[$i]; | |
| if (($tempReal < 0.00000001)) { | |
| $outReal[$outIdx++] = 0.0; | |
| } else { | |
| $outReal[$outIdx++] = ($inClose[$i] - $inOpen[$i]) / $tempReal; | |
| } | |
| } | |
| $outNBElement = $outIdx; | |
| $outBegIdx = $startIdx; | |
| 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 cci(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; | |
| } | |
| $circBuffer_Idx = 0; | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $lookbackTotal = ($optInTimePeriod - 1); | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| { | |
| if ($optInTimePeriod <= 0) { | |
| return ReturnCode::AllocError; | |
| } | |
| $circBuffer = static::double($optInTimePeriod); | |
| $maxIdx_circBuffer = ($optInTimePeriod - 1); | |
| }; | |
| $i = $startIdx - $lookbackTotal; | |
| if ($optInTimePeriod > 1) { | |
| while ($i < $startIdx) { | |
| $circBuffer[$circBuffer_Idx] = ($inHigh[$i] + $inLow[$i] + $inClose[$i]) / 3; | |
| $i++; | |
| { | |
| $circBuffer_Idx++; | |
| if ($circBuffer_Idx > $maxIdx_circBuffer) { | |
| $circBuffer_Idx = 0; | |
| } | |
| }; | |
| } | |
| } | |
| $outIdx = 0; | |
| do { | |
| $lastValue = ($inHigh[$i] + $inLow[$i] + $inClose[$i]) / 3; | |
| $circBuffer[$circBuffer_Idx] = $lastValue; | |
| $theAverage = 0; | |
| for ($j = 0; $j < $optInTimePeriod; $j++) { | |
| $theAverage += $circBuffer[$j]; | |
| } | |
| $theAverage /= $optInTimePeriod; | |
| $tempReal2 = 0; | |
| for ($j = 0; $j < $optInTimePeriod; $j++) { | |
| $tempReal2 += abs($circBuffer[$j] - $theAverage); | |
| } | |
| $tempReal = $lastValue - $theAverage; | |
| if (($tempReal != 0.0) && ($tempReal2 != 0.0)) { | |
| $outReal[$outIdx++] = $tempReal / (0.015 * ($tempReal2 / $optInTimePeriod)); | |
| } else { | |
| $outReal[$outIdx++] = 0.0; | |
| } | |
| { | |
| $circBuffer_Idx++; | |
| if ($circBuffer_Idx > $maxIdx_circBuffer) { | |
| $circBuffer_Idx = 0; | |
| } | |
| }; | |
| $i++; | |
| } while ($i <= $endIdx); | |
| $outNBElement = $outIdx; | |
| $outBegIdx = $startIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function cmo(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| $lookbackTotal = Lookback::cmoLookback($optInTimePeriod); | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| if ($optInTimePeriod == 1) { | |
| $outBegIdx = $startIdx; | |
| $i = ($endIdx - $startIdx) + 1; | |
| $outNBElement = $i; | |
| $outReal = \array_slice($inReal, 0, $i); | |
| return ReturnCode::Success; | |
| } | |
| $today = $startIdx - $lookbackTotal; | |
| $prevValue = $inReal[$today]; | |
| $unstablePeriod = (static::$unstablePeriod[UnstablePeriodFunctionID::CMO]); | |
| if (($unstablePeriod == 0) && | |
| ((static::$compatibility) == Compatibility::Metastock)) { | |
| $savePrevValue = $prevValue; | |
| $prevGain = 0.0; | |
| $prevLoss = 0.0; | |
| for ($i = $optInTimePeriod; $i > 0; $i--) { | |
| $tempValue1 = $inReal[$today++]; | |
| $tempValue2 = $tempValue1 - $prevValue; | |
| $prevValue = $tempValue1; | |
| if ($tempValue2 < 0) { | |
| $prevLoss -= $tempValue2; | |
| } else { | |
| $prevGain += $tempValue2; | |
| } | |
| } | |
| $tempValue1 = $prevLoss / $optInTimePeriod; | |
| $tempValue2 = $prevGain / $optInTimePeriod; | |
| $tempValue3 = $tempValue2 - $tempValue1; | |
| $tempValue4 = $tempValue1 + $tempValue2; | |
| if (!(((-0.00000001) < $tempValue4) && ($tempValue4 < 0.00000001))) { | |
| $outReal[$outIdx++] = 100 * ($tempValue3 / $tempValue4); | |
| } else { | |
| $outReal[$outIdx++] = 0.0; | |
| } | |
| if ($today > $endIdx) { | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| $today -= $optInTimePeriod; | |
| $prevValue = $savePrevValue; | |
| } | |
| $prevGain = 0.0; | |
| $prevLoss = 0.0; | |
| $today++; | |
| for ($i = $optInTimePeriod; $i > 0; $i--) { | |
| $tempValue1 = $inReal[$today++]; | |
| $tempValue2 = $tempValue1 - $prevValue; | |
| $prevValue = $tempValue1; | |
| if ($tempValue2 < 0) { | |
| $prevLoss -= $tempValue2; | |
| } else { | |
| $prevGain += $tempValue2; | |
| } | |
| } | |
| $prevLoss /= $optInTimePeriod; | |
| $prevGain /= $optInTimePeriod; | |
| if ($today > $startIdx) { | |
| $tempValue1 = $prevGain + $prevLoss; | |
| if (!(((-0.00000001) < $tempValue1) && ($tempValue1 < 0.00000001))) { | |
| $outReal[$outIdx++] = 100.0 * (($prevGain - $prevLoss) / $tempValue1); | |
| } else { | |
| $outReal[$outIdx++] = 0.0; | |
| } | |
| } else { | |
| while ($today < $startIdx) { | |
| $tempValue1 = $inReal[$today]; | |
| $tempValue2 = $tempValue1 - $prevValue; | |
| $prevValue = $tempValue1; | |
| $prevLoss *= ($optInTimePeriod - 1); | |
| $prevGain *= ($optInTimePeriod - 1); | |
| if ($tempValue2 < 0) { | |
| $prevLoss -= $tempValue2; | |
| } else { | |
| $prevGain += $tempValue2; | |
| } | |
| $prevLoss /= $optInTimePeriod; | |
| $prevGain /= $optInTimePeriod; | |
| $today++; | |
| } | |
| } | |
| while ($today <= $endIdx) { | |
| $tempValue1 = $inReal[$today++]; | |
| $tempValue2 = $tempValue1 - $prevValue; | |
| $prevValue = $tempValue1; | |
| $prevLoss *= ($optInTimePeriod - 1); | |
| $prevGain *= ($optInTimePeriod - 1); | |
| if ($tempValue2 < 0) { | |
| $prevLoss -= $tempValue2; | |
| } else { | |
| $prevGain += $tempValue2; | |
| } | |
| $prevLoss /= $optInTimePeriod; | |
| $prevGain /= $optInTimePeriod; | |
| $tempValue1 = $prevGain + $prevLoss; | |
| if (!(((-0.00000001) < $tempValue1) && ($tempValue1 < 0.00000001))) { | |
| $outReal[$outIdx++] = 100.0 * (($prevGain - $prevLoss) / $tempValue1); | |
| } else { | |
| $outReal[$outIdx++] = 0.0; | |
| } | |
| } | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inHigh | |
| * @param array $inLow | |
| * @param array $inClose | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function dx(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; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInTimePeriod > 1) { | |
| $lookbackTotal = $optInTimePeriod + (static::$unstablePeriod[UnstablePeriodFunctionID::DX]); | |
| } else { | |
| $lookbackTotal = 2; | |
| } | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| $outBegIdx = $today = $startIdx; | |
| $prevMinusDM = 0.0; | |
| $prevPlusDM = 0.0; | |
| $prevTR = 0.0; | |
| $today = $startIdx - $lookbackTotal; | |
| $prevHigh = $inHigh[$today]; | |
| $prevLow = $inLow[$today]; | |
| $prevClose = $inClose[$today]; | |
| $i = $optInTimePeriod - 1; | |
| while ($i-- > 0) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| $prevMinusDM += $diffM; | |
| } elseif (($diffP > 0) && ($diffP > $diffM)) { | |
| $prevPlusDM += $diffP; | |
| } | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| $prevTR += $tempReal; | |
| $prevClose = $inClose[$today]; | |
| } | |
| $i = (static::$unstablePeriod[UnstablePeriodFunctionID::DX]) + 1; | |
| while ($i-- != 0) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| $prevMinusDM -= $prevMinusDM / $optInTimePeriod; | |
| $prevPlusDM -= $prevPlusDM / $optInTimePeriod; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| $prevMinusDM += $diffM; | |
| } elseif (($diffP > 0) && ($diffP > $diffM)) { | |
| $prevPlusDM += $diffP; | |
| } | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| $prevTR = $prevTR - ($prevTR / $optInTimePeriod) + $tempReal; | |
| $prevClose = $inClose[$today]; | |
| } | |
| if (!(((-0.00000001) < $prevTR) && ($prevTR < 0.00000001))) { | |
| $minusDI = (100.0 * ($prevMinusDM / $prevTR)); | |
| $plusDI = (100.0 * ($prevPlusDM / $prevTR)); | |
| $tempReal = $minusDI + $plusDI; | |
| if (!(((-0.00000001) < $tempReal) && ($tempReal < 0.00000001))) { | |
| $outReal[0] = (100.0 * (abs($minusDI - $plusDI) / $tempReal)); | |
| } else { | |
| $outReal[0] = 0.0; | |
| } | |
| } else { | |
| $outReal[0] = 0.0; | |
| } | |
| $outIdx = 1; | |
| while ($today < $endIdx) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| $prevMinusDM -= $prevMinusDM / $optInTimePeriod; | |
| $prevPlusDM -= $prevPlusDM / $optInTimePeriod; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| $prevMinusDM += $diffM; | |
| } elseif (($diffP > 0) && ($diffP > $diffM)) { | |
| $prevPlusDM += $diffP; | |
| } | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| $prevTR = $prevTR - ($prevTR / $optInTimePeriod) + $tempReal; | |
| $prevClose = $inClose[$today]; | |
| if (!(((-0.00000001) < $prevTR) && ($prevTR < 0.00000001))) { | |
| $minusDI = (100.0 * ($prevMinusDM / $prevTR)); | |
| $plusDI = (100.0 * ($prevPlusDM / $prevTR)); | |
| $tempReal = $minusDI + $plusDI; | |
| if (!(((-0.00000001) < $tempReal) && ($tempReal < 0.00000001))) { | |
| $outReal[$outIdx] = (100.0 * (abs($minusDI - $plusDI) / $tempReal)); | |
| } else { | |
| $outReal[$outIdx] = $outReal[$outIdx - 1]; | |
| } | |
| } else { | |
| $outReal[$outIdx] = $outReal[$outIdx - 1]; | |
| } | |
| $outIdx++; | |
| } | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInFastPeriod | |
| * @param int $optInSlowPeriod | |
| * @param int $optInSignalPeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outMACD | |
| * @param array $outMACDSignal | |
| * @param array $outMACDHist | |
| * | |
| * @return int | |
| */ | |
| public static function macd(int $startIdx, int $endIdx, array $inReal, int $optInFastPeriod, int $optInSlowPeriod, int $optInSignalPeriod, int &$outBegIdx, int &$outNBElement, array &$outMACD, array &$outMACDSignal, array &$outMACDHist): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInFastPeriod == (PHP_INT_MIN)) { | |
| $optInFastPeriod = 12; | |
| } elseif (((int)$optInFastPeriod < 2) || ((int)$optInFastPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInSlowPeriod == (PHP_INT_MIN)) { | |
| $optInSlowPeriod = 26; | |
| } elseif (((int)$optInSlowPeriod < 2) || ((int)$optInSlowPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInSignalPeriod == (PHP_INT_MIN)) { | |
| $optInSignalPeriod = 9; | |
| } elseif (((int)$optInSignalPeriod < 1) || ((int)$optInSignalPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| return static::TA_INT_MACD( | |
| $startIdx, $endIdx, $inReal, | |
| $optInFastPeriod, | |
| $optInSlowPeriod, | |
| $optInSignalPeriod, | |
| $outBegIdx, | |
| $outNBElement, | |
| $outMACD, | |
| $outMACDSignal, | |
| $outMACDHist | |
| ); | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInFastPeriod | |
| * @param int $optInFastMAType | |
| * @param int $optInSlowPeriod | |
| * @param int $optInSlowMAType | |
| * @param int $optInSignalPeriod | |
| * @param int $optInSignalMAType | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outMACD | |
| * @param array $outMACDSignal | |
| * @param array $outMACDHist | |
| * | |
| * @return int | |
| */ | |
| public static function macdExt(int $startIdx, int $endIdx, array $inReal, int $optInFastPeriod, int $optInFastMAType, int $optInSlowPeriod, int $optInSlowMAType, int $optInSignalPeriod, int $optInSignalMAType, int &$outBegIdx, int &$outNBElement, array &$outMACD, array &$outMACDSignal, array &$outMACDHist): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $outBegIdx1 = 0; | |
| $outNbElement1 = 0; | |
| $outBegIdx2 = 0; | |
| $outNbElement2 = 0; | |
| if ((int)$optInFastPeriod == (PHP_INT_MIN)) { | |
| $optInFastPeriod = 12; | |
| } elseif (((int)$optInFastPeriod < 2) || ((int)$optInFastPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInSlowPeriod == (PHP_INT_MIN)) { | |
| $optInSlowPeriod = 26; | |
| } elseif (((int)$optInSlowPeriod < 2) || ((int)$optInSlowPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInSignalPeriod == (PHP_INT_MIN)) { | |
| $optInSignalPeriod = 9; | |
| } elseif (((int)$optInSignalPeriod < 1) || ((int)$optInSignalPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInSlowPeriod < $optInFastPeriod) { | |
| $tempInteger = $optInSlowPeriod; | |
| $optInSlowPeriod = $optInFastPeriod; | |
| $optInFastPeriod = $tempInteger; | |
| $tempMAType = $optInSlowMAType; | |
| $optInSlowMAType = $optInFastMAType; | |
| $optInFastMAType = $tempMAType; | |
| } | |
| $lookbackLargest = Lookback::movingAverageLookback($optInFastPeriod, $optInFastMAType); | |
| $tempInteger = Lookback::movingAverageLookback($optInSlowPeriod, $optInSlowMAType); | |
| if ($tempInteger > $lookbackLargest) { | |
| $lookbackLargest = $tempInteger; | |
| } | |
| $lookbackSignal = Lookback::movingAverageLookback($optInSignalPeriod, $optInSignalMAType); | |
| $lookbackTotal = $lookbackSignal + $lookbackLargest; | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $tempInteger = ($endIdx - $startIdx) + 1 + $lookbackSignal; | |
| $fastMABuffer = static::double($tempInteger); | |
| $slowMABuffer = static::double($tempInteger); | |
| $tempInteger = $startIdx - $lookbackSignal; | |
| $ReturnCode = OverlapStudies::movingAverage( | |
| $tempInteger, $endIdx, | |
| $inReal, $optInSlowPeriod, $optInSlowMAType, | |
| $outBegIdx1, $outNbElement1, | |
| $slowMABuffer | |
| ); | |
| if ($ReturnCode != ReturnCode::Success) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| $ReturnCode = OverlapStudies::movingAverage( | |
| $tempInteger, $endIdx, | |
| $inReal, $optInFastPeriod, $optInFastMAType, | |
| $outBegIdx2, $outNbElement2, | |
| $fastMABuffer | |
| ); | |
| if ($ReturnCode != ReturnCode::Success) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| if (($outBegIdx1 != $tempInteger) || | |
| ($outBegIdx2 != $tempInteger) || | |
| ($outNbElement1 != $outNbElement2) || | |
| ($outNbElement1 != ($endIdx - $startIdx) + 1 + $lookbackSignal)) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return (ReturnCode::InternalError); | |
| } | |
| for ($i = 0; $i < $outNbElement1; $i++) { | |
| $fastMABuffer[$i] = $fastMABuffer[$i] - $slowMABuffer[$i]; | |
| } | |
| //System::arraycopy($fastMABuffer, $lookbackSignal, $outMACD, 0, ($endIdx - $startIdx) + 1); | |
| $outMACD = \array_slice($fastMABuffer, $lookbackSignal, ($endIdx - $startIdx) + 1); | |
| $ReturnCode = OverlapStudies::movingAverage( | |
| 0, $outNbElement1 - 1, | |
| $fastMABuffer, $optInSignalPeriod, $optInSignalMAType, | |
| $outBegIdx2, $outNbElement2, $outMACDSignal | |
| ); | |
| if ($ReturnCode != ReturnCode::Success) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| for ($i = 0; $i < $outNbElement2; $i++) { | |
| $outMACDHist[$i] = $outMACD[$i] - $outMACDSignal[$i]; | |
| } | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $outNbElement2; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInSignalPeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outMACD | |
| * @param array $outMACDSignal | |
| * @param array $outMACDHist | |
| * | |
| * @return int | |
| */ | |
| public static function macdFix(int $startIdx, int $endIdx, array $inReal, int $optInSignalPeriod, int &$outBegIdx, int &$outNBElement, array &$outMACD, array &$outMACDSignal, array &$outMACDHist): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInSignalPeriod == (PHP_INT_MIN)) { | |
| $optInSignalPeriod = 9; | |
| } elseif (((int)$optInSignalPeriod < 1) || ((int)$optInSignalPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| return static::TA_INT_MACD( | |
| $startIdx, $endIdx, $inReal, | |
| 0, | |
| 0, | |
| $optInSignalPeriod, | |
| $outBegIdx, | |
| $outNBElement, | |
| $outMACD, | |
| $outMACDSignal, | |
| $outMACDHist | |
| ); | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inHigh | |
| * @param array $inLow | |
| * @param array $inClose | |
| * @param array $inVolume | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function mfi(int $startIdx, int $endIdx, array $inHigh, array $inLow, array $inClose, array &$inVolume, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $money_flow_Idx = 0; | |
| $maxIdx_money_flow = (50 - 1); | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| { | |
| if ($optInTimePeriod <= 0) { | |
| return ReturnCode::AllocError; | |
| } | |
| $money_flow = \array_pad([], $optInTimePeriod, new MoneyFlow()); | |
| for ($_money_flow_index = 0; $_money_flow_index < $optInTimePeriod; $_money_flow_index++) { | |
| $money_flow[$_money_flow_index] = new MoneyFlow(); | |
| } | |
| $maxIdx_money_flow = ($optInTimePeriod - 1); | |
| }; | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| $lookbackTotal = $optInTimePeriod + (static::$unstablePeriod[UnstablePeriodFunctionID::MFI]); | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| $today = $startIdx - $lookbackTotal; | |
| $prevValue = ($inHigh[$today] + $inLow[$today] + $inClose[$today]) / 3.0; | |
| $posSumMF = 0.0; | |
| $negSumMF = 0.0; | |
| $today++; | |
| for ($i = $optInTimePeriod; $i > 0; $i--) { | |
| $tempValue1 = ($inHigh[$today] + $inLow[$today] + $inClose[$today]) / 3.0; | |
| $tempValue2 = $tempValue1 - $prevValue; | |
| $prevValue = $tempValue1; | |
| $tempValue1 *= $inVolume[$today++]; | |
| if ($tempValue2 < 0) { | |
| ($money_flow[$money_flow_Idx])->negative = $tempValue1; | |
| $negSumMF += $tempValue1; | |
| ($money_flow[$money_flow_Idx])->positive = 0.0; | |
| } elseif ($tempValue2 > 0) { | |
| ($money_flow[$money_flow_Idx])->positive = $tempValue1; | |
| $posSumMF += $tempValue1; | |
| ($money_flow[$money_flow_Idx])->negative = 0.0; | |
| } else { | |
| ($money_flow[$money_flow_Idx])->positive = 0.0; | |
| ($money_flow[$money_flow_Idx])->negative = 0.0; | |
| } | |
| { | |
| $money_flow_Idx++; | |
| if ($money_flow_Idx > $maxIdx_money_flow) { | |
| $money_flow_Idx = 0; | |
| } | |
| }; | |
| } | |
| if ($today > $startIdx) { | |
| $tempValue1 = $posSumMF + $negSumMF; | |
| if ($tempValue1 < 1.0) { | |
| $outReal[$outIdx++] = 0.0; | |
| } else { | |
| $outReal[$outIdx++] = 100.0 * ($posSumMF / $tempValue1); | |
| } | |
| } else { | |
| while ($today < $startIdx) { | |
| $posSumMF -= ($money_flow[$money_flow_Idx])->positive; | |
| $negSumMF -= ($money_flow[$money_flow_Idx])->negative; | |
| $tempValue1 = ($inHigh[$today] + $inLow[$today] + $inClose[$today]) / 3.0; | |
| $tempValue2 = $tempValue1 - $prevValue; | |
| $prevValue = $tempValue1; | |
| $tempValue1 *= $inVolume[$today++]; | |
| if ($tempValue2 < 0) { | |
| ($money_flow[$money_flow_Idx])->negative = $tempValue1; | |
| $negSumMF += $tempValue1; | |
| ($money_flow[$money_flow_Idx])->positive = 0.0; | |
| } elseif ($tempValue2 > 0) { | |
| ($money_flow[$money_flow_Idx])->positive = $tempValue1; | |
| $posSumMF += $tempValue1; | |
| ($money_flow[$money_flow_Idx])->negative = 0.0; | |
| } else { | |
| ($money_flow[$money_flow_Idx])->positive = 0.0; | |
| ($money_flow[$money_flow_Idx])->negative = 0.0; | |
| } | |
| { | |
| $money_flow_Idx++; | |
| if ($money_flow_Idx > $maxIdx_money_flow) { | |
| $money_flow_Idx = 0; | |
| } | |
| }; | |
| } | |
| } | |
| while ($today <= $endIdx) { | |
| $posSumMF -= ($money_flow[$money_flow_Idx])->positive; | |
| $negSumMF -= ($money_flow[$money_flow_Idx])->negative; | |
| $tempValue1 = ($inHigh[$today] + $inLow[$today] + $inClose[$today]) / 3.0; | |
| $tempValue2 = $tempValue1 - $prevValue; | |
| $prevValue = $tempValue1; | |
| $tempValue1 *= $inVolume[$today++]; | |
| if ($tempValue2 < 0) { | |
| ($money_flow[$money_flow_Idx])->negative = $tempValue1; | |
| $negSumMF += $tempValue1; | |
| ($money_flow[$money_flow_Idx])->positive = 0.0; | |
| } elseif ($tempValue2 > 0) { | |
| ($money_flow[$money_flow_Idx])->positive = $tempValue1; | |
| $posSumMF += $tempValue1; | |
| ($money_flow[$money_flow_Idx])->negative = 0.0; | |
| } else { | |
| ($money_flow[$money_flow_Idx])->positive = 0.0; | |
| ($money_flow[$money_flow_Idx])->negative = 0.0; | |
| } | |
| $tempValue1 = $posSumMF + $negSumMF; | |
| if ($tempValue1 < 1.0) { | |
| $outReal[$outIdx++] = 0.0; | |
| } else { | |
| $outReal[$outIdx++] = 100.0 * ($posSumMF / $tempValue1); | |
| } | |
| { | |
| $money_flow_Idx++; | |
| if ($money_flow_Idx > $maxIdx_money_flow) { | |
| $money_flow_Idx = 0; | |
| } | |
| }; | |
| } | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inHigh | |
| * @param array $inLow | |
| * @param array $inClose | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function minusDI(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; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 1) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInTimePeriod > 1) { | |
| $lookbackTotal = $optInTimePeriod + (static::$unstablePeriod[UnstablePeriodFunctionID::MinusDI]); | |
| } else { | |
| $lookbackTotal = 1; | |
| } | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| if ($optInTimePeriod <= 1) { | |
| $outBegIdx = $startIdx; | |
| $today = $startIdx - 1; | |
| $prevHigh = $inHigh[$today]; | |
| $prevLow = $inLow[$today]; | |
| $prevClose = $inClose[$today]; | |
| while ($today < $endIdx) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| if ((((-0.00000001) < $tempReal) && ($tempReal < 0.00000001))) { | |
| $outReal[$outIdx++] = (double)0.0; | |
| } else { | |
| $outReal[$outIdx++] = $diffM / $tempReal; | |
| } | |
| } else { | |
| $outReal[$outIdx++] = (double)0.0; | |
| } | |
| $prevClose = $inClose[$today]; | |
| } | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| $outBegIdx = $today = $startIdx; | |
| $prevMinusDM = 0.0; | |
| $prevTR = 0.0; | |
| $today = $startIdx - $lookbackTotal; | |
| $prevHigh = $inHigh[$today]; | |
| $prevLow = $inLow[$today]; | |
| $prevClose = $inClose[$today]; | |
| $i = $optInTimePeriod - 1; | |
| while ($i-- > 0) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| $prevMinusDM += $diffM; | |
| } | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| $prevTR += $tempReal; | |
| $prevClose = $inClose[$today]; | |
| } | |
| $i = (static::$unstablePeriod[UnstablePeriodFunctionID::MinusDI]) + 1; | |
| while ($i-- != 0) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| $prevMinusDM = $prevMinusDM - ($prevMinusDM / $optInTimePeriod) + $diffM; | |
| } else { | |
| $prevMinusDM = $prevMinusDM - ($prevMinusDM / $optInTimePeriod); | |
| } | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| $prevTR = $prevTR - ($prevTR / $optInTimePeriod) + $tempReal; | |
| $prevClose = $inClose[$today]; | |
| } | |
| if (!(((-0.00000001) < $prevTR) && ($prevTR < 0.00000001))) { | |
| $outReal[0] = (100.0 * ($prevMinusDM / $prevTR)); | |
| } else { | |
| $outReal[0] = 0.0; | |
| } | |
| $outIdx = 1; | |
| while ($today < $endIdx) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| $prevMinusDM = $prevMinusDM - ($prevMinusDM / $optInTimePeriod) + $diffM; | |
| } else { | |
| $prevMinusDM = $prevMinusDM - ($prevMinusDM / $optInTimePeriod); | |
| } | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| $prevTR = $prevTR - ($prevTR / $optInTimePeriod) + $tempReal; | |
| $prevClose = $inClose[$today]; | |
| if (!(((-0.00000001) < $prevTR) && ($prevTR < 0.00000001))) { | |
| $outReal[$outIdx++] = (100.0 * ($prevMinusDM / $prevTR)); | |
| } else { | |
| $outReal[$outIdx++] = 0.0; | |
| } | |
| } | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inHigh | |
| * @param array $inLow | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function minusDM(int $startIdx, int $endIdx, array $inHigh, array $inLow, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 1) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInTimePeriod > 1) { | |
| $lookbackTotal = $optInTimePeriod + (static::$unstablePeriod[UnstablePeriodFunctionID::MinusDM]) - 1; | |
| } else { | |
| $lookbackTotal = 1; | |
| } | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| if ($optInTimePeriod <= 1) { | |
| $outBegIdx = $startIdx; | |
| $today = $startIdx - 1; | |
| $prevHigh = $inHigh[$today]; | |
| $prevLow = $inLow[$today]; | |
| while ($today < $endIdx) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| $outReal[$outIdx++] = $diffM; | |
| } else { | |
| $outReal[$outIdx++] = 0; | |
| } | |
| } | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| $outBegIdx = $startIdx; | |
| $prevMinusDM = 0.0; | |
| $today = $startIdx - $lookbackTotal; | |
| $prevHigh = $inHigh[$today]; | |
| $prevLow = $inLow[$today]; | |
| $i = $optInTimePeriod - 1; | |
| while ($i-- > 0) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| $prevMinusDM += $diffM; | |
| } | |
| } | |
| $i = (static::$unstablePeriod[UnstablePeriodFunctionID::MinusDM]); | |
| while ($i-- != 0) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| $prevMinusDM = $prevMinusDM - ($prevMinusDM / $optInTimePeriod) + $diffM; | |
| } else { | |
| $prevMinusDM = $prevMinusDM - ($prevMinusDM / $optInTimePeriod); | |
| } | |
| } | |
| $outReal[0] = $prevMinusDM; | |
| $outIdx = 1; | |
| while ($today < $endIdx) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffM > 0) && ($diffP < $diffM)) { | |
| $prevMinusDM = $prevMinusDM - ($prevMinusDM / $optInTimePeriod) + $diffM; | |
| } else { | |
| $prevMinusDM = $prevMinusDM - ($prevMinusDM / $optInTimePeriod); | |
| } | |
| $outReal[$outIdx++] = $prevMinusDM; | |
| } | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function mom(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 10; | |
| } elseif (((int)$optInTimePeriod < 1) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($startIdx < $optInTimePeriod) { | |
| $startIdx = $optInTimePeriod; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| $inIdx = $startIdx; | |
| $trailingIdx = $startIdx - $optInTimePeriod; | |
| while ($inIdx <= $endIdx) { | |
| $outReal[$outIdx++] = $inReal[$inIdx++] - $inReal[$trailingIdx++]; | |
| } | |
| $outNBElement = $outIdx; | |
| $outBegIdx = $startIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inHigh | |
| * @param array $inLow | |
| * @param array $inClose | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function plusDI(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; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 1) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInTimePeriod > 1) { | |
| $lookbackTotal = $optInTimePeriod + (static::$unstablePeriod[UnstablePeriodFunctionID::PlusDI]); | |
| } else { | |
| $lookbackTotal = 1; | |
| } | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| if ($optInTimePeriod <= 1) { | |
| $outBegIdx = $startIdx; | |
| $today = $startIdx - 1; | |
| $prevHigh = $inHigh[$today]; | |
| $prevLow = $inLow[$today]; | |
| $prevClose = $inClose[$today]; | |
| while ($today < $endIdx) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffP > 0) && ($diffP > $diffM)) { | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| if ((((-0.00000001) < $tempReal) && ($tempReal < 0.00000001))) { | |
| $outReal[$outIdx++] = (double)0.0; | |
| } else { | |
| $outReal[$outIdx++] = $diffP / $tempReal; | |
| } | |
| } else { | |
| $outReal[$outIdx++] = (double)0.0; | |
| } | |
| $prevClose = $inClose[$today]; | |
| } | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| $outBegIdx = $today = $startIdx; | |
| $prevPlusDM = 0.0; | |
| $prevTR = 0.0; | |
| $today = $startIdx - $lookbackTotal; | |
| $prevHigh = $inHigh[$today]; | |
| $prevLow = $inLow[$today]; | |
| $prevClose = $inClose[$today]; | |
| $i = $optInTimePeriod - 1; | |
| while ($i-- > 0) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffP > 0) && ($diffP > $diffM)) { | |
| $prevPlusDM += $diffP; | |
| } | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| $prevTR += $tempReal; | |
| $prevClose = $inClose[$today]; | |
| } | |
| $i = (static::$unstablePeriod[UnstablePeriodFunctionID::PlusDI]) + 1; | |
| while ($i-- != 0) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffP > 0) && ($diffP > $diffM)) { | |
| $prevPlusDM = $prevPlusDM - ($prevPlusDM / $optInTimePeriod) + $diffP; | |
| } else { | |
| $prevPlusDM = $prevPlusDM - ($prevPlusDM / $optInTimePeriod); | |
| } | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| $prevTR = $prevTR - ($prevTR / $optInTimePeriod) + $tempReal; | |
| $prevClose = $inClose[$today]; | |
| } | |
| if (!(((-0.00000001) < $prevTR) && ($prevTR < 0.00000001))) { | |
| $outReal[0] = (100.0 * ($prevPlusDM / $prevTR)); | |
| } else { | |
| $outReal[0] = 0.0; | |
| } | |
| $outIdx = 1; | |
| while ($today < $endIdx) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffP > 0) && ($diffP > $diffM)) { | |
| $prevPlusDM = $prevPlusDM - ($prevPlusDM / $optInTimePeriod) + $diffP; | |
| } else { | |
| $prevPlusDM = $prevPlusDM - ($prevPlusDM / $optInTimePeriod); | |
| } | |
| { | |
| $tempReal = $prevHigh - $prevLow; | |
| $tempReal2 = abs($prevHigh - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| $tempReal2 = abs($prevLow - $prevClose); | |
| if ($tempReal2 > $tempReal) { | |
| $tempReal = $tempReal2; | |
| } | |
| }; | |
| $prevTR = $prevTR - ($prevTR / $optInTimePeriod) + $tempReal; | |
| $prevClose = $inClose[$today]; | |
| if (!(((-0.00000001) < $prevTR) && ($prevTR < 0.00000001))) { | |
| $outReal[$outIdx++] = (100.0 * ($prevPlusDM / $prevTR)); | |
| } else { | |
| $outReal[$outIdx++] = 0.0; | |
| } | |
| } | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inHigh | |
| * @param array $inLow | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function plusDM(int $startIdx, int $endIdx, array $inHigh, array $inLow, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 1) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInTimePeriod > 1) { | |
| $lookbackTotal = $optInTimePeriod + (static::$unstablePeriod[UnstablePeriodFunctionID::PlusDM]) - 1; | |
| } else { | |
| $lookbackTotal = 1; | |
| } | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| if ($optInTimePeriod <= 1) { | |
| $outBegIdx = $startIdx; | |
| $today = $startIdx - 1; | |
| $prevHigh = $inHigh[$today]; | |
| $prevLow = $inLow[$today]; | |
| while ($today < $endIdx) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffP > 0) && ($diffP > $diffM)) { | |
| $outReal[$outIdx++] = $diffP; | |
| } else { | |
| $outReal[$outIdx++] = 0; | |
| } | |
| } | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| $outBegIdx = $startIdx; | |
| $prevPlusDM = 0.0; | |
| $today = $startIdx - $lookbackTotal; | |
| $prevHigh = $inHigh[$today]; | |
| $prevLow = $inLow[$today]; | |
| $i = $optInTimePeriod - 1; | |
| while ($i-- > 0) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffP > 0) && ($diffP > $diffM)) { | |
| $prevPlusDM += $diffP; | |
| } | |
| } | |
| $i = (static::$unstablePeriod[UnstablePeriodFunctionID::PlusDM]); | |
| while ($i-- != 0) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffP > 0) && ($diffP > $diffM)) { | |
| $prevPlusDM = $prevPlusDM - ($prevPlusDM / $optInTimePeriod) + $diffP; | |
| } else { | |
| $prevPlusDM = $prevPlusDM - ($prevPlusDM / $optInTimePeriod); | |
| } | |
| } | |
| $outReal[0] = $prevPlusDM; | |
| $outIdx = 1; | |
| while ($today < $endIdx) { | |
| $today++; | |
| $tempReal = $inHigh[$today]; | |
| $diffP = $tempReal - $prevHigh; | |
| $prevHigh = $tempReal; | |
| $tempReal = $inLow[$today]; | |
| $diffM = $prevLow - $tempReal; | |
| $prevLow = $tempReal; | |
| if (($diffP > 0) && ($diffP > $diffM)) { | |
| $prevPlusDM = $prevPlusDM - ($prevPlusDM / $optInTimePeriod) + $diffP; | |
| } else { | |
| $prevPlusDM = $prevPlusDM - ($prevPlusDM / $optInTimePeriod); | |
| } | |
| $outReal[$outIdx++] = $prevPlusDM; | |
| } | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInFastPeriod | |
| * @param int $optInSlowPeriod | |
| * @param int $optInMAType | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function ppo(int $startIdx, int $endIdx, array $inReal, int $optInFastPeriod, int $optInSlowPeriod, int $optInMAType, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInFastPeriod == (PHP_INT_MIN)) { | |
| $optInFastPeriod = 12; | |
| } elseif (((int)$optInFastPeriod < 2) || ((int)$optInFastPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInSlowPeriod == (PHP_INT_MIN)) { | |
| $optInSlowPeriod = 26; | |
| } elseif (((int)$optInSlowPeriod < 2) || ((int)$optInSlowPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $tempBuffer = static::double($endIdx - $startIdx + 1); | |
| $one = 1; | |
| $ReturnCode = static::TA_INT_PO( | |
| $startIdx, $endIdx, $inReal, | |
| $optInFastPeriod, | |
| $optInSlowPeriod, | |
| $optInMAType, | |
| $outBegIdx, | |
| $outNBElement, | |
| $outReal, | |
| $tempBuffer, | |
| $one | |
| ); | |
| return $ReturnCode; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function roc(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 10; | |
| } elseif (((int)$optInTimePeriod < 1) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($startIdx < $optInTimePeriod) { | |
| $startIdx = $optInTimePeriod; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| $inIdx = $startIdx; | |
| $trailingIdx = $startIdx - $optInTimePeriod; | |
| while ($inIdx <= $endIdx) { | |
| $tempReal = $inReal[$trailingIdx++]; | |
| if ($tempReal != 0.0) { | |
| $outReal[$outIdx++] = (($inReal[$inIdx] / $tempReal) - 1.0) * 100.0; | |
| } else { | |
| $outReal[$outIdx++] = 0.0; | |
| } | |
| $inIdx++; | |
| } | |
| $outNBElement = $outIdx; | |
| $outBegIdx = $startIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function rocP(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 10; | |
| } elseif (((int)$optInTimePeriod < 1) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($startIdx < $optInTimePeriod) { | |
| $startIdx = $optInTimePeriod; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| $inIdx = $startIdx; | |
| $trailingIdx = $startIdx - $optInTimePeriod; | |
| while ($inIdx <= $endIdx) { | |
| $tempReal = $inReal[$trailingIdx++]; | |
| if ($tempReal != 0.0) { | |
| $outReal[$outIdx++] = ($inReal[$inIdx] - $tempReal) / $tempReal; | |
| } else { | |
| $outReal[$outIdx++] = 0.0; | |
| } | |
| $inIdx++; | |
| } | |
| $outNBElement = $outIdx; | |
| $outBegIdx = $startIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function rocR(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 10; | |
| } elseif (((int)$optInTimePeriod < 1) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($startIdx < $optInTimePeriod) { | |
| $startIdx = $optInTimePeriod; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| $inIdx = $startIdx; | |
| $trailingIdx = $startIdx - $optInTimePeriod; | |
| while ($inIdx <= $endIdx) { | |
| $tempReal = $inReal[$trailingIdx++]; | |
| if ($tempReal != 0.0) { | |
| $outReal[$outIdx++] = ($inReal[$inIdx] / $tempReal); | |
| } else { | |
| $outReal[$outIdx++] = 0.0; | |
| } | |
| $inIdx++; | |
| } | |
| $outNBElement = $outIdx; | |
| $outBegIdx = $startIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function rocR100(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 10; | |
| } elseif (((int)$optInTimePeriod < 1) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($startIdx < $optInTimePeriod) { | |
| $startIdx = $optInTimePeriod; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| $inIdx = $startIdx; | |
| $trailingIdx = $startIdx - $optInTimePeriod; | |
| while ($inIdx <= $endIdx) { | |
| $tempReal = $inReal[$trailingIdx++]; | |
| if ($tempReal != 0.0) { | |
| $outReal[$outIdx++] = ($inReal[$inIdx] / $tempReal) * 100.0; | |
| } else { | |
| $outReal[$outIdx++] = 0.0; | |
| } | |
| $inIdx++; | |
| } | |
| $outNBElement = $outIdx; | |
| $outBegIdx = $startIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function rsi(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| $lookbackTotal = Lookback::rsiLookback($optInTimePeriod); | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| if ($optInTimePeriod == 1) { | |
| $outBegIdx = $startIdx; | |
| $i = ($endIdx - $startIdx) + 1; | |
| $outNBElement = $i; | |
| //System::arraycopy($inReal, $startIdx, $outReal, 0, $i); | |
| $outReal = \array_slice($inReal, $startIdx, $i); | |
| return ReturnCode::Success; | |
| } | |
| $today = $startIdx - $lookbackTotal; | |
| $prevValue = $inReal[$today]; | |
| $unstablePeriod = (static::$unstablePeriod[UnstablePeriodFunctionID::RSI]); | |
| if (($unstablePeriod == 0) && | |
| ((static::$compatibility) == Compatibility::Metastock)) { | |
| $savePrevValue = $prevValue; | |
| $prevGain = 0.0; | |
| $prevLoss = 0.0; | |
| for ($i = $optInTimePeriod; $i > 0; $i--) { | |
| $tempValue1 = $inReal[$today++]; | |
| $tempValue2 = $tempValue1 - $prevValue; | |
| $prevValue = $tempValue1; | |
| if ($tempValue2 < 0) { | |
| $prevLoss -= $tempValue2; | |
| } else { | |
| $prevGain += $tempValue2; | |
| } | |
| } | |
| $tempValue1 = $prevLoss / $optInTimePeriod; | |
| $tempValue2 = $prevGain / $optInTimePeriod; | |
| $tempValue1 = $tempValue2 + $tempValue1; | |
| if (!(((-0.00000001) < $tempValue1) && ($tempValue1 < 0.00000001))) { | |
| $outReal[$outIdx++] = 100 * ($tempValue2 / $tempValue1); | |
| } else { | |
| $outReal[$outIdx++] = 0.0; | |
| } | |
| if ($today > $endIdx) { | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| $today -= $optInTimePeriod; | |
| $prevValue = $savePrevValue; | |
| } | |
| $prevGain = 0.0; | |
| $prevLoss = 0.0; | |
| $today++; | |
| for ($i = $optInTimePeriod; $i > 0; $i--) { | |
| $tempValue1 = $inReal[$today++]; | |
| $tempValue2 = $tempValue1 - $prevValue; | |
| $prevValue = $tempValue1; | |
| if ($tempValue2 < 0) { | |
| $prevLoss -= $tempValue2; | |
| } else { | |
| $prevGain += $tempValue2; | |
| } | |
| } | |
| $prevLoss /= $optInTimePeriod; | |
| $prevGain /= $optInTimePeriod; | |
| if ($today > $startIdx) { | |
| $tempValue1 = $prevGain + $prevLoss; | |
| if (!(((-0.00000001) < $tempValue1) && ($tempValue1 < 0.00000001))) { | |
| $outReal[$outIdx++] = 100.0 * ($prevGain / $tempValue1); | |
| } else { | |
| $outReal[$outIdx++] = 0.0; | |
| } | |
| } else { | |
| while ($today < $startIdx) { | |
| $tempValue1 = $inReal[$today]; | |
| $tempValue2 = $tempValue1 - $prevValue; | |
| $prevValue = $tempValue1; | |
| $prevLoss *= ($optInTimePeriod - 1); | |
| $prevGain *= ($optInTimePeriod - 1); | |
| if ($tempValue2 < 0) { | |
| $prevLoss -= $tempValue2; | |
| } else { | |
| $prevGain += $tempValue2; | |
| } | |
| $prevLoss /= $optInTimePeriod; | |
| $prevGain /= $optInTimePeriod; | |
| $today++; | |
| } | |
| } | |
| while ($today <= $endIdx) { | |
| $tempValue1 = $inReal[$today++]; | |
| $tempValue2 = $tempValue1 - $prevValue; | |
| $prevValue = $tempValue1; | |
| $prevLoss *= ($optInTimePeriod - 1); | |
| $prevGain *= ($optInTimePeriod - 1); | |
| if ($tempValue2 < 0) { | |
| $prevLoss -= $tempValue2; | |
| } else { | |
| $prevGain += $tempValue2; | |
| } | |
| $prevLoss /= $optInTimePeriod; | |
| $prevGain /= $optInTimePeriod; | |
| $tempValue1 = $prevGain + $prevLoss; | |
| if (!(((-0.00000001) < $tempValue1) && ($tempValue1 < 0.00000001))) { | |
| $outReal[$outIdx++] = 100.0 * ($prevGain / $tempValue1); | |
| } else { | |
| $outReal[$outIdx++] = 0.0; | |
| } | |
| } | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inHigh | |
| * @param array $inLow | |
| * @param array $inClose | |
| * @param int $optInFastK_Period | |
| * @param int $optInSlowK_Period | |
| * @param int $optInSlowK_MAType | |
| * @param int $optInSlowD_Period | |
| * @param int $optInSlowD_MAType | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outSlowK | |
| * @param array $outSlowD | |
| * | |
| * @return int | |
| */ | |
| public static function stoch(int $startIdx, int $endIdx, array $inHigh, array $inLow, array $inClose, int $optInFastK_Period, int $optInSlowK_Period, int $optInSlowK_MAType, int $optInSlowD_Period, int $optInSlowD_MAType, int &$outBegIdx, int &$outNBElement, array &$outSlowK, array &$outSlowD): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInFastK_Period == (PHP_INT_MIN)) { | |
| $optInFastK_Period = 5; | |
| } elseif (((int)$optInFastK_Period < 1) || ((int)$optInFastK_Period > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInSlowK_Period == (PHP_INT_MIN)) { | |
| $optInSlowK_Period = 3; | |
| } elseif (((int)$optInSlowK_Period < 1) || ((int)$optInSlowK_Period > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInSlowD_Period == (PHP_INT_MIN)) { | |
| $optInSlowD_Period = 3; | |
| } elseif (((int)$optInSlowD_Period < 1) || ((int)$optInSlowD_Period > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $lookbackK = $optInFastK_Period - 1; | |
| $lookbackKSlow = Lookback::movingAverageLookback($optInSlowK_Period, $optInSlowK_MAType); | |
| $lookbackDSlow = Lookback::movingAverageLookback($optInSlowD_Period, $optInSlowD_MAType); | |
| $lookbackTotal = $lookbackK + $lookbackDSlow + $lookbackKSlow; | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| $trailingIdx = $startIdx - $lookbackTotal; | |
| $today = $trailingIdx + $lookbackK; | |
| $lowestIdx = $highestIdx = -1; | |
| $diff = $highest = $lowest = 0.0; | |
| if (($outSlowK == $inHigh) || | |
| ($outSlowK == $inLow) || | |
| ($outSlowK == $inClose)) { | |
| $tempBuffer = $outSlowK; | |
| } elseif (($outSlowD == $inHigh) || | |
| ($outSlowD == $inLow) || | |
| ($outSlowD == $inClose)) { | |
| $tempBuffer = $outSlowD; | |
| } else { | |
| $tempBuffer = static::double($endIdx - $today + 1); | |
| } | |
| while ($today <= $endIdx) { | |
| $tmp = $inLow[$today]; | |
| if ($lowestIdx < $trailingIdx) { | |
| $lowestIdx = $trailingIdx; | |
| $lowest = $inLow[$lowestIdx]; | |
| $i = $lowestIdx; | |
| while (++$i <= $today) { | |
| $tmp = $inLow[$i]; | |
| if ($tmp < $lowest) { | |
| $lowestIdx = $i; | |
| $lowest = $tmp; | |
| } | |
| } | |
| $diff = ($highest - $lowest) / 100.0; | |
| } elseif ($tmp <= $lowest) { | |
| $lowestIdx = $today; | |
| $lowest = $tmp; | |
| $diff = ($highest - $lowest) / 100.0; | |
| } | |
| $tmp = $inHigh[$today]; | |
| if ($highestIdx < $trailingIdx) { | |
| $highestIdx = $trailingIdx; | |
| $highest = $inHigh[$highestIdx]; | |
| $i = $highestIdx; | |
| while (++$i <= $today) { | |
| $tmp = $inHigh[$i]; | |
| if ($tmp > $highest) { | |
| $highestIdx = $i; | |
| $highest = $tmp; | |
| } | |
| } | |
| $diff = ($highest - $lowest) / 100.0; | |
| } elseif ($tmp >= $highest) { | |
| $highestIdx = $today; | |
| $highest = $tmp; | |
| $diff = ($highest - $lowest) / 100.0; | |
| } | |
| if ($diff != 0.0) { | |
| $tempBuffer[$outIdx++] = ($inClose[$today] - $lowest) / $diff; | |
| } else { | |
| $tempBuffer[$outIdx++] = 0.0; | |
| } | |
| $trailingIdx++; | |
| $today++; | |
| } | |
| $ReturnCode = OverlapStudies::movingAverage( | |
| 0, $outIdx - 1, | |
| $tempBuffer, $optInSlowK_Period, | |
| $optInSlowK_MAType, | |
| $outBegIdx, $outNBElement, $tempBuffer | |
| ); | |
| if (($ReturnCode != ReturnCode::Success) || ((int)$outNBElement == 0)) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| $ReturnCode = OverlapStudies::movingAverage( | |
| 0, (int)$outNBElement - 1, | |
| $tempBuffer, $optInSlowD_Period, | |
| $optInSlowD_MAType, | |
| $outBegIdx, $outNBElement, $outSlowD | |
| ); | |
| //System::arraycopy($tempBuffer, $lookbackDSlow, $outSlowK, 0, (int)$outNBElement); | |
| $outSlowK = \array_slice($tempBuffer, $lookbackDSlow, (int)$outNBElement); | |
| if ($ReturnCode != ReturnCode::Success) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| $outBegIdx = $startIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inHigh | |
| * @param array $inLow | |
| * @param array $inClose | |
| * @param int $optInFastK_Period | |
| * @param int $optInFastD_Period | |
| * @param int $optInFastD_MAType | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outFastK | |
| * @param array $outFastD | |
| * | |
| * @return int | |
| */ | |
| public static function stochF(int $startIdx, int $endIdx, array $inHigh, array $inLow, array $inClose, int $optInFastK_Period, int $optInFastD_Period, int $optInFastD_MAType, int &$outBegIdx, int &$outNBElement, array &$outFastK, array &$outFastD): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInFastK_Period == (PHP_INT_MIN)) { | |
| $optInFastK_Period = 5; | |
| } elseif (((int)$optInFastK_Period < 1) || ((int)$optInFastK_Period > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInFastD_Period == (PHP_INT_MIN)) { | |
| $optInFastD_Period = 3; | |
| } elseif (((int)$optInFastD_Period < 1) || ((int)$optInFastD_Period > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $lookbackK = $optInFastK_Period - 1; | |
| $lookbackFastD = Lookback::movingAverageLookback($optInFastD_Period, $optInFastD_MAType); | |
| $lookbackTotal = $lookbackK + $lookbackFastD; | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| $trailingIdx = $startIdx - $lookbackTotal; | |
| $today = $trailingIdx + $lookbackK; | |
| $lowestIdx = $highestIdx = -1; | |
| $diff = $highest = $lowest = 0.0; | |
| if (($outFastK == $inHigh) || | |
| ($outFastK == $inLow) || | |
| ($outFastK == $inClose)) { | |
| $tempBuffer = $outFastK; | |
| } elseif (($outFastD == $inHigh) || | |
| ($outFastD == $inLow) || | |
| ($outFastD == $inClose)) { | |
| $tempBuffer = $outFastD; | |
| } else { | |
| $tempBuffer = static::double($endIdx - $today + 1); | |
| } | |
| while ($today <= $endIdx) { | |
| $tmp = $inLow[$today]; | |
| if ($lowestIdx < $trailingIdx) { | |
| $lowestIdx = $trailingIdx; | |
| $lowest = $inLow[$lowestIdx]; | |
| $i = $lowestIdx; | |
| while (++$i <= $today) { | |
| $tmp = $inLow[$i]; | |
| if ($tmp < $lowest) { | |
| $lowestIdx = $i; | |
| $lowest = $tmp; | |
| } | |
| } | |
| $diff = ($highest - $lowest) / 100.0; | |
| } elseif ($tmp <= $lowest) { | |
| $lowestIdx = $today; | |
| $lowest = $tmp; | |
| $diff = ($highest - $lowest) / 100.0; | |
| } | |
| $tmp = $inHigh[$today]; | |
| if ($highestIdx < $trailingIdx) { | |
| $highestIdx = $trailingIdx; | |
| $highest = $inHigh[$highestIdx]; | |
| $i = $highestIdx; | |
| while (++$i <= $today) { | |
| $tmp = $inHigh[$i]; | |
| if ($tmp > $highest) { | |
| $highestIdx = $i; | |
| $highest = $tmp; | |
| } | |
| } | |
| $diff = ($highest - $lowest) / 100.0; | |
| } elseif ($tmp >= $highest) { | |
| $highestIdx = $today; | |
| $highest = $tmp; | |
| $diff = ($highest - $lowest) / 100.0; | |
| } | |
| if ($diff != 0.0) { | |
| $tempBuffer[$outIdx++] = ($inClose[$today] - $lowest) / $diff; | |
| } else { | |
| $tempBuffer[$outIdx++] = 0.0; | |
| } | |
| $trailingIdx++; | |
| $today++; | |
| } | |
| $ReturnCode = OverlapStudies::movingAverage( | |
| 0, $outIdx - 1, | |
| $tempBuffer, $optInFastD_Period, | |
| $optInFastD_MAType, | |
| $outBegIdx, $outNBElement, $outFastD | |
| ); | |
| if (($ReturnCode != ReturnCode::Success) || ((int)$outNBElement) == 0) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| //System::arraycopy($tempBuffer, $lookbackFastD, $outFastK, 0, (int)$outNBElement); | |
| $outFastK = \array_slice($tempBuffer, $lookbackFastD, (int)$outNBElement); | |
| if ($ReturnCode != ReturnCode::Success) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| $outBegIdx = $startIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInTimePeriod | |
| * @param int $optInFastK_Period | |
| * @param int $optInFastD_Period | |
| * @param int $optInFastD_MAType | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outFastK | |
| * @param array $outFastD | |
| * | |
| * @return int | |
| */ | |
| public static function stochRsi(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int $optInFastK_Period, int $optInFastD_Period, int $optInFastD_MAType, int &$outBegIdx, int &$outNBElement, array &$outFastK, array &$outFastD): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $outBegIdx1 = 0; | |
| $outBegIdx2 = 0; | |
| $outNbElement1 = 0; | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInFastK_Period == (PHP_INT_MIN)) { | |
| $optInFastK_Period = 5; | |
| } elseif (((int)$optInFastK_Period < 1) || ((int)$optInFastK_Period > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInFastD_Period == (PHP_INT_MIN)) { | |
| $optInFastD_Period = 3; | |
| } elseif (((int)$optInFastD_Period < 1) || ((int)$optInFastD_Period > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| $lookbackSTOCHF = Lookback::stochFLookback($optInFastK_Period, $optInFastD_Period, $optInFastD_MAType); | |
| $lookbackTotal = Lookback::rsiLookback($optInTimePeriod) + $lookbackSTOCHF; | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outBegIdx = $startIdx; | |
| $tempArraySize = ($endIdx - $startIdx) + 1 + $lookbackSTOCHF; | |
| $tempRSIBuffer = static::double($tempArraySize); | |
| $ReturnCode = self::rsi( | |
| $startIdx - $lookbackSTOCHF, | |
| $endIdx, | |
| $inReal, | |
| $optInTimePeriod, | |
| $outBegIdx1, | |
| $outNbElement1, | |
| $tempRSIBuffer | |
| ); | |
| if ($ReturnCode != ReturnCode::Success || $outNbElement1 == 0) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| $ReturnCode = self::stochF( | |
| 0, | |
| $tempArraySize - 1, | |
| $tempRSIBuffer, | |
| $tempRSIBuffer, | |
| $tempRSIBuffer, | |
| $optInFastK_Period, | |
| $optInFastD_Period, | |
| $optInFastD_MAType, | |
| $outBegIdx2, | |
| $outNBElement, | |
| $outFastK, | |
| $outFastD | |
| ); | |
| if ($ReturnCode != ReturnCode::Success || ((int)$outNBElement) == 0) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function trix(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $nbElement = 0; | |
| $begIdx = 0; | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 30; | |
| } elseif (((int)$optInTimePeriod < 1) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $emaLookback = Lookback::emaLookback($optInTimePeriod); | |
| $rocLookback = Lookback::rocRLookback(1); | |
| $totalLookback = ($emaLookback * 3) + $rocLookback; | |
| if ($startIdx < $totalLookback) { | |
| $startIdx = $totalLookback; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outNBElement = 0; | |
| $outBegIdx = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outBegIdx = $startIdx; | |
| $nbElementToOutput = ($endIdx - $startIdx) + 1 + $totalLookback; | |
| $tempBuffer = static::double($nbElementToOutput); | |
| $k = ((double)2.0 / ((double)($optInTimePeriod + 1))); | |
| $ReturnCode = static::TA_INT_EMA( | |
| ($startIdx - $totalLookback), $endIdx, $inReal, | |
| $optInTimePeriod, $k, | |
| $begIdx, $nbElement, | |
| $tempBuffer | |
| ); | |
| if (($ReturnCode != ReturnCode::Success) || ($nbElement == 0)) { | |
| $outNBElement = 0; | |
| $outBegIdx = 0; | |
| return $ReturnCode; | |
| } | |
| $nbElementToOutput--; | |
| $nbElementToOutput -= $emaLookback; | |
| $ReturnCode = static::TA_INT_EMA( | |
| 0, $nbElementToOutput, $tempBuffer, | |
| $optInTimePeriod, $k, | |
| $begIdx, $nbElement, | |
| $tempBuffer | |
| ); | |
| if (($ReturnCode != ReturnCode::Success) || ($nbElement == 0)) { | |
| $outNBElement = 0; | |
| $outBegIdx = 0; | |
| return $ReturnCode; | |
| } | |
| $nbElementToOutput -= $emaLookback; | |
| $ReturnCode = static::TA_INT_EMA( | |
| 0, $nbElementToOutput, $tempBuffer, | |
| $optInTimePeriod, $k, | |
| $begIdx, $nbElement, | |
| $tempBuffer | |
| ); | |
| if (($ReturnCode != ReturnCode::Success) || ($nbElement == 0)) { | |
| $outNBElement = 0; | |
| $outBegIdx = 0; | |
| return $ReturnCode; | |
| } | |
| $nbElementToOutput -= $emaLookback; | |
| $ReturnCode = self::roc( | |
| 0, $nbElementToOutput, | |
| $tempBuffer, | |
| 1, $begIdx, $outNBElement, | |
| $outReal | |
| ); | |
| if (($ReturnCode != ReturnCode::Success) || ((int)$outNBElement == 0)) { | |
| $outNBElement = 0; | |
| $outBegIdx = 0; | |
| return $ReturnCode; | |
| } | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inHigh | |
| * @param array $inLow | |
| * @param array $inClose | |
| * @param int $optInTimePeriod1 | |
| * @param int $optInTimePeriod2 | |
| * @param int $optInTimePeriod3 | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function ultOsc(int $startIdx, int $endIdx, array $inHigh, array $inLow, array $inClose, int $optInTimePeriod1, int $optInTimePeriod2, int $optInTimePeriod3, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $usedFlag = \array_pad([], 3, 0); | |
| $periods = \array_pad([], 3, 0); | |
| $sortedPeriods = \array_pad([], 3, 0); | |
| if ((int)$optInTimePeriod1 == (PHP_INT_MIN)) { | |
| $optInTimePeriod1 = 7; | |
| } elseif (((int)$optInTimePeriod1 < 1) || ((int)$optInTimePeriod1 > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInTimePeriod2 == (PHP_INT_MIN)) { | |
| $optInTimePeriod2 = 14; | |
| } elseif (((int)$optInTimePeriod2 < 1) || ((int)$optInTimePeriod2 > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInTimePeriod3 == (PHP_INT_MIN)) { | |
| $optInTimePeriod3 = 28; | |
| } elseif (((int)$optInTimePeriod3 < 1) || ((int)$optInTimePeriod3 > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| $periods[0] = $optInTimePeriod1; | |
| $periods[1] = $optInTimePeriod2; | |
| $periods[2] = $optInTimePeriod3; | |
| $usedFlag[0] = 0; | |
| $usedFlag[1] = 0; | |
| $usedFlag[2] = 0; | |
| for ($i = 0; $i < 3; ++$i) { | |
| $longestPeriod = 0; | |
| $longestIndex = 0; | |
| for ($j = 0; $j < 3; ++$j) { | |
| if (($usedFlag[$j] == 0) && ($periods[$j] > $longestPeriod)) { | |
| $longestPeriod = $periods[$j]; | |
| $longestIndex = $j; | |
| } | |
| } | |
| $usedFlag[$longestIndex] = 1; | |
| $sortedPeriods[$i] = $longestPeriod; | |
| } | |
| $optInTimePeriod1 = $sortedPeriods[2]; | |
| $optInTimePeriod2 = $sortedPeriods[1]; | |
| $optInTimePeriod3 = $sortedPeriods[0]; | |
| $lookbackTotal = Lookback::ultOscLookback($optInTimePeriod1, $optInTimePeriod2, $optInTimePeriod3); | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| return ReturnCode::Success; | |
| } | |
| { | |
| $a1Total = 0; | |
| $b1Total = 0; | |
| for ($i = $startIdx - $optInTimePeriod1 + 1; $i < $startIdx; ++$i) { | |
| { | |
| $tempLT = $inLow[$i]; | |
| $tempHT = $inHigh[$i]; | |
| $tempCY = $inClose[$i - 1]; | |
| $trueLow = ((($tempLT) < ($tempCY)) ? ($tempLT) : ($tempCY)); | |
| $closeMinusTrueLow = $inClose[$i] - $trueLow; | |
| $trueRange = $tempHT - $tempLT; | |
| $tempDouble = abs($tempCY - $tempHT); | |
| if ($tempDouble > $trueRange) { | |
| $trueRange = $tempDouble; | |
| } | |
| $tempDouble = abs($tempCY - $tempLT); | |
| if ($tempDouble > $trueRange) { | |
| $trueRange = $tempDouble; | |
| } | |
| }; | |
| $a1Total += $closeMinusTrueLow; | |
| $b1Total += $trueRange; | |
| } | |
| }; | |
| { | |
| $a2Total = 0; | |
| $b2Total = 0; | |
| for ($i = $startIdx - $optInTimePeriod2 + 1; $i < $startIdx; ++$i) { | |
| { | |
| $tempLT = $inLow[$i]; | |
| $tempHT = $inHigh[$i]; | |
| $tempCY = $inClose[$i - 1]; | |
| $trueLow = ((($tempLT) < ($tempCY)) ? ($tempLT) : ($tempCY)); | |
| $closeMinusTrueLow = $inClose[$i] - $trueLow; | |
| $trueRange = $tempHT - $tempLT; | |
| $tempDouble = abs($tempCY - $tempHT); | |
| if ($tempDouble > $trueRange) { | |
| $trueRange = $tempDouble; | |
| } | |
| $tempDouble = abs($tempCY - $tempLT); | |
| if ($tempDouble > $trueRange) { | |
| $trueRange = $tempDouble; | |
| } | |
| }; | |
| $a2Total += $closeMinusTrueLow; | |
| $b2Total += $trueRange; | |
| } | |
| }; | |
| { | |
| $a3Total = 0; | |
| $b3Total = 0; | |
| for ($i = $startIdx - $optInTimePeriod3 + 1; $i < $startIdx; ++$i) { | |
| { | |
| $tempLT = $inLow[$i]; | |
| $tempHT = $inHigh[$i]; | |
| $tempCY = $inClose[$i - 1]; | |
| $trueLow = ((($tempLT) < ($tempCY)) ? ($tempLT) : ($tempCY)); | |
| $closeMinusTrueLow = $inClose[$i] - $trueLow; | |
| $trueRange = $tempHT - $tempLT; | |
| $tempDouble = abs($tempCY - $tempHT); | |
| if ($tempDouble > $trueRange) { | |
| $trueRange = $tempDouble; | |
| } | |
| $tempDouble = abs($tempCY - $tempLT); | |
| if ($tempDouble > $trueRange) { | |
| $trueRange = $tempDouble; | |
| } | |
| }; | |
| $a3Total += $closeMinusTrueLow; | |
| $b3Total += $trueRange; | |
| } | |
| }; | |
| $today = $startIdx; | |
| $outIdx = 0; | |
| $trailingIdx1 = $today - $optInTimePeriod1 + 1; | |
| $trailingIdx2 = $today - $optInTimePeriod2 + 1; | |
| $trailingIdx3 = $today - $optInTimePeriod3 + 1; | |
| while ($today <= $endIdx) { | |
| { | |
| $tempLT = $inLow[$today]; | |
| $tempHT = $inHigh[$today]; | |
| $tempCY = $inClose[$today - 1]; | |
| $trueLow = ((($tempLT) < ($tempCY)) ? ($tempLT) : ($tempCY)); | |
| $closeMinusTrueLow = $inClose[$today] - $trueLow; | |
| $trueRange = $tempHT - $tempLT; | |
| $tempDouble = abs($tempCY - $tempHT); | |
| if ($tempDouble > $trueRange) { | |
| $trueRange = $tempDouble; | |
| } | |
| $tempDouble = abs($tempCY - $tempLT); | |
| if ($tempDouble > $trueRange) { | |
| $trueRange = $tempDouble; | |
| } | |
| }; | |
| $a1Total += $closeMinusTrueLow; | |
| $a2Total += $closeMinusTrueLow; | |
| $a3Total += $closeMinusTrueLow; | |
| $b1Total += $trueRange; | |
| $b2Total += $trueRange; | |
| $b3Total += $trueRange; | |
| $output = 0.0; | |
| if (!(((-0.00000001) < $b1Total) && ($b1Total < 0.00000001))) { | |
| $output += 4.0 * ($a1Total / $b1Total); | |
| } | |
| if (!(((-0.00000001) < $b2Total) && ($b2Total < 0.00000001))) { | |
| $output += 2.0 * ($a2Total / $b2Total); | |
| } | |
| if (!(((-0.00000001) < $b3Total) && ($b3Total < 0.00000001))) { | |
| $output += $a3Total / $b3Total; | |
| } | |
| { | |
| $tempLT = $inLow[$trailingIdx1]; | |
| $tempHT = $inHigh[$trailingIdx1]; | |
| $tempCY = $inClose[$trailingIdx1 - 1]; | |
| $trueLow = ((($tempLT) < ($tempCY)) ? ($tempLT) : ($tempCY)); | |
| $closeMinusTrueLow = $inClose[$trailingIdx1] - $trueLow; | |
| $trueRange = $tempHT - $tempLT; | |
| $tempDouble = abs($tempCY - $tempHT); | |
| if ($tempDouble > $trueRange) { | |
| $trueRange = $tempDouble; | |
| } | |
| $tempDouble = abs($tempCY - $tempLT); | |
| if ($tempDouble > $trueRange) { | |
| $trueRange = $tempDouble; | |
| } | |
| }; | |
| $a1Total -= $closeMinusTrueLow; | |
| $b1Total -= $trueRange; | |
| { | |
| $tempLT = $inLow[$trailingIdx2]; | |
| $tempHT = $inHigh[$trailingIdx2]; | |
| $tempCY = $inClose[$trailingIdx2 - 1]; | |
| $trueLow = ((($tempLT) < ($tempCY)) ? ($tempLT) : ($tempCY)); | |
| $closeMinusTrueLow = $inClose[$trailingIdx2] - $trueLow; | |
| $trueRange = $tempHT - $tempLT; | |
| $tempDouble = abs($tempCY - $tempHT); | |
| if ($tempDouble > $trueRange) { | |
| $trueRange = $tempDouble; | |
| } | |
| $tempDouble = abs($tempCY - $tempLT); | |
| if ($tempDouble > $trueRange) { | |
| $trueRange = $tempDouble; | |
| } | |
| }; | |
| $a2Total -= $closeMinusTrueLow; | |
| $b2Total -= $trueRange; | |
| { | |
| $tempLT = $inLow[$trailingIdx3]; | |
| $tempHT = $inHigh[$trailingIdx3]; | |
| $tempCY = $inClose[$trailingIdx3 - 1]; | |
| $trueLow = ((($tempLT) < ($tempCY)) ? ($tempLT) : ($tempCY)); | |
| $closeMinusTrueLow = $inClose[$trailingIdx3] - $trueLow; | |
| $trueRange = $tempHT - $tempLT; | |
| $tempDouble = abs($tempCY - $tempHT); | |
| if ($tempDouble > $trueRange) { | |
| $trueRange = $tempDouble; | |
| } | |
| $tempDouble = abs($tempCY - $tempLT); | |
| if ($tempDouble > $trueRange) { | |
| $trueRange = $tempDouble; | |
| } | |
| }; | |
| $a3Total -= $closeMinusTrueLow; | |
| $b3Total -= $trueRange; | |
| $outReal[$outIdx] = 100.0 * ($output / 7.0); | |
| $outIdx++; | |
| $today++; | |
| $trailingIdx1++; | |
| $trailingIdx2++; | |
| $trailingIdx3++; | |
| } | |
| $outNBElement = $outIdx; | |
| $outBegIdx = $startIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inHigh | |
| * @param array $inLow | |
| * @param array $inClose | |
| * @param int $optInTimePeriod | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function willR(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; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 14; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $nbInitialElementNeeded = ($optInTimePeriod - 1); | |
| if ($startIdx < $nbInitialElementNeeded) { | |
| $startIdx = $nbInitialElementNeeded; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $diff = 0.0; | |
| $outIdx = 0; | |
| $today = $startIdx; | |
| $trailingIdx = $startIdx - $nbInitialElementNeeded; | |
| $lowestIdx = $highestIdx = -1; | |
| $diff = $highest = $lowest = 0.0; | |
| while ($today <= $endIdx) { | |
| $tmp = $inLow[$today]; | |
| if ($lowestIdx < $trailingIdx) { | |
| $lowestIdx = $trailingIdx; | |
| $lowest = $inLow[$lowestIdx]; | |
| $i = $lowestIdx; | |
| while (++$i <= $today) { | |
| $tmp = $inLow[$i]; | |
| if ($tmp < $lowest) { | |
| $lowestIdx = $i; | |
| $lowest = $tmp; | |
| } | |
| } | |
| $diff = ($highest - $lowest) / (-100.0); | |
| } elseif ($tmp <= $lowest) { | |
| $lowestIdx = $today; | |
| $lowest = $tmp; | |
| $diff = ($highest - $lowest) / (-100.0); | |
| } | |
| $tmp = $inHigh[$today]; | |
| if ($highestIdx < $trailingIdx) { | |
| $highestIdx = $trailingIdx; | |
| $highest = $inHigh[$highestIdx]; | |
| $i = $highestIdx; | |
| while (++$i <= $today) { | |
| $tmp = $inHigh[$i]; | |
| if ($tmp > $highest) { | |
| $highestIdx = $i; | |
| $highest = $tmp; | |
| } | |
| } | |
| $diff = ($highest - $lowest) / (-100.0); | |
| } elseif ($tmp >= $highest) { | |
| $highestIdx = $today; | |
| $highest = $tmp; | |
| $diff = ($highest - $lowest) / (-100.0); | |
| } | |
| if ($diff != 0.0) { | |
| $outReal[$outIdx++] = ($highest - $inClose[$today]) / $diff; | |
| } else { | |
| $outReal[$outIdx++] = 0.0; | |
| } | |
| $trailingIdx++; | |
| $today++; | |
| } | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| } |