Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 17 |
CRAP | |
83.78% |
1152 / 1375 |
| LupeCode\phpTraderNative\TALib\Core\OverlapStudies | |
0.00% |
0 / 1 |
|
0.00% |
0 / 17 |
779.36 | |
83.78% |
1152 / 1375 |
| bbands | |
0.00% |
0 / 1 |
232.98 | |
39.13% |
27 / 69 |
|||
| dema | |
0.00% |
0 / 1 |
13.60 | |
84.78% |
39 / 46 |
|||
| ema | |
0.00% |
0 / 1 |
5.51 | |
72.73% |
8 / 11 |
|||
| htTrendline | |
0.00% |
0 / 1 |
19 | |
97.85% |
228 / 233 |
|||
| kama | |
0.00% |
0 / 1 |
26.87 | |
72.06% |
49 / 68 |
|||
| movingAverage | |
0.00% |
0 / 1 |
17.30 | |
82.81% |
53 / 64 |
|||
| mama | |
0.00% |
0 / 1 |
26 | |
96.20% |
228 / 237 |
|||
| movingAverageVariablePeriod | |
0.00% |
0 / 1 |
31.81 | |
69.09% |
38 / 55 |
|||
| midPoint | |
0.00% |
0 / 1 |
11.97 | |
80.00% |
24 / 30 |
|||
| midPrice | |
0.00% |
0 / 1 |
11.80 | |
81.25% |
26 / 32 |
|||
| sar | |
0.00% |
0 / 1 |
38.91 | |
83.81% |
88 / 105 |
|||
| sarExt | |
0.00% |
0 / 1 |
136.99 | |
72.67% |
109 / 150 |
|||
| sma | |
0.00% |
0 / 1 |
5.68 | |
70.00% |
7 / 10 |
|||
| t3 | |
0.00% |
0 / 1 |
19.50 | |
83.33% |
70 / 84 |
|||
| tema | |
0.00% |
0 / 1 |
14.43 | |
87.04% |
47 / 54 |
|||
| trima | |
0.00% |
0 / 1 |
14.07 | |
93.02% |
80 / 86 |
|||
| wma | |
0.00% |
0 / 1 |
11.45 | |
75.61% |
31 / 41 |
|||
| <?php | |
| /** | |
| * This is a PHP port of the Trader extension for PHP, which is a port of the TA-LIB C code. | |
| * | |
| * This port is written in PHP and without any other requirements. | |
| * The goal is that this library can be used by those whom cannot install the PHP Trader extension. | |
| * | |
| * Below is the copyright information for TA-LIB found in the source code. | |
| */ | |
| /* TA-LIB Copyright (c) 1999-2007, Mario Fortier | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or | |
| * without modification, are permitted provided that the following | |
| * conditions are met: | |
| * | |
| * - Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * | |
| * - Redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in | |
| * the documentation and/or other materials provided with the | |
| * distribution. | |
| * | |
| * - Neither name of author nor the names of its contributors | |
| * may be used to endorse or promote products derived from this | |
| * software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
| * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| namespace LupeCode\phpTraderNative\TALib\Core; | |
| use LupeCode\phpTraderNative\TALib\Enum\MovingAverageType; | |
| use LupeCode\phpTraderNative\TALib\Enum\ReturnCode; | |
| use LupeCode\phpTraderNative\TALib\Enum\UnstablePeriodFunctionID; | |
| class OverlapStudies extends Core | |
| { | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param float[] $inReal | |
| * @param int $optInTimePeriod | |
| * @param float $optInNbDevUp | |
| * @param float $optInNbDevDn | |
| * @param int $optInMAType | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param float[] $outRealUpperBand | |
| * @param float[] $outRealMiddleBand | |
| * @param float[] $outRealLowerBand | |
| * | |
| * @return int | |
| */ | |
| public static function bbands(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, float $optInNbDevUp, float $optInNbDevDn, int $optInMAType, int &$outBegIdx, int &$outNBElement, array &$outRealUpperBand, array &$outRealMiddleBand, array &$outRealLowerBand): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 5; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInNbDevUp == (-4e+37)) { | |
| $optInNbDevUp = 2.000000e+0; | |
| } elseif (($optInNbDevUp < -3.000000e+37) || ($optInNbDevUp > 3.000000e+37)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInNbDevDn == (-4e+37)) { | |
| $optInNbDevDn = 2.000000e+0; | |
| } elseif (($optInNbDevDn < -3.000000e+37) || ($optInNbDevDn > 3.000000e+37)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($inReal == $outRealUpperBand) { | |
| $tempBuffer1 = $outRealMiddleBand; | |
| $tempBuffer2 = $outRealLowerBand; | |
| } elseif ($inReal == $outRealLowerBand) { | |
| $tempBuffer1 = $outRealMiddleBand; | |
| $tempBuffer2 = $outRealUpperBand; | |
| } elseif ($inReal == $outRealMiddleBand) { | |
| $tempBuffer1 = $outRealLowerBand; | |
| $tempBuffer2 = $outRealUpperBand; | |
| } else { | |
| $tempBuffer1 = $outRealMiddleBand; | |
| $tempBuffer2 = $outRealUpperBand; | |
| } | |
| if (($tempBuffer1 == $inReal) || ($tempBuffer2 == $inReal)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $ReturnCode = self::movingAverage($startIdx, $endIdx, $inReal, $optInTimePeriod, $optInMAType, $outBegIdx, $outNBElement, $tempBuffer1); | |
| if (($ReturnCode != ReturnCode::Success) || ((int)$outNBElement == 0)) { | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| if ($optInMAType == MovingAverageType::SMA) { | |
| static::TA_INT_stddev_using_precalc_ma($inReal, $tempBuffer1, (int)$outBegIdx, (int)$outNBElement, $optInTimePeriod, $tempBuffer2); | |
| } else { | |
| $ReturnCode = StatisticFunctions::stdDev((int)$outBegIdx, $endIdx, $inReal, $optInTimePeriod, 1.0, $outBegIdx, $outNBElement, $tempBuffer2); | |
| if ($ReturnCode != ReturnCode::Success) { | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| } | |
| if ($tempBuffer1 != $outRealMiddleBand) { | |
| $outRealMiddleBand = \array_slice($tempBuffer1, 0, $outNBElement); | |
| } | |
| if ($optInNbDevUp == $optInNbDevDn) { | |
| if ($optInNbDevUp == 1.0) { | |
| for ($i = 0; $i < (int)$outNBElement; $i++) { | |
| $tempReal = $tempBuffer2[$i]; | |
| $tempReal2 = $outRealMiddleBand[$i]; | |
| $outRealUpperBand[$i] = $tempReal2 + $tempReal; | |
| $outRealLowerBand[$i] = $tempReal2 - $tempReal; | |
| } | |
| } else { | |
| for ($i = 0; $i < (int)$outNBElement; $i++) { | |
| $tempReal = $tempBuffer2[$i] * $optInNbDevUp; | |
| $tempReal2 = $outRealMiddleBand[$i]; | |
| $outRealUpperBand[$i] = $tempReal2 + $tempReal; | |
| $outRealLowerBand[$i] = $tempReal2 - $tempReal; | |
| } | |
| } | |
| } elseif ($optInNbDevUp == 1.0) { | |
| for ($i = 0; $i < (int)$outNBElement; $i++) { | |
| $tempReal = $tempBuffer2[$i]; | |
| $tempReal2 = $outRealMiddleBand[$i]; | |
| $outRealUpperBand[$i] = $tempReal2 + $tempReal; | |
| $outRealLowerBand[$i] = $tempReal2 - ($tempReal * $optInNbDevDn); | |
| } | |
| } elseif ($optInNbDevDn == 1.0) { | |
| for ($i = 0; $i < (int)$outNBElement; $i++) { | |
| $tempReal = $tempBuffer2[$i]; | |
| $tempReal2 = $outRealMiddleBand[$i]; | |
| $outRealLowerBand[$i] = $tempReal2 - $tempReal; | |
| $outRealUpperBand[$i] = $tempReal2 + ($tempReal * $optInNbDevUp); | |
| } | |
| } else { | |
| for ($i = 0; $i < (int)$outNBElement; $i++) { | |
| $tempReal = $tempBuffer2[$i]; | |
| $tempReal2 = $outRealMiddleBand[$i]; | |
| $outRealUpperBand[$i] = $tempReal2 + ($tempReal * $optInNbDevUp); | |
| $outRealLowerBand[$i] = $tempReal2 - ($tempReal * $optInNbDevDn); | |
| } | |
| } | |
| 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 dema(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $firstEMABegIdx = 0; | |
| $firstEMANbElement = 0; | |
| $secondEMABegIdx = 0; | |
| $secondEMANbElement = 0; | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 30; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $outNBElement = 0; | |
| $outBegIdx = 0; | |
| $lookbackEMA = Lookback::emaLookback($optInTimePeriod); | |
| $lookbackTotal = $lookbackEMA * 2; | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| return ReturnCode::Success; | |
| } | |
| if ($inReal == $outReal) { | |
| $firstEMA = $outReal; | |
| } else { | |
| $tempInt = $lookbackTotal + ($endIdx - $startIdx) + 1; | |
| $firstEMA = static::double($tempInt); | |
| } | |
| $k = ((double)2.0 / ((double)($optInTimePeriod + 1))); | |
| $ReturnCode = static::TA_INT_EMA( | |
| $startIdx - $lookbackEMA, $endIdx, $inReal, | |
| $optInTimePeriod, $k, | |
| $firstEMABegIdx, $firstEMANbElement, | |
| $firstEMA | |
| ); | |
| if (($ReturnCode != ReturnCode::Success) || ($firstEMANbElement == 0)) { | |
| return $ReturnCode; | |
| } | |
| $secondEMA = static::double($firstEMANbElement); | |
| $ReturnCode = static::TA_INT_EMA( | |
| 0, $firstEMANbElement - 1, $firstEMA, | |
| $optInTimePeriod, $k, | |
| $secondEMABegIdx, $secondEMANbElement, | |
| $secondEMA | |
| ); | |
| if (($ReturnCode != ReturnCode::Success) || ($secondEMANbElement == 0)) { | |
| return $ReturnCode; | |
| } | |
| $firstEMAIdx = $secondEMABegIdx; | |
| $outIdx = 0; | |
| while ($outIdx < $secondEMANbElement) { | |
| $outReal[$outIdx] = (2.0 * $firstEMA[$firstEMAIdx++]) - $secondEMA[$outIdx]; | |
| $outIdx++; | |
| } | |
| $outBegIdx = $firstEMABegIdx + $secondEMABegIdx; | |
| $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 ema(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 = 30; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| return static::TA_INT_EMA( | |
| $startIdx, $endIdx, $inReal, | |
| $optInTimePeriod, | |
| ((double)2.0 / ((double)($optInTimePeriod + 1))), | |
| $outBegIdx, $outNBElement, $outReal | |
| ); | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function htTrendline(int $startIdx, int $endIdx, array $inReal, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $a = 0.0962; | |
| $b = 0.5769; | |
| $detrender_Odd = static::double(3); | |
| $detrender_Even = static::double(3); | |
| $Q1_Odd = static::double(3); | |
| $Q1_Even = static::double(3); | |
| $jI_Odd = static::double(3); | |
| $jI_Even = static::double(3); | |
| $jQ_Odd = static::double(3); | |
| $jQ_Even = static::double(3); | |
| $smoothPrice_Idx = 0; | |
| $maxIdx_smoothPricePrice = (50 - 1); | |
| { | |
| $smoothPrice = static::double($maxIdx_smoothPricePrice + 1); | |
| }; | |
| $iTrend1 = $iTrend2 = $iTrend3 = 0.0; | |
| $tempReal = atan(1); | |
| $rad2Deg = 45.0 / $tempReal; | |
| $lookbackTotal = 63 + (static::$unstablePeriod[UnstablePeriodFunctionID::HtTrendline]); | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outBegIdx = $startIdx; | |
| $trailingWMAIdx = $startIdx - $lookbackTotal; | |
| $today = $trailingWMAIdx; | |
| $tempReal = $inReal[$today++]; | |
| $periodWMASub = $tempReal; | |
| $periodWMASum = $tempReal; | |
| $tempReal = $inReal[$today++]; | |
| $periodWMASub += $tempReal; | |
| $periodWMASum += $tempReal * 2.0; | |
| $tempReal = $inReal[$today++]; | |
| $periodWMASub += $tempReal; | |
| $periodWMASum += $tempReal * 3.0; | |
| $trailingWMAValue = 0.0; | |
| $i = 34; | |
| do { | |
| $tempReal = $inReal[$today++]; | |
| { | |
| $periodWMASub += $tempReal; | |
| $periodWMASub -= $trailingWMAValue; | |
| $periodWMASum += $tempReal * 4.0; | |
| $trailingWMAValue = $inReal[$trailingWMAIdx++]; | |
| $smoothedValue = $periodWMASum * 0.1; | |
| $periodWMASum -= $periodWMASub; | |
| }; | |
| } while (--$i != 0); | |
| $hilbertIdx = 0; | |
| { | |
| $detrender_Odd[0] = 0.0; | |
| $detrender_Odd[1] = 0.0; | |
| $detrender_Odd[2] = 0.0; | |
| $detrender_Even[0] = 0.0; | |
| $detrender_Even[1] = 0.0; | |
| $detrender_Even[2] = 0.0; | |
| $detrender = 0.0; | |
| $prev_detrender_Odd = 0.0; | |
| $prev_detrender_Even = 0.0; | |
| $prev_detrender_input_Odd = 0.0; | |
| $prev_detrender_input_Even = 0.0; | |
| }; | |
| { | |
| $Q1_Odd[0] = 0.0; | |
| $Q1_Odd[1] = 0.0; | |
| $Q1_Odd[2] = 0.0; | |
| $Q1_Even[0] = 0.0; | |
| $Q1_Even[1] = 0.0; | |
| $Q1_Even[2] = 0.0; | |
| $Q1 = 0.0; | |
| $prev_Q1_Odd = 0.0; | |
| $prev_Q1_Even = 0.0; | |
| $prev_Q1_input_Odd = 0.0; | |
| $prev_Q1_input_Even = 0.0; | |
| }; | |
| { | |
| $jI_Odd[0] = 0.0; | |
| $jI_Odd[1] = 0.0; | |
| $jI_Odd[2] = 0.0; | |
| $jI_Even[0] = 0.0; | |
| $jI_Even[1] = 0.0; | |
| $jI_Even[2] = 0.0; | |
| $jI = 0.0; | |
| $prev_jI_Odd = 0.0; | |
| $prev_jI_Even = 0.0; | |
| $prev_jI_input_Odd = 0.0; | |
| $prev_jI_input_Even = 0.0; | |
| }; | |
| { | |
| $jQ_Odd[0] = 0.0; | |
| $jQ_Odd[1] = 0.0; | |
| $jQ_Odd[2] = 0.0; | |
| $jQ_Even[0] = 0.0; | |
| $jQ_Even[1] = 0.0; | |
| $jQ_Even[2] = 0.0; | |
| $jQ = 0.0; | |
| $prev_jQ_Odd = 0.0; | |
| $prev_jQ_Even = 0.0; | |
| $prev_jQ_input_Odd = 0.0; | |
| $prev_jQ_input_Even = 0.0; | |
| }; | |
| $period = 0.0; | |
| $outIdx = 0; | |
| $prevI2 = $prevQ2 = 0.0; | |
| $Re = $Im = 0.0; | |
| $I1ForOddPrev3 = $I1ForEvenPrev3 = 0.0; | |
| $I1ForOddPrev2 = $I1ForEvenPrev2 = 0.0; | |
| $smoothPeriod = 0.0; | |
| for ($i = 0; $i < 50; $i++) { | |
| $smoothPrice[$i] = 0.0; | |
| } | |
| while ($today <= $endIdx) { | |
| $adjustedPrevPeriod = (0.075 * $period) + 0.54; | |
| $todayValue = $inReal[$today]; | |
| { | |
| $periodWMASub += $todayValue; | |
| $periodWMASub -= $trailingWMAValue; | |
| $periodWMASum += $todayValue * 4.0; | |
| $trailingWMAValue = $inReal[$trailingWMAIdx++]; | |
| $smoothedValue = $periodWMASum * 0.1; | |
| $periodWMASum -= $periodWMASub; | |
| }; | |
| $smoothPrice[$smoothPrice_Idx] = $smoothedValue; | |
| if (($today % 2) == 0) { | |
| { | |
| $hilbertTempReal = $a * $smoothedValue; | |
| $detrender = -$detrender_Even[$hilbertIdx]; | |
| $detrender_Even[$hilbertIdx] = $hilbertTempReal; | |
| $detrender += $hilbertTempReal; | |
| $detrender -= $prev_detrender_Even; | |
| $prev_detrender_Even = $b * $prev_detrender_input_Even; | |
| $detrender += $prev_detrender_Even; | |
| $prev_detrender_input_Even = $smoothedValue; | |
| $detrender *= $adjustedPrevPeriod; | |
| }; | |
| { | |
| $hilbertTempReal = $a * $detrender; | |
| $Q1 = -$Q1_Even[$hilbertIdx]; | |
| $Q1_Even[$hilbertIdx] = $hilbertTempReal; | |
| $Q1 += $hilbertTempReal; | |
| $Q1 -= $prev_Q1_Even; | |
| $prev_Q1_Even = $b * $prev_Q1_input_Even; | |
| $Q1 += $prev_Q1_Even; | |
| $prev_Q1_input_Even = $detrender; | |
| $Q1 *= $adjustedPrevPeriod; | |
| }; | |
| { | |
| $hilbertTempReal = $a * $I1ForEvenPrev3; | |
| $jI = -$jI_Even[$hilbertIdx]; | |
| $jI_Even[$hilbertIdx] = $hilbertTempReal; | |
| $jI += $hilbertTempReal; | |
| $jI -= $prev_jI_Even; | |
| $prev_jI_Even = $b * $prev_jI_input_Even; | |
| $jI += $prev_jI_Even; | |
| $prev_jI_input_Even = $I1ForEvenPrev3; | |
| $jI *= $adjustedPrevPeriod; | |
| }; | |
| { | |
| $hilbertTempReal = $a * $Q1; | |
| $jQ = -$jQ_Even[$hilbertIdx]; | |
| $jQ_Even[$hilbertIdx] = $hilbertTempReal; | |
| $jQ += $hilbertTempReal; | |
| $jQ -= $prev_jQ_Even; | |
| $prev_jQ_Even = $b * $prev_jQ_input_Even; | |
| $jQ += $prev_jQ_Even; | |
| $prev_jQ_input_Even = $Q1; | |
| $jQ *= $adjustedPrevPeriod; | |
| }; | |
| if (++$hilbertIdx == 3) { | |
| $hilbertIdx = 0; | |
| } | |
| $Q2 = (0.2 * ($Q1 + $jI)) + (0.8 * $prevQ2); | |
| $I2 = (0.2 * ($I1ForEvenPrev3 - $jQ)) + (0.8 * $prevI2); | |
| $I1ForOddPrev3 = $I1ForOddPrev2; | |
| $I1ForOddPrev2 = $detrender; | |
| } else { | |
| { | |
| $hilbertTempReal = $a * $smoothedValue; | |
| $detrender = -$detrender_Odd[$hilbertIdx]; | |
| $detrender_Odd[$hilbertIdx] = $hilbertTempReal; | |
| $detrender += $hilbertTempReal; | |
| $detrender -= $prev_detrender_Odd; | |
| $prev_detrender_Odd = $b * $prev_detrender_input_Odd; | |
| $detrender += $prev_detrender_Odd; | |
| $prev_detrender_input_Odd = $smoothedValue; | |
| $detrender *= $adjustedPrevPeriod; | |
| }; | |
| { | |
| $hilbertTempReal = $a * $detrender; | |
| $Q1 = -$Q1_Odd[$hilbertIdx]; | |
| $Q1_Odd[$hilbertIdx] = $hilbertTempReal; | |
| $Q1 += $hilbertTempReal; | |
| $Q1 -= $prev_Q1_Odd; | |
| $prev_Q1_Odd = $b * $prev_Q1_input_Odd; | |
| $Q1 += $prev_Q1_Odd; | |
| $prev_Q1_input_Odd = $detrender; | |
| $Q1 *= $adjustedPrevPeriod; | |
| }; | |
| { | |
| $hilbertTempReal = $a * $I1ForOddPrev3; | |
| $jI = -$jI_Odd[$hilbertIdx]; | |
| $jI_Odd[$hilbertIdx] = $hilbertTempReal; | |
| $jI += $hilbertTempReal; | |
| $jI -= $prev_jI_Odd; | |
| $prev_jI_Odd = $b * $prev_jI_input_Odd; | |
| $jI += $prev_jI_Odd; | |
| $prev_jI_input_Odd = $I1ForOddPrev3; | |
| $jI *= $adjustedPrevPeriod; | |
| }; | |
| { | |
| $hilbertTempReal = $a * $Q1; | |
| $jQ = -$jQ_Odd[$hilbertIdx]; | |
| $jQ_Odd[$hilbertIdx] = $hilbertTempReal; | |
| $jQ += $hilbertTempReal; | |
| $jQ -= $prev_jQ_Odd; | |
| $prev_jQ_Odd = $b * $prev_jQ_input_Odd; | |
| $jQ += $prev_jQ_Odd; | |
| $prev_jQ_input_Odd = $Q1; | |
| $jQ *= $adjustedPrevPeriod; | |
| }; | |
| $Q2 = (0.2 * ($Q1 + $jI)) + (0.8 * $prevQ2); | |
| $I2 = (0.2 * ($I1ForOddPrev3 - $jQ)) + (0.8 * $prevI2); | |
| $I1ForEvenPrev3 = $I1ForEvenPrev2; | |
| $I1ForEvenPrev2 = $detrender; | |
| } | |
| $Re = (0.2 * (($I2 * $prevI2) + ($Q2 * $prevQ2))) + (0.8 * $Re); | |
| $Im = (0.2 * (($I2 * $prevQ2) - ($Q2 * $prevI2))) + (0.8 * $Im); | |
| $prevQ2 = $Q2; | |
| $prevI2 = $I2; | |
| $tempReal = $period; | |
| if (($Im != 0.0) && ($Re != 0.0)) { | |
| $period = 360.0 / (atan($Im / $Re) * $rad2Deg); | |
| } | |
| $tempReal2 = 1.5 * $tempReal; | |
| if ($period > $tempReal2) { | |
| $period = $tempReal2; | |
| } | |
| $tempReal2 = 0.67 * $tempReal; | |
| if ($period < $tempReal2) { | |
| $period = $tempReal2; | |
| } | |
| if ($period < 6) { | |
| $period = 6; | |
| } elseif ($period > 50) { | |
| $period = 50; | |
| } | |
| $period = (0.2 * $period) + (0.8 * $tempReal); | |
| $smoothPeriod = (0.33 * $period) + (0.67 * $smoothPeriod); | |
| $DCPeriod = $smoothPeriod + 0.5; | |
| $DCPeriodInt = (int)$DCPeriod; | |
| $idxothPricePrice = $today; | |
| $tempReal = 0.0; | |
| for ($i = 0; $i < $DCPeriodInt; $i++) { | |
| $tempReal += $inReal[$idxothPricePrice--]; | |
| } | |
| if ($DCPeriodInt > 0) { | |
| $tempReal = $tempReal / (double)$DCPeriodInt; | |
| } | |
| $tempReal2 = (4.0 * $tempReal + 3.0 * $iTrend1 + 2.0 * $iTrend2 + $iTrend3) / 10.0; | |
| $iTrend3 = $iTrend2; | |
| $iTrend2 = $iTrend1; | |
| $iTrend1 = $tempReal; | |
| if ($today >= $startIdx) { | |
| $outReal[$outIdx++] = $tempReal2; | |
| } | |
| { | |
| $smoothPrice_Idx++; | |
| if ($smoothPrice_Idx > $maxIdx_smoothPricePrice) { | |
| $smoothPrice_Idx = 0; | |
| } | |
| }; | |
| $today++; | |
| } | |
| $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 kama(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $constMax = 2.0 / (30.0 + 1.0); | |
| $constDiff = 2.0 / (2.0 + 1.0) - $constMax; | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 30; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| $lookbackTotal = $optInTimePeriod + (static::$unstablePeriod[UnstablePeriodFunctionID::KAMA]); | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $sumROC1 = 0.0; | |
| $today = $startIdx - $lookbackTotal; | |
| $trailingIdx = $today; | |
| $i = $optInTimePeriod; | |
| while ($i-- > 0) { | |
| $tempReal = $inReal[$today++]; | |
| $tempReal -= $inReal[$today]; | |
| $sumROC1 += abs($tempReal); | |
| } | |
| $prevKAMA = $inReal[$today - 1]; | |
| $tempReal = $inReal[$today]; | |
| $tempReal2 = $inReal[$trailingIdx++]; | |
| $periodROC = $tempReal - $tempReal2; | |
| $trailingValue = $tempReal2; | |
| if (($sumROC1 <= $periodROC) || (((-0.00000001) < $sumROC1) && ($sumROC1 < 0.00000001))) { | |
| $tempReal = 1.0; | |
| } else { | |
| $tempReal = abs($periodROC / $sumROC1); | |
| } | |
| $tempReal = ($tempReal * $constDiff) + $constMax; | |
| $tempReal *= $tempReal; | |
| $prevKAMA = (($inReal[$today++] - $prevKAMA) * $tempReal) + $prevKAMA; | |
| while ($today <= $startIdx) { | |
| $tempReal = $inReal[$today]; | |
| $tempReal2 = $inReal[$trailingIdx++]; | |
| $periodROC = $tempReal - $tempReal2; | |
| $sumROC1 -= abs($trailingValue - $tempReal2); | |
| $sumROC1 += abs($tempReal - $inReal[$today - 1]); | |
| $trailingValue = $tempReal2; | |
| if (($sumROC1 <= $periodROC) || (((-0.00000001) < $sumROC1) && ($sumROC1 < 0.00000001))) { | |
| $tempReal = 1.0; | |
| } else { | |
| $tempReal = abs($periodROC / $sumROC1); | |
| } | |
| $tempReal = ($tempReal * $constDiff) + $constMax; | |
| $tempReal *= $tempReal; | |
| $prevKAMA = (($inReal[$today++] - $prevKAMA) * $tempReal) + $prevKAMA; | |
| } | |
| $outReal[0] = $prevKAMA; | |
| $outIdx = 1; | |
| $outBegIdx = $today - 1; | |
| while ($today <= $endIdx) { | |
| $tempReal = $inReal[$today]; | |
| $tempReal2 = $inReal[$trailingIdx++]; | |
| $periodROC = $tempReal - $tempReal2; | |
| $sumROC1 -= abs($trailingValue - $tempReal2); | |
| $sumROC1 += abs($tempReal - $inReal[$today - 1]); | |
| $trailingValue = $tempReal2; | |
| if (($sumROC1 <= $periodROC) || (((-0.00000001) < $sumROC1) && ($sumROC1 < 0.00000001))) { | |
| $tempReal = 1.0; | |
| } else { | |
| $tempReal = abs($periodROC / $sumROC1); | |
| } | |
| $tempReal = ($tempReal * $constDiff) + $constMax; | |
| $tempReal *= $tempReal; | |
| $prevKAMA = (($inReal[$today++] - $prevKAMA) * $tempReal) + $prevKAMA; | |
| $outReal[$outIdx++] = $prevKAMA; | |
| } | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInTimePeriod | |
| * @param int $optInMAType | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function movingAverage(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int $optInMAType, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 30; | |
| } elseif (((int)$optInTimePeriod < 1) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInTimePeriod == 1) { | |
| $nbElement = $endIdx - $startIdx + 1; | |
| $outNBElement = $nbElement; | |
| for ($todayIdx = $startIdx, $outIdx = 0; $outIdx < $nbElement; $outIdx++, $todayIdx++) { | |
| $outReal[$outIdx] = $inReal[$todayIdx]; | |
| } | |
| $outBegIdx = $startIdx; | |
| return ReturnCode::Success; | |
| } | |
| switch ($optInMAType) { | |
| case MovingAverageType::SMA: | |
| $ReturnCode = self::sma( | |
| $startIdx, $endIdx, $inReal, $optInTimePeriod, | |
| $outBegIdx, $outNBElement, $outReal | |
| ); | |
| break; | |
| case MovingAverageType::EMA: | |
| $ReturnCode = self::ema( | |
| $startIdx, $endIdx, $inReal, $optInTimePeriod, | |
| $outBegIdx, $outNBElement, $outReal | |
| ); | |
| break; | |
| case MovingAverageType::WMA: | |
| $ReturnCode = self::wma( | |
| $startIdx, $endIdx, $inReal, $optInTimePeriod, | |
| $outBegIdx, $outNBElement, $outReal | |
| ); | |
| break; | |
| case MovingAverageType::DEMA: | |
| $ReturnCode = self::dema( | |
| $startIdx, $endIdx, $inReal, $optInTimePeriod, | |
| $outBegIdx, $outNBElement, $outReal | |
| ); | |
| break; | |
| case MovingAverageType::TEMA: | |
| $ReturnCode = self::tema( | |
| $startIdx, $endIdx, $inReal, $optInTimePeriod, | |
| $outBegIdx, $outNBElement, $outReal | |
| ); | |
| break; | |
| case MovingAverageType::TRIMA: | |
| $ReturnCode = self::trima( | |
| $startIdx, $endIdx, $inReal, $optInTimePeriod, | |
| $outBegIdx, $outNBElement, $outReal | |
| ); | |
| break; | |
| case MovingAverageType::KAMA: | |
| $ReturnCode = self::kama( | |
| $startIdx, $endIdx, $inReal, $optInTimePeriod, | |
| $outBegIdx, $outNBElement, $outReal | |
| ); | |
| break; | |
| case MovingAverageType::MAMA: | |
| $dummyBuffer = static::double(($endIdx - $startIdx + 1)); | |
| $ReturnCode = self::mama( | |
| $startIdx, $endIdx, $inReal, 0.5, 0.05, | |
| $outBegIdx, $outNBElement, | |
| $outReal, $dummyBuffer | |
| ); | |
| break; | |
| case MovingAverageType::T3: | |
| $ReturnCode = self::t3( | |
| $startIdx, $endIdx, $inReal, | |
| $optInTimePeriod, 0.7, | |
| $outBegIdx, $outNBElement, $outReal | |
| ); | |
| break; | |
| default: | |
| $ReturnCode = ReturnCode::BadParam; | |
| break; | |
| } | |
| return $ReturnCode; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param float $optInFastLimit | |
| * @param float $optInSlowLimit | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outMAMA | |
| * @param array $outFAMA | |
| * | |
| * @return int | |
| */ | |
| public static function mama(int $startIdx, int $endIdx, array $inReal, float $optInFastLimit, float $optInSlowLimit, int &$outBegIdx, int &$outNBElement, array &$outMAMA, array &$outFAMA): int | |
| { | |
| $a = 0.0962; | |
| $b = 0.5769; | |
| $detrender_Odd = static::double(3); | |
| $detrender_Even = static::double(3); | |
| $Q1_Odd = static::double(3); | |
| $Q1_Even = static::double(3); | |
| $jI_Odd = static::double(3); | |
| $jI_Even = static::double(3); | |
| $jQ_Odd = static::double(3); | |
| $jQ_Even = static::double(3); | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ($optInFastLimit == (-4e+37)) { | |
| $optInFastLimit = 5.000000e-1; | |
| } elseif (($optInFastLimit < 1.000000e-2) || ($optInFastLimit > 9.900000e-1)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInSlowLimit == (-4e+37)) { | |
| $optInSlowLimit = 5.000000e-2; | |
| } elseif (($optInSlowLimit < 1.000000e-2) || ($optInSlowLimit > 9.900000e-1)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $rad2Deg = 180.0 / (4.0 * atan(1)); | |
| $lookbackTotal = 32 + (static::$unstablePeriod[UnstablePeriodFunctionID::MAMA]); | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outBegIdx = $startIdx; | |
| $trailingWMAIdx = $startIdx - $lookbackTotal; | |
| $today = $trailingWMAIdx; | |
| $tempReal = $inReal[$today++]; | |
| $periodWMASub = $tempReal; | |
| $periodWMASum = $tempReal; | |
| $tempReal = $inReal[$today++]; | |
| $periodWMASub += $tempReal; | |
| $periodWMASum += $tempReal * 2.0; | |
| $tempReal = $inReal[$today++]; | |
| $periodWMASub += $tempReal; | |
| $periodWMASum += $tempReal * 3.0; | |
| $trailingWMAValue = 0.0; | |
| $i = 9; | |
| do { | |
| $tempReal = $inReal[$today++]; | |
| { | |
| $periodWMASub += $tempReal; | |
| $periodWMASub -= $trailingWMAValue; | |
| $periodWMASum += $tempReal * 4.0; | |
| $trailingWMAValue = $inReal[$trailingWMAIdx++]; | |
| $smoothedValue = $periodWMASum * 0.1; | |
| $periodWMASum -= $periodWMASub; | |
| }; | |
| } while (--$i != 0); | |
| $hilbertIdx = 0; | |
| { | |
| $detrender_Odd[0] = 0.0; | |
| $detrender_Odd[1] = 0.0; | |
| $detrender_Odd[2] = 0.0; | |
| $detrender_Even[0] = 0.0; | |
| $detrender_Even[1] = 0.0; | |
| $detrender_Even[2] = 0.0; | |
| $detrender = 0.0; | |
| $prev_detrender_Odd = 0.0; | |
| $prev_detrender_Even = 0.0; | |
| $prev_detrender_input_Odd = 0.0; | |
| $prev_detrender_input_Even = 0.0; | |
| }; | |
| { | |
| $Q1_Odd[0] = 0.0; | |
| $Q1_Odd[1] = 0.0; | |
| $Q1_Odd[2] = 0.0; | |
| $Q1_Even[0] = 0.0; | |
| $Q1_Even[1] = 0.0; | |
| $Q1_Even[2] = 0.0; | |
| $Q1 = 0.0; | |
| $prev_Q1_Odd = 0.0; | |
| $prev_Q1_Even = 0.0; | |
| $prev_Q1_input_Odd = 0.0; | |
| $prev_Q1_input_Even = 0.0; | |
| }; | |
| { | |
| $jI_Odd[0] = 0.0; | |
| $jI_Odd[1] = 0.0; | |
| $jI_Odd[2] = 0.0; | |
| $jI_Even[0] = 0.0; | |
| $jI_Even[1] = 0.0; | |
| $jI_Even[2] = 0.0; | |
| $jI = 0.0; | |
| $prev_jI_Odd = 0.0; | |
| $prev_jI_Even = 0.0; | |
| $prev_jI_input_Odd = 0.0; | |
| $prev_jI_input_Even = 0.0; | |
| }; | |
| { | |
| $jQ_Odd[0] = 0.0; | |
| $jQ_Odd[1] = 0.0; | |
| $jQ_Odd[2] = 0.0; | |
| $jQ_Even[0] = 0.0; | |
| $jQ_Even[1] = 0.0; | |
| $jQ_Even[2] = 0.0; | |
| $jQ = 0.0; | |
| $prev_jQ_Odd = 0.0; | |
| $prev_jQ_Even = 0.0; | |
| $prev_jQ_input_Odd = 0.0; | |
| $prev_jQ_input_Even = 0.0; | |
| }; | |
| $period = 0.0; | |
| $outIdx = 0; | |
| $prevI2 = $prevQ2 = 0.0; | |
| $Re = $Im = 0.0; | |
| $mama = $fama = 0.0; | |
| $I1ForOddPrev3 = $I1ForEvenPrev3 = 0.0; | |
| $I1ForOddPrev2 = $I1ForEvenPrev2 = 0.0; | |
| $prevPhase = 0.0; | |
| while ($today <= $endIdx) { | |
| $adjustedPrevPeriod = (0.075 * $period) + 0.54; | |
| $todayValue = $inReal[$today]; | |
| { | |
| $periodWMASub += $todayValue; | |
| $periodWMASub -= $trailingWMAValue; | |
| $periodWMASum += $todayValue * 4.0; | |
| $trailingWMAValue = $inReal[$trailingWMAIdx++]; | |
| $smoothedValue = $periodWMASum * 0.1; | |
| $periodWMASum -= $periodWMASub; | |
| }; | |
| if (($today % 2) == 0) { | |
| { | |
| $hilbertTempReal = $a * $smoothedValue; | |
| $detrender = -$detrender_Even[$hilbertIdx]; | |
| $detrender_Even[$hilbertIdx] = $hilbertTempReal; | |
| $detrender += $hilbertTempReal; | |
| $detrender -= $prev_detrender_Even; | |
| $prev_detrender_Even = $b * $prev_detrender_input_Even; | |
| $detrender += $prev_detrender_Even; | |
| $prev_detrender_input_Even = $smoothedValue; | |
| $detrender *= $adjustedPrevPeriod; | |
| }; | |
| { | |
| $hilbertTempReal = $a * $detrender; | |
| $Q1 = -$Q1_Even[$hilbertIdx]; | |
| $Q1_Even[$hilbertIdx] = $hilbertTempReal; | |
| $Q1 += $hilbertTempReal; | |
| $Q1 -= $prev_Q1_Even; | |
| $prev_Q1_Even = $b * $prev_Q1_input_Even; | |
| $Q1 += $prev_Q1_Even; | |
| $prev_Q1_input_Even = $detrender; | |
| $Q1 *= $adjustedPrevPeriod; | |
| }; | |
| { | |
| $hilbertTempReal = $a * $I1ForEvenPrev3; | |
| $jI = -$jI_Even[$hilbertIdx]; | |
| $jI_Even[$hilbertIdx] = $hilbertTempReal; | |
| $jI += $hilbertTempReal; | |
| $jI -= $prev_jI_Even; | |
| $prev_jI_Even = $b * $prev_jI_input_Even; | |
| $jI += $prev_jI_Even; | |
| $prev_jI_input_Even = $I1ForEvenPrev3; | |
| $jI *= $adjustedPrevPeriod; | |
| }; | |
| { | |
| $hilbertTempReal = $a * $Q1; | |
| $jQ = -$jQ_Even[$hilbertIdx]; | |
| $jQ_Even[$hilbertIdx] = $hilbertTempReal; | |
| $jQ += $hilbertTempReal; | |
| $jQ -= $prev_jQ_Even; | |
| $prev_jQ_Even = $b * $prev_jQ_input_Even; | |
| $jQ += $prev_jQ_Even; | |
| $prev_jQ_input_Even = $Q1; | |
| $jQ *= $adjustedPrevPeriod; | |
| }; | |
| if (++$hilbertIdx == 3) { | |
| $hilbertIdx = 0; | |
| } | |
| $Q2 = (0.2 * ($Q1 + $jI)) + (0.8 * $prevQ2); | |
| $I2 = (0.2 * ($I1ForEvenPrev3 - $jQ)) + (0.8 * $prevI2); | |
| $I1ForOddPrev3 = $I1ForOddPrev2; | |
| $I1ForOddPrev2 = $detrender; | |
| if ($I1ForEvenPrev3 != 0.0) { | |
| $tempReal2 = (atan($Q1 / $I1ForEvenPrev3) * $rad2Deg); | |
| } else { | |
| $tempReal2 = 0.0; | |
| } | |
| } else { | |
| { | |
| $hilbertTempReal = $a * $smoothedValue; | |
| $detrender = -$detrender_Odd[$hilbertIdx]; | |
| $detrender_Odd[$hilbertIdx] = $hilbertTempReal; | |
| $detrender += $hilbertTempReal; | |
| $detrender -= $prev_detrender_Odd; | |
| $prev_detrender_Odd = $b * $prev_detrender_input_Odd; | |
| $detrender += $prev_detrender_Odd; | |
| $prev_detrender_input_Odd = $smoothedValue; | |
| $detrender *= $adjustedPrevPeriod; | |
| }; | |
| { | |
| $hilbertTempReal = $a * $detrender; | |
| $Q1 = -$Q1_Odd[$hilbertIdx]; | |
| $Q1_Odd[$hilbertIdx] = $hilbertTempReal; | |
| $Q1 += $hilbertTempReal; | |
| $Q1 -= $prev_Q1_Odd; | |
| $prev_Q1_Odd = $b * $prev_Q1_input_Odd; | |
| $Q1 += $prev_Q1_Odd; | |
| $prev_Q1_input_Odd = $detrender; | |
| $Q1 *= $adjustedPrevPeriod; | |
| }; | |
| { | |
| $hilbertTempReal = $a * $I1ForOddPrev3; | |
| $jI = -$jI_Odd[$hilbertIdx]; | |
| $jI_Odd[$hilbertIdx] = $hilbertTempReal; | |
| $jI += $hilbertTempReal; | |
| $jI -= $prev_jI_Odd; | |
| $prev_jI_Odd = $b * $prev_jI_input_Odd; | |
| $jI += $prev_jI_Odd; | |
| $prev_jI_input_Odd = $I1ForOddPrev3; | |
| $jI *= $adjustedPrevPeriod; | |
| }; | |
| { | |
| $hilbertTempReal = $a * $Q1; | |
| $jQ = -$jQ_Odd[$hilbertIdx]; | |
| $jQ_Odd[$hilbertIdx] = $hilbertTempReal; | |
| $jQ += $hilbertTempReal; | |
| $jQ -= $prev_jQ_Odd; | |
| $prev_jQ_Odd = $b * $prev_jQ_input_Odd; | |
| $jQ += $prev_jQ_Odd; | |
| $prev_jQ_input_Odd = $Q1; | |
| $jQ *= $adjustedPrevPeriod; | |
| }; | |
| $Q2 = (0.2 * ($Q1 + $jI)) + (0.8 * $prevQ2); | |
| $I2 = (0.2 * ($I1ForOddPrev3 - $jQ)) + (0.8 * $prevI2); | |
| $I1ForEvenPrev3 = $I1ForEvenPrev2; | |
| $I1ForEvenPrev2 = $detrender; | |
| if ($I1ForOddPrev3 != 0.0) { | |
| $tempReal2 = (atan($Q1 / $I1ForOddPrev3) * $rad2Deg); | |
| } else { | |
| $tempReal2 = 0.0; | |
| } | |
| } | |
| $tempReal = $prevPhase - $tempReal2; | |
| $prevPhase = $tempReal2; | |
| if ($tempReal < 1.0) { | |
| $tempReal = 1.0; | |
| } | |
| if ($tempReal > 1.0) { | |
| $tempReal = $optInFastLimit / $tempReal; | |
| if ($tempReal < $optInSlowLimit) { | |
| $tempReal = $optInSlowLimit; | |
| } | |
| } else { | |
| $tempReal = $optInFastLimit; | |
| } | |
| $mama = ($tempReal * $todayValue) + ((1 - $tempReal) * $mama); | |
| $tempReal *= 0.5; | |
| $fama = ($tempReal * $mama) + ((1 - $tempReal) * $fama); | |
| if ($today >= $startIdx) { | |
| $outMAMA[$outIdx] = $mama; | |
| $outFAMA[$outIdx++] = $fama; | |
| } | |
| $Re = (0.2 * (($I2 * $prevI2) + ($Q2 * $prevQ2))) + (0.8 * $Re); | |
| $Im = (0.2 * (($I2 * $prevQ2) - ($Q2 * $prevI2))) + (0.8 * $Im); | |
| $prevQ2 = $Q2; | |
| $prevI2 = $I2; | |
| $tempReal = $period; | |
| if (($Im != 0.0) && ($Re != 0.0)) { | |
| $period = 360.0 / (atan($Im / $Re) * $rad2Deg); | |
| } | |
| $tempReal2 = 1.5 * $tempReal; | |
| if ($period > $tempReal2) { | |
| $period = $tempReal2; | |
| } | |
| $tempReal2 = 0.67 * $tempReal; | |
| if ($period < $tempReal2) { | |
| $period = $tempReal2; | |
| } | |
| if ($period < 6) { | |
| $period = 6; | |
| } elseif ($period > 50) { | |
| $period = 50; | |
| } | |
| $period = (0.2 * $period) + (0.8 * $tempReal); | |
| $today++; | |
| } | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param array $inPeriods | |
| * @param int $optInMinPeriod | |
| * @param int $optInMaxPeriod | |
| * @param int $optInMAType | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function movingAverageVariablePeriod(int $startIdx, int $endIdx, array $inReal, array &$inPeriods, int $optInMinPeriod, int $optInMaxPeriod, int $optInMAType, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $localBegIdx = 0; | |
| $localNbElement = 0; | |
| if ((int)$optInMinPeriod == (PHP_INT_MIN)) { | |
| $optInMinPeriod = 2; | |
| } elseif (((int)$optInMinPeriod < 2) || ((int)$optInMinPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ((int)$optInMaxPeriod == (PHP_INT_MIN)) { | |
| $optInMaxPeriod = 30; | |
| } elseif (((int)$optInMaxPeriod < 2) || ((int)$optInMaxPeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $lookbackTotal = Lookback::movingAverageLookback($optInMaxPeriod, $optInMAType); | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| if ($lookbackTotal > $startIdx) { | |
| $tempInt = $lookbackTotal; | |
| } else { | |
| $tempInt = $startIdx; | |
| } | |
| if ($tempInt > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outputSize = $endIdx - $tempInt + 1; | |
| $localOutputArray = \array_pad([], $outputSize, 0.); | |
| $localPeriodArray = \array_pad([], $outputSize, 0); | |
| for ($i = 0; $i < $outputSize; $i++) { | |
| $tempInt = (int)($inPeriods[$startIdx + $i]); | |
| if ($tempInt < $optInMinPeriod) { | |
| $tempInt = $optInMinPeriod; | |
| } elseif ($tempInt > $optInMaxPeriod) { | |
| $tempInt = $optInMaxPeriod; | |
| } | |
| $localPeriodArray[$i] = $tempInt; | |
| } | |
| for ($i = 0; $i < $outputSize; $i++) { | |
| $curPeriod = $localPeriodArray[$i]; | |
| if ($curPeriod != 0) { | |
| $ReturnCode = self::movingAverage( | |
| $startIdx, $endIdx, $inReal, | |
| $curPeriod, $optInMAType, | |
| $localBegIdx, $localNbElement, $localOutputArray | |
| ); | |
| if ($ReturnCode != ReturnCode::Success) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| $outReal[$i] = $localOutputArray[$i]; | |
| for ($j = $i + 1; $j < $outputSize; $j++) { | |
| if ($localPeriodArray[$j] == $curPeriod) { | |
| $localPeriodArray[$j] = 0; | |
| $outReal[$j] = $localOutputArray[$j]; | |
| } | |
| } | |
| } | |
| } | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $outputSize; | |
| 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 midPoint(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; | |
| } | |
| $nbInitialElementNeeded = ($optInTimePeriod - 1); | |
| if ($startIdx < $nbInitialElementNeeded) { | |
| $startIdx = $nbInitialElementNeeded; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| $today = $startIdx; | |
| $trailingIdx = $startIdx - $nbInitialElementNeeded; | |
| while ($today <= $endIdx) { | |
| $lowest = $inReal[$trailingIdx++]; | |
| $highest = $lowest; | |
| for ($i = $trailingIdx; $i <= $today; $i++) { | |
| $tmp = $inReal[$i]; | |
| if ($tmp < $lowest) { | |
| $lowest = $tmp; | |
| } elseif ($tmp > $highest) { | |
| $highest = $tmp; | |
| } | |
| } | |
| $outReal[$outIdx++] = ($highest + $lowest) / 2.0; | |
| $today++; | |
| } | |
| $outBegIdx = $startIdx; | |
| $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 midPrice(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; | |
| } | |
| $nbInitialElementNeeded = ($optInTimePeriod - 1); | |
| if ($startIdx < $nbInitialElementNeeded) { | |
| $startIdx = $nbInitialElementNeeded; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outIdx = 0; | |
| $today = $startIdx; | |
| $trailingIdx = $startIdx - $nbInitialElementNeeded; | |
| while ($today <= $endIdx) { | |
| $lowest = $inLow[$trailingIdx]; | |
| $highest = $inHigh[$trailingIdx]; | |
| $trailingIdx++; | |
| for ($i = $trailingIdx; $i <= $today; $i++) { | |
| $tmp = $inLow[$i]; | |
| if ($tmp < $lowest) { | |
| $lowest = $tmp; | |
| } | |
| $tmp = $inHigh[$i]; | |
| if ($tmp > $highest) { | |
| $highest = $tmp; | |
| } | |
| } | |
| $outReal[$outIdx++] = ($highest + $lowest) / 2.0; | |
| $today++; | |
| } | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inHigh | |
| * @param array $inLow | |
| * @param float $optInAcceleration | |
| * @param float $optInMaximum | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function sar(int $startIdx, int $endIdx, array $inHigh, array $inLow, float $optInAcceleration, float $optInMaximum, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $tempInt = 0; | |
| $ep_temp = static::double(1); | |
| if ($optInAcceleration == (-4e+37)) { | |
| $optInAcceleration = 2.000000e-2; | |
| } elseif (($optInAcceleration < 0.000000e+0) || ($optInAcceleration > 3.000000e+37)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInMaximum == (-4e+37)) { | |
| $optInMaximum = 2.000000e-1; | |
| } elseif (($optInMaximum < 0.000000e+0) || ($optInMaximum > 3.000000e+37)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($startIdx < 1) { | |
| $startIdx = 1; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $af = $optInAcceleration; | |
| if ($af > $optInMaximum) { | |
| $af = $optInAcceleration = $optInMaximum; | |
| } | |
| $ReturnCode = MomentumIndicators::minusDM( | |
| $startIdx, $startIdx, $inHigh, $inLow, 1, | |
| $tempInt, $tempInt, | |
| $ep_temp | |
| ); | |
| if ($ep_temp[0] > 0) { | |
| $isLong = 0; | |
| } else { | |
| $isLong = 1; | |
| } | |
| if ($ReturnCode != ReturnCode::Success) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| $outBegIdx = $startIdx; | |
| $outIdx = 0; | |
| $todayIdx = $startIdx; | |
| $newHigh = $inHigh[$todayIdx - 1]; | |
| $newLow = $inLow[$todayIdx - 1]; | |
| if ($isLong == 1) { | |
| $ep = $inHigh[$todayIdx]; | |
| $sar = $newLow; | |
| } else { | |
| $ep = $inLow[$todayIdx]; | |
| $sar = $newHigh; | |
| } | |
| $newLow = $inLow[$todayIdx]; | |
| $newHigh = $inHigh[$todayIdx]; | |
| while ($todayIdx <= $endIdx) { | |
| $prevLow = $newLow; | |
| $prevHigh = $newHigh; | |
| $newLow = $inLow[$todayIdx]; | |
| $newHigh = $inHigh[$todayIdx]; | |
| $todayIdx++; | |
| if ($isLong == 1) { | |
| if ($newLow <= $sar) { | |
| $isLong = 0; | |
| $sar = $ep; | |
| if ($sar < $prevHigh) { | |
| $sar = $prevHigh; | |
| } | |
| if ($sar < $newHigh) { | |
| $sar = $newHigh; | |
| } | |
| $outReal[$outIdx++] = $sar; | |
| $af = $optInAcceleration; | |
| $ep = $newLow; | |
| $sar = $sar + $af * ($ep - $sar); | |
| if ($sar < $prevHigh) { | |
| $sar = $prevHigh; | |
| } | |
| if ($sar < $newHigh) { | |
| $sar = $newHigh; | |
| } | |
| } else { | |
| $outReal[$outIdx++] = $sar; | |
| if ($newHigh > $ep) { | |
| $ep = $newHigh; | |
| $af += $optInAcceleration; | |
| if ($af > $optInMaximum) { | |
| $af = $optInMaximum; | |
| } | |
| } | |
| $sar = $sar + $af * ($ep - $sar); | |
| if ($sar > $prevLow) { | |
| $sar = $prevLow; | |
| } | |
| if ($sar > $newLow) { | |
| $sar = $newLow; | |
| } | |
| } | |
| } else { | |
| if ($newHigh >= $sar) { | |
| $isLong = 1; | |
| $sar = $ep; | |
| if ($sar > $prevLow) { | |
| $sar = $prevLow; | |
| } | |
| if ($sar > $newLow) { | |
| $sar = $newLow; | |
| } | |
| $outReal[$outIdx++] = $sar; | |
| $af = $optInAcceleration; | |
| $ep = $newHigh; | |
| $sar = $sar + $af * ($ep - $sar); | |
| if ($sar > $prevLow) { | |
| $sar = $prevLow; | |
| } | |
| if ($sar > $newLow) { | |
| $sar = $newLow; | |
| } | |
| } else { | |
| $outReal[$outIdx++] = $sar; | |
| if ($newLow < $ep) { | |
| $ep = $newLow; | |
| $af += $optInAcceleration; | |
| if ($af > $optInMaximum) { | |
| $af = $optInMaximum; | |
| } | |
| } | |
| $sar = $sar + $af * ($ep - $sar); | |
| if ($sar < $prevHigh) { | |
| $sar = $prevHigh; | |
| } | |
| if ($sar < $newHigh) { | |
| $sar = $newHigh; | |
| } | |
| } | |
| } | |
| } | |
| $outNBElement = $outIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inHigh | |
| * @param array $inLow | |
| * @param float $optInStartValue | |
| * @param float $optInOffsetOnReverse | |
| * @param float $optInAccelerationInitLong | |
| * @param float $optInAccelerationLong | |
| * @param float $optInAccelerationMaxLong | |
| * @param float $optInAccelerationInitShort | |
| * @param float $optInAccelerationShort | |
| * @param float $optInAccelerationMaxShort | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function sarExt(int $startIdx, int $endIdx, array $inHigh, array $inLow, float $optInStartValue, float $optInOffsetOnReverse, float $optInAccelerationInitLong, float $optInAccelerationLong, float $optInAccelerationMaxLong, float $optInAccelerationInitShort, float $optInAccelerationShort, float $optInAccelerationMaxShort, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $tempInt = 0; | |
| $ep_temp = static::double(1); | |
| if ($optInStartValue == (-4e+37)) { | |
| $optInStartValue = 0.000000e+0; | |
| } elseif (($optInStartValue < -3.000000e+37) || ($optInStartValue > 3.000000e+37)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInOffsetOnReverse == (-4e+37)) { | |
| $optInOffsetOnReverse = 0.000000e+0; | |
| } elseif (($optInOffsetOnReverse < 0.000000e+0) || ($optInOffsetOnReverse > 3.000000e+37)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInAccelerationInitLong == (-4e+37)) { | |
| $optInAccelerationInitLong = 2.000000e-2; | |
| } elseif (($optInAccelerationInitLong < 0.000000e+0) || ($optInAccelerationInitLong > 3.000000e+37)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInAccelerationLong == (-4e+37)) { | |
| $optInAccelerationLong = 2.000000e-2; | |
| } elseif (($optInAccelerationLong < 0.000000e+0) || ($optInAccelerationLong > 3.000000e+37)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInAccelerationMaxLong == (-4e+37)) { | |
| $optInAccelerationMaxLong = 2.000000e-1; | |
| } elseif (($optInAccelerationMaxLong < 0.000000e+0) || ($optInAccelerationMaxLong > 3.000000e+37)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInAccelerationInitShort == (-4e+37)) { | |
| $optInAccelerationInitShort = 2.000000e-2; | |
| } elseif (($optInAccelerationInitShort < 0.000000e+0) || ($optInAccelerationInitShort > 3.000000e+37)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInAccelerationShort == (-4e+37)) { | |
| $optInAccelerationShort = 2.000000e-2; | |
| } elseif (($optInAccelerationShort < 0.000000e+0) || ($optInAccelerationShort > 3.000000e+37)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInAccelerationMaxShort == (-4e+37)) { | |
| $optInAccelerationMaxShort = 2.000000e-1; | |
| } elseif (($optInAccelerationMaxShort < 0.000000e+0) || ($optInAccelerationMaxShort > 3.000000e+37)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($startIdx < 1) { | |
| $startIdx = 1; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $afLong = $optInAccelerationInitLong; | |
| $afShort = $optInAccelerationInitShort; | |
| if ($afLong > $optInAccelerationMaxLong) { | |
| $afLong = $optInAccelerationInitLong = $optInAccelerationMaxLong; | |
| } | |
| if ($optInAccelerationLong > $optInAccelerationMaxLong) { | |
| $optInAccelerationLong = $optInAccelerationMaxLong; | |
| } | |
| if ($afShort > $optInAccelerationMaxShort) { | |
| $afShort = $optInAccelerationInitShort = $optInAccelerationMaxShort; | |
| } | |
| if ($optInAccelerationShort > $optInAccelerationMaxShort) { | |
| $optInAccelerationShort = $optInAccelerationMaxShort; | |
| } | |
| if ($optInStartValue == 0) { | |
| $ReturnCode = MomentumIndicators::minusDM( | |
| $startIdx, $startIdx, $inHigh, $inLow, 1, | |
| $tempInt, $tempInt, | |
| $ep_temp | |
| ); | |
| if ($ep_temp[0] > 0) { | |
| $isLong = 0; | |
| } else { | |
| $isLong = 1; | |
| } | |
| if ($ReturnCode != ReturnCode::Success) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| } elseif ($optInStartValue > 0) { | |
| $isLong = 1; | |
| } else { | |
| $isLong = 0; | |
| } | |
| $outBegIdx = $startIdx; | |
| $outIdx = 0; | |
| $todayIdx = $startIdx; | |
| $newHigh = $inHigh[$todayIdx - 1]; | |
| $newLow = $inLow[$todayIdx - 1]; | |
| if ($optInStartValue == 0) { | |
| if ($isLong == 1) { | |
| $ep = $inHigh[$todayIdx]; | |
| $sar = $newLow; | |
| } else { | |
| $ep = $inLow[$todayIdx]; | |
| $sar = $newHigh; | |
| } | |
| } elseif ($optInStartValue > 0) { | |
| $ep = $inHigh[$todayIdx]; | |
| $sar = $optInStartValue; | |
| } else { | |
| $ep = $inLow[$todayIdx]; | |
| $sar = abs($optInStartValue); | |
| } | |
| $newLow = $inLow[$todayIdx]; | |
| $newHigh = $inHigh[$todayIdx]; | |
| while ($todayIdx <= $endIdx) { | |
| $prevLow = $newLow; | |
| $prevHigh = $newHigh; | |
| $newLow = $inLow[$todayIdx]; | |
| $newHigh = $inHigh[$todayIdx]; | |
| $todayIdx++; | |
| if ($isLong == 1) { | |
| if ($newLow <= $sar) { | |
| $isLong = 0; | |
| $sar = $ep; | |
| if ($sar < $prevHigh) { | |
| $sar = $prevHigh; | |
| } | |
| if ($sar < $newHigh) { | |
| $sar = $newHigh; | |
| } | |
| if ($optInOffsetOnReverse != 0.0) { | |
| $sar += $sar * $optInOffsetOnReverse; | |
| } | |
| $outReal[$outIdx++] = -$sar; | |
| $afShort = $optInAccelerationInitShort; | |
| $ep = $newLow; | |
| $sar = $sar + $afShort * ($ep - $sar); | |
| if ($sar < $prevHigh) { | |
| $sar = $prevHigh; | |
| } | |
| if ($sar < $newHigh) { | |
| $sar = $newHigh; | |
| } | |
| } else { | |
| $outReal[$outIdx++] = $sar; | |
| if ($newHigh > $ep) { | |
| $ep = $newHigh; | |
| $afLong += $optInAccelerationLong; | |
| if ($afLong > $optInAccelerationMaxLong) { | |
| $afLong = $optInAccelerationMaxLong; | |
| } | |
| } | |
| $sar = $sar + $afLong * ($ep - $sar); | |
| if ($sar > $prevLow) { | |
| $sar = $prevLow; | |
| } | |
| if ($sar > $newLow) { | |
| $sar = $newLow; | |
| } | |
| } | |
| } else { | |
| if ($newHigh >= $sar) { | |
| $isLong = 1; | |
| $sar = $ep; | |
| if ($sar > $prevLow) { | |
| $sar = $prevLow; | |
| } | |
| if ($sar > $newLow) { | |
| $sar = $newLow; | |
| } | |
| if ($optInOffsetOnReverse != 0.0) { | |
| $sar -= $sar * $optInOffsetOnReverse; | |
| } | |
| $outReal[$outIdx++] = $sar; | |
| $afLong = $optInAccelerationInitLong; | |
| $ep = $newHigh; | |
| $sar = $sar + $afLong * ($ep - $sar); | |
| if ($sar > $prevLow) { | |
| $sar = $prevLow; | |
| } | |
| if ($sar > $newLow) { | |
| $sar = $newLow; | |
| } | |
| } else { | |
| $outReal[$outIdx++] = -$sar; | |
| if ($newLow < $ep) { | |
| $ep = $newLow; | |
| $afShort += $optInAccelerationShort; | |
| if ($afShort > $optInAccelerationMaxShort) { | |
| $afShort = $optInAccelerationMaxShort; | |
| } | |
| } | |
| $sar = $sar + $afShort * ($ep - $sar); | |
| if ($sar < $prevHigh) { | |
| $sar = $prevHigh; | |
| } | |
| if ($sar < $newHigh) { | |
| $sar = $newHigh; | |
| } | |
| } | |
| } | |
| } | |
| $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 sma(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 = 30; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| return static::TA_INT_SMA( | |
| $startIdx, $endIdx, | |
| $inReal, $optInTimePeriod, | |
| $outBegIdx, $outNBElement, $outReal | |
| ); | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInTimePeriod | |
| * @param float $optInVFactor | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| public static function t3(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, float $optInVFactor, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 5; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| if ($optInVFactor == (-4e+37)) { | |
| $optInVFactor = 7.000000e-1; | |
| } elseif (($optInVFactor < 0.000000e+0) || ($optInVFactor > 1.000000e+0)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $lookbackTotal = 6 * ($optInTimePeriod - 1) + (static::$unstablePeriod[UnstablePeriodFunctionID::T3]); | |
| if ($startIdx <= $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outNBElement = 0; | |
| $outBegIdx = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outBegIdx = $startIdx; | |
| $today = $startIdx - $lookbackTotal; | |
| $k = 2.0 / ($optInTimePeriod + 1.0); | |
| $one_minus_k = 1.0 - $k; | |
| $tempReal = $inReal[$today++]; | |
| for ($i = $optInTimePeriod - 1; $i > 0; $i--) { | |
| $tempReal += $inReal[$today++]; | |
| } | |
| $e1 = $tempReal / $optInTimePeriod; | |
| $tempReal = $e1; | |
| for ($i = $optInTimePeriod - 1; $i > 0; $i--) { | |
| $e1 = ($k * $inReal[$today++]) + ($one_minus_k * $e1); | |
| $tempReal += $e1; | |
| } | |
| $e2 = $tempReal / $optInTimePeriod; | |
| $tempReal = $e2; | |
| for ($i = $optInTimePeriod - 1; $i > 0; $i--) { | |
| $e1 = ($k * $inReal[$today++]) + ($one_minus_k * $e1); | |
| $e2 = ($k * $e1) + ($one_minus_k * $e2); | |
| $tempReal += $e2; | |
| } | |
| $e3 = $tempReal / $optInTimePeriod; | |
| $tempReal = $e3; | |
| for ($i = $optInTimePeriod - 1; $i > 0; $i--) { | |
| $e1 = ($k * $inReal[$today++]) + ($one_minus_k * $e1); | |
| $e2 = ($k * $e1) + ($one_minus_k * $e2); | |
| $e3 = ($k * $e2) + ($one_minus_k * $e3); | |
| $tempReal += $e3; | |
| } | |
| $e4 = $tempReal / $optInTimePeriod; | |
| $tempReal = $e4; | |
| for ($i = $optInTimePeriod - 1; $i > 0; $i--) { | |
| $e1 = ($k * $inReal[$today++]) + ($one_minus_k * $e1); | |
| $e2 = ($k * $e1) + ($one_minus_k * $e2); | |
| $e3 = ($k * $e2) + ($one_minus_k * $e3); | |
| $e4 = ($k * $e3) + ($one_minus_k * $e4); | |
| $tempReal += $e4; | |
| } | |
| $e5 = $tempReal / $optInTimePeriod; | |
| $tempReal = $e5; | |
| for ($i = $optInTimePeriod - 1; $i > 0; $i--) { | |
| $e1 = ($k * $inReal[$today++]) + ($one_minus_k * $e1); | |
| $e2 = ($k * $e1) + ($one_minus_k * $e2); | |
| $e3 = ($k * $e2) + ($one_minus_k * $e3); | |
| $e4 = ($k * $e3) + ($one_minus_k * $e4); | |
| $e5 = ($k * $e4) + ($one_minus_k * $e5); | |
| $tempReal += $e5; | |
| } | |
| $e6 = $tempReal / $optInTimePeriod; | |
| while ($today <= $startIdx) { | |
| $e1 = ($k * $inReal[$today++]) + ($one_minus_k * $e1); | |
| $e2 = ($k * $e1) + ($one_minus_k * $e2); | |
| $e3 = ($k * $e2) + ($one_minus_k * $e3); | |
| $e4 = ($k * $e3) + ($one_minus_k * $e4); | |
| $e5 = ($k * $e4) + ($one_minus_k * $e5); | |
| $e6 = ($k * $e5) + ($one_minus_k * $e6); | |
| } | |
| $tempReal = $optInVFactor * $optInVFactor; | |
| $c1 = -($tempReal * $optInVFactor); | |
| $c2 = 3.0 * ($tempReal - $c1); | |
| $c3 = -6.0 * $tempReal - 3.0 * ($optInVFactor - $c1); | |
| $c4 = 1.0 + 3.0 * $optInVFactor - $c1 + 3.0 * $tempReal; | |
| $outIdx = 0; | |
| $outReal[$outIdx++] = $c1 * $e6 + $c2 * $e5 + $c3 * $e4 + $c4 * $e3; | |
| while ($today <= $endIdx) { | |
| $e1 = ($k * $inReal[$today++]) + ($one_minus_k * $e1); | |
| $e2 = ($k * $e1) + ($one_minus_k * $e2); | |
| $e3 = ($k * $e2) + ($one_minus_k * $e3); | |
| $e4 = ($k * $e3) + ($one_minus_k * $e4); | |
| $e5 = ($k * $e4) + ($one_minus_k * $e5); | |
| $e6 = ($k * $e5) + ($one_minus_k * $e6); | |
| $outReal[$outIdx++] = $c1 * $e6 + $c2 * $e5 + $c3 * $e4 + $c4 * $e3; | |
| } | |
| $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 tema(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| if ($RetCode = static::validateStartEndIndexes($startIdx, $endIdx)) { | |
| return $RetCode; | |
| } | |
| $firstEMABegIdx = 0; | |
| $firstEMANbElement = 0; | |
| $secondEMABegIdx = 0; | |
| $secondEMANbElement = 0; | |
| $thirdEMABegIdx = 0; | |
| $thirdEMANbElement = 0; | |
| if ((int)$optInTimePeriod == (PHP_INT_MIN)) { | |
| $optInTimePeriod = 30; | |
| } elseif (((int)$optInTimePeriod < 2) || ((int)$optInTimePeriod > 100000)) { | |
| return ReturnCode::BadParam; | |
| } | |
| $outNBElement = 0; | |
| $outBegIdx = 0; | |
| $lookbackEMA = Lookback::emaLookback($optInTimePeriod); | |
| $lookbackTotal = $lookbackEMA * 3; | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| return ReturnCode::Success; | |
| } | |
| $tempInt = $lookbackTotal + ($endIdx - $startIdx) + 1; | |
| $firstEMA = static::double($tempInt); | |
| $k = ((double)2.0 / ((double)($optInTimePeriod + 1))); | |
| $ReturnCode = static::TA_INT_EMA( | |
| $startIdx - ($lookbackEMA * 2), $endIdx, $inReal, | |
| $optInTimePeriod, $k, | |
| $firstEMABegIdx, $firstEMANbElement, | |
| $firstEMA | |
| ); | |
| if (($ReturnCode != ReturnCode::Success) || ($firstEMANbElement == 0)) { | |
| return $ReturnCode; | |
| } | |
| $secondEMA = static::double($firstEMANbElement); | |
| $ReturnCode = static::TA_INT_EMA( | |
| 0, $firstEMANbElement - 1, $firstEMA, | |
| $optInTimePeriod, $k, | |
| $secondEMABegIdx, $secondEMANbElement, | |
| $secondEMA | |
| ); | |
| if (($ReturnCode != ReturnCode::Success) || ($secondEMANbElement == 0)) { | |
| return $ReturnCode; | |
| } | |
| $ReturnCode = static::TA_INT_EMA( | |
| 0, $secondEMANbElement - 1, $secondEMA, | |
| $optInTimePeriod, $k, | |
| $thirdEMABegIdx, $thirdEMANbElement, | |
| $outReal | |
| ); | |
| if (($ReturnCode != ReturnCode::Success) || ($thirdEMANbElement == 0)) { | |
| return $ReturnCode; | |
| } | |
| $firstEMAIdx = $thirdEMABegIdx + $secondEMABegIdx; | |
| $secondEMAIdx = $thirdEMABegIdx; | |
| $outBegIdx = $firstEMAIdx + $firstEMABegIdx; | |
| $outIdx = 0; | |
| while ($outIdx < $thirdEMANbElement) { | |
| $outReal[$outIdx] += (3.0 * $firstEMA[$firstEMAIdx++]) - (3.0 * $secondEMA[$secondEMAIdx++]); | |
| $outIdx++; | |
| } | |
| $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 trima(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 = 30; | |
| } 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; | |
| } | |
| $outIdx = 0; | |
| if (($optInTimePeriod % 2) == 1) { | |
| $i = ($optInTimePeriod >> 1); | |
| $factor = ($i + 1) * ($i + 1); | |
| $factor = 1.0 / $factor; | |
| $trailingIdx = $startIdx - $lookbackTotal; | |
| $middleIdx = $trailingIdx + $i; | |
| $todayIdx = $middleIdx + $i; | |
| $numerator = 0.0; | |
| $numeratorSub = 0.0; | |
| for ($i = $middleIdx; $i >= $trailingIdx; $i--) { | |
| $tempReal = $inReal[$i]; | |
| $numeratorSub += $tempReal; | |
| $numerator += $numeratorSub; | |
| } | |
| $numeratorAdd = 0.0; | |
| $middleIdx++; | |
| for ($i = $middleIdx; $i <= $todayIdx; $i++) { | |
| $tempReal = $inReal[$i]; | |
| $numeratorAdd += $tempReal; | |
| $numerator += $numeratorAdd; | |
| } | |
| $outIdx = 0; | |
| $tempReal = $inReal[$trailingIdx++]; | |
| $outReal[$outIdx++] = $numerator * $factor; | |
| $todayIdx++; | |
| while ($todayIdx <= $endIdx) { | |
| $numerator -= $numeratorSub; | |
| $numeratorSub -= $tempReal; | |
| $tempReal = $inReal[$middleIdx++]; | |
| $numeratorSub += $tempReal; | |
| $numerator += $numeratorAdd; | |
| $numeratorAdd -= $tempReal; | |
| $tempReal = $inReal[$todayIdx++]; | |
| $numeratorAdd += $tempReal; | |
| $numerator += $tempReal; | |
| $tempReal = $inReal[$trailingIdx++]; | |
| $outReal[$outIdx++] = $numerator * $factor; | |
| } | |
| } else { | |
| $i = ($optInTimePeriod >> 1); | |
| $factor = $i * ($i + 1); | |
| $factor = 1.0 / $factor; | |
| $trailingIdx = $startIdx - $lookbackTotal; | |
| $middleIdx = $trailingIdx + $i - 1; | |
| $todayIdx = $middleIdx + $i; | |
| $numerator = 0.0; | |
| $numeratorSub = 0.0; | |
| for ($i = $middleIdx; $i >= $trailingIdx; $i--) { | |
| $tempReal = $inReal[$i]; | |
| $numeratorSub += $tempReal; | |
| $numerator += $numeratorSub; | |
| } | |
| $numeratorAdd = 0.0; | |
| $middleIdx++; | |
| for ($i = $middleIdx; $i <= $todayIdx; $i++) { | |
| $tempReal = $inReal[$i]; | |
| $numeratorAdd += $tempReal; | |
| $numerator += $numeratorAdd; | |
| } | |
| $outIdx = 0; | |
| $tempReal = $inReal[$trailingIdx++]; | |
| $outReal[$outIdx++] = $numerator * $factor; | |
| $todayIdx++; | |
| while ($todayIdx <= $endIdx) { | |
| $numerator -= $numeratorSub; | |
| $numeratorSub -= $tempReal; | |
| $tempReal = $inReal[$middleIdx++]; | |
| $numeratorSub += $tempReal; | |
| $numeratorAdd -= $tempReal; | |
| $numerator += $numeratorAdd; | |
| $tempReal = $inReal[$todayIdx++]; | |
| $numeratorAdd += $tempReal; | |
| $numerator += $tempReal; | |
| $tempReal = $inReal[$trailingIdx++]; | |
| $outReal[$outIdx++] = $numerator * $factor; | |
| } | |
| } | |
| $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 wma(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 = 30; | |
| } 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 == 1) { | |
| $outBegIdx = $startIdx; | |
| $outNBElement = $endIdx - $startIdx + 1; | |
| //System::arraycopy($inReal, $startIdx, $outReal, 0, (int)$outNBElement); | |
| $outReal = \array_slice($inReal, $startIdx, (int)$outNBElement); | |
| return ReturnCode::Success; | |
| } | |
| $divider = ($optInTimePeriod * ($optInTimePeriod + 1)) >> 1; | |
| $outIdx = 0; | |
| $trailingIdx = $startIdx - $lookbackTotal; | |
| $periodSum = $periodSub = (double)0.0; | |
| $inIdx = $trailingIdx; | |
| $i = 1; | |
| while ($inIdx < $startIdx) { | |
| $tempReal = $inReal[$inIdx++]; | |
| $periodSub += $tempReal; | |
| $periodSum += $tempReal * $i; | |
| $i++; | |
| } | |
| $trailingValue = 0.0; | |
| while ($inIdx <= $endIdx) { | |
| $tempReal = $inReal[$inIdx++]; | |
| $periodSub += $tempReal; | |
| $periodSub -= $trailingValue; | |
| $periodSum += $tempReal * $optInTimePeriod; | |
| $trailingValue = $inReal[$trailingIdx++]; | |
| $outReal[$outIdx++] = $periodSum / $divider; | |
| $periodSum -= $periodSub; | |
| } | |
| $outNBElement = $outIdx; | |
| $outBegIdx = $startIdx; | |
| return ReturnCode::Success; | |
| } | |
| } |