Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
22.22% |
2 / 9 |
CRAP | |
81.43% |
171 / 210 |
| LupeCode\phpTraderNative\TALib\Core\Core | |
0.00% |
0 / 1 |
|
22.22% |
2 / 9 |
72.68 | |
81.43% |
171 / 210 |
| construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
15 / 15 |
|||
| double | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| validateStartEndIndexes | |
0.00% |
0 / 1 |
5.02 | |
60.00% |
3 / 5 |
|||
| TA_INT_PO | |
0.00% |
0 / 1 |
11.10 | |
77.78% |
21 / 27 |
|||
| TA_INT_MACD | |
0.00% |
0 / 1 |
21.39 | |
69.49% |
41 / 59 |
|||
| TA_INT_EMA | |
0.00% |
0 / 1 |
7.60 | |
76.92% |
20 / 26 |
|||
| TA_INT_SMA | |
0.00% |
0 / 1 |
6.09 | |
86.36% |
19 / 22 |
|||
| TA_INT_stddev_using_precalc_ma | |
0.00% |
0 / 1 |
4 | |
95.45% |
21 / 22 |
|||
| TA_INT_VAR | |
0.00% |
0 / 1 |
6.03 | |
90.91% |
30 / 33 |
|||
| <?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\CandleSetting; | |
| use LupeCode\phpTraderNative\TALib\Enum\CandleSettingType; | |
| use LupeCode\phpTraderNative\TALib\Enum\Compatibility; | |
| use LupeCode\phpTraderNative\TALib\Enum\RangeType; | |
| use LupeCode\phpTraderNative\TALib\Enum\ReturnCode; | |
| use LupeCode\phpTraderNative\TALib\Enum\UnstablePeriodFunctionID; | |
| /** | |
| * Class Core | |
| * | |
| * @package LupeCode\phpTraderNative\TALib\Core | |
| */ | |
| class Core | |
| { | |
| /** @var int[] */ | |
| protected static $unstablePeriod; | |
| /** @var CandleSetting[] */ | |
| protected static $candleSettings; | |
| /** @var int */ | |
| public static $compatibility; | |
| /** | |
| * Core constructor. | |
| */ | |
| public static function construct() | |
| { | |
| static::$candleSettings = [ | |
| /* real body is long when it's longer than the average of the 10 previous candles' real body */ | |
| new CandleSetting(CandleSettingType::BodyLong, RangeType::RealBody, 10, 1.), | |
| /* real body is very long when it's longer than 3 times the average of the 10 previous candles' real body */ | |
| new CandleSetting(CandleSettingType::BodyVeryLong, RangeType::RealBody, 10, 3.), | |
| /* real body is short when it's shorter than the average of the 10 previous candles' real bodies */ | |
| new CandleSetting(CandleSettingType::BodyShort, RangeType::RealBody, 10, 1.), | |
| /* real body is like doji's body when it's shorter than 10% the average of the 10 previous candles' high-low range */ | |
| new CandleSetting(CandleSettingType::BodyDoji, RangeType::HighLow, 10, 0.1), | |
| /* shadow is long when it's longer than the real body */ | |
| new CandleSetting(CandleSettingType::ShadowLong, RangeType::RealBody, 0, 1.), | |
| /* shadow is very long when it's longer than 2 times the real body */ | |
| new CandleSetting(CandleSettingType::ShadowVeryLong, RangeType::RealBody, 0, 2.), | |
| /* shadow is short when it's shorter than half the average of the 10 previous candles' sum of shadows */ | |
| new CandleSetting(CandleSettingType::ShadowShort, RangeType::Shadows, 10, 1.), | |
| /* shadow is very short when it's shorter than 10% the average of the 10 previous candles' high-low range */ | |
| new CandleSetting(CandleSettingType::ShadowVeryShort, RangeType::HighLow, 10, 0.1), | |
| /* when measuring distance between parts of candles or width of gaps "near" means "<= 20% of the average of the 5 previous candles' high-low range" */ | |
| new CandleSetting(CandleSettingType::Near, RangeType::HighLow, 5, 0.2), | |
| /* when measuring distance between parts of candles or width of gaps "far" means ">= 60% of the average of the 5 previous candles' high-low range" */ | |
| new CandleSetting(CandleSettingType::Far, RangeType::HighLow, 5, 0.6), | |
| /* when measuring distance between parts of candles or width of gaps "equal" means "<= 5% of the average of the 5 previous candles' high-low range" */ | |
| new CandleSetting(CandleSettingType::Equal, RangeType::HighLow, 5, 0.05), | |
| ]; | |
| static::$unstablePeriod = \array_pad([], UnstablePeriodFunctionID::ALL, 0); | |
| static::$compatibility = Compatibility::Default; | |
| } | |
| /** | |
| * @param int $size | |
| * | |
| * @return array | |
| */ | |
| protected static function double(int $size) | |
| { | |
| return \array_pad([], $size, 0.); | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * | |
| * @return int | |
| */ | |
| protected static function validateStartEndIndexes(int $startIdx, int $endIdx) | |
| { | |
| if ($startIdx < 0) { | |
| return ReturnCode::OutOfRangeStartIndex; | |
| } | |
| if (($endIdx < 0) || ($endIdx < $startIdx)) { | |
| return ReturnCode::OutOfRangeEndIndex; | |
| } | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInFastPeriod | |
| * @param int $optInSlowPeriod | |
| * @param int $optInMethod_2 | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * @param array $tempBuffer | |
| * @param bool $doPercentageOutput | |
| * | |
| * @return int | |
| */ | |
| protected static function TA_INT_PO(int $startIdx, int $endIdx, array $inReal, int $optInFastPeriod, int $optInSlowPeriod, int $optInMethod_2, int &$outBegIdx, int &$outNBElement, array &$outReal, array &$tempBuffer, bool $doPercentageOutput): int | |
| { | |
| $outBegIdx1 = 0; | |
| $outNbElement1 = 0; | |
| $outBegIdx2 = 0; | |
| $outNbElement2 = 0; | |
| if ($optInSlowPeriod < $optInFastPeriod) { | |
| $tempInteger = $optInSlowPeriod; | |
| $optInSlowPeriod = $optInFastPeriod; | |
| $optInFastPeriod = $tempInteger; | |
| } | |
| $ReturnCode = OverlapStudies::movingAverage($startIdx, $endIdx, $inReal, $optInFastPeriod, $optInMethod_2, $outBegIdx2, $outNbElement2, $tempBuffer); | |
| if ($ReturnCode == ReturnCode::Success) { | |
| $ReturnCode = OverlapStudies::movingAverage($startIdx, $endIdx, $inReal, $optInSlowPeriod, $optInMethod_2, $outBegIdx1, $outNbElement1, $outReal); | |
| if ($ReturnCode == ReturnCode::Success) { | |
| $tempInteger = $outBegIdx1 - $outBegIdx2; | |
| if ($doPercentageOutput != 0) { | |
| for ($i = 0, $j = $tempInteger; $i < $outNbElement1; $i++, $j++) { | |
| $tempReal = $outReal[$i]; | |
| if (!(((-0.00000001) < $tempReal) && ($tempReal < 0.00000001))) { | |
| $outReal[$i] = (($tempBuffer[$j] - $tempReal) / $tempReal) * 100.0; | |
| } else { | |
| $outReal[$i] = 0.0; | |
| } | |
| } | |
| } else { | |
| for ($i = 0, $j = $tempInteger; $i < $outNbElement1; $i++, $j++) { | |
| $outReal[$i] = $tempBuffer[$j] - $outReal[$i]; | |
| } | |
| } | |
| $outBegIdx = $outBegIdx1; | |
| $outNBElement = $outNbElement1; | |
| } | |
| } | |
| if ($ReturnCode != ReturnCode::Success) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| } | |
| return $ReturnCode; | |
| } | |
| /** | |
| * @param int $startIdx | |
| * @param int $endIdx | |
| * @param array $inReal | |
| * @param int $optInFastPeriod | |
| * @param int $optInSlowPeriod | |
| * @param int $optInSignalPeriod_2 | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outMACD | |
| * @param array $outMACDSignal | |
| * @param array $outMACDHist | |
| * | |
| * @return int | |
| */ | |
| protected static function TA_INT_MACD(int $startIdx, int $endIdx, array $inReal, int $optInFastPeriod, int $optInSlowPeriod, int $optInSignalPeriod_2, int &$outBegIdx, int &$outNBElement, array &$outMACD, array &$outMACDSignal, array &$outMACDHist): int | |
| { | |
| //double[] $slowEMABuffer; | |
| //double[] $fastEMABuffer; | |
| //double $k1, $k2; | |
| //ReturnCode $ReturnCode; | |
| //int $tempInteger; | |
| $outBegIdx1 = 0; | |
| $outNbElement1 = 0; | |
| $outBegIdx2 = 0; | |
| $outNbElement2 = 0; | |
| //int $lookbackTotal, $lookbackSignal; | |
| //int $i; | |
| if ($optInSlowPeriod < $optInFastPeriod) { | |
| $tempInteger = $optInSlowPeriod; | |
| $optInSlowPeriod = $optInFastPeriod; | |
| $optInFastPeriod = $tempInteger; | |
| } | |
| if ($optInSlowPeriod != 0) { | |
| $k1 = ((double)2.0 / ((double)($optInSlowPeriod + 1))); | |
| } else { | |
| $optInSlowPeriod = 26; | |
| $k1 = (double)0.075; | |
| } | |
| if ($optInFastPeriod != 0) { | |
| $k2 = ((double)2.0 / ((double)($optInFastPeriod + 1))); | |
| } else { | |
| $optInFastPeriod = 12; | |
| $k2 = (double)0.15; | |
| } | |
| $lookbackSignal = Lookback::emaLookback($optInSignalPeriod_2); | |
| $lookbackTotal = $lookbackSignal; | |
| $lookbackTotal += Lookback::emaLookback($optInSlowPeriod); | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $tempInteger = ($endIdx - $startIdx) + 1 + $lookbackSignal; | |
| $fastEMABuffer = static::double($tempInteger); | |
| $slowEMABuffer = static::double($tempInteger); | |
| $tempInteger = $startIdx - $lookbackSignal; | |
| $ReturnCode = static::TA_INT_EMA($tempInteger, $endIdx, $inReal, $optInSlowPeriod, $k1, $outBegIdx1, $outNbElement1, $slowEMABuffer); | |
| if ($ReturnCode != ReturnCode::Success) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return $ReturnCode; | |
| } | |
| $ReturnCode = static::TA_INT_EMA($tempInteger, $endIdx, $inReal, $optInFastPeriod, $k2, $outBegIdx2, $outNbElement2, $fastEMABuffer); | |
| 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++) { | |
| $fastEMABuffer[$i] = $fastEMABuffer[$i] - $slowEMABuffer[$i]; | |
| } | |
| //System::arraycopy($fastEMABuffer, $lookbackSignal, $outMACD, 0, ($endIdx - $startIdx) + 1); | |
| $outMACD = \array_slice($fastEMABuffer, $lookbackSignal, ($endIdx - $startIdx) + 1); | |
| $ReturnCode = static::TA_INT_EMA(0, $outNbElement1 - 1, $fastEMABuffer, $optInSignalPeriod_2, ((double)2.0 / ((double)($optInSignalPeriod_2 + 1))), $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 $inReal | |
| * @param int $optInTimePeriod | |
| * @param float $optInK_1 | |
| * @param int $outBegIdx | |
| * @param int $outNBElement | |
| * @param array $outReal | |
| * | |
| * @return int | |
| */ | |
| protected static function TA_INT_EMA(int $startIdx, int $endIdx, $inReal, int $optInTimePeriod, float $optInK_1, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| //double $tempReal, $prevMA; | |
| //int $i, $today, $outIdx, $lookbackTotal; | |
| $lookbackTotal = Lookback::emaLookback($optInTimePeriod); | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $outBegIdx = $startIdx; | |
| if ((static::$compatibility) == Compatibility::Default) { | |
| $today = $startIdx - $lookbackTotal; | |
| $i = $optInTimePeriod; | |
| $tempReal = 0.0; | |
| while ($i-- > 0) { | |
| $tempReal += $inReal[$today++]; | |
| } | |
| $prevMA = $tempReal / $optInTimePeriod; | |
| } else { | |
| $prevMA = $inReal[0]; | |
| $today = 1; | |
| } | |
| while ($today <= $startIdx) { | |
| $prevMA = (($inReal[$today++] - $prevMA) * $optInK_1) + $prevMA; | |
| } | |
| $outReal[0] = $prevMA; | |
| $outIdx = 1; | |
| while ($today <= $endIdx) { | |
| $prevMA = (($inReal[$today++] - $prevMA) * $optInK_1) + $prevMA; | |
| $outReal[$outIdx++] = $prevMA; | |
| } | |
| $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 | |
| */ | |
| protected static function TA_INT_SMA(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| //double $periodTotal, $tempReal; | |
| //int $i, $outIdx, $trailingIdx, $lookbackTotal; | |
| $lookbackTotal = ($optInTimePeriod - 1); | |
| if ($startIdx < $lookbackTotal) { | |
| $startIdx = $lookbackTotal; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $periodTotal = 0; | |
| $trailingIdx = $startIdx - $lookbackTotal; | |
| $i = $trailingIdx; | |
| if ($optInTimePeriod > 1) { | |
| while ($i < $startIdx) { | |
| $periodTotal += $inReal[$i++]; | |
| } | |
| } | |
| $outIdx = 0; | |
| do { | |
| $periodTotal += $inReal[$i++]; | |
| $tempReal = $periodTotal; | |
| $periodTotal -= $inReal[$trailingIdx++]; | |
| $outReal[$outIdx++] = $tempReal / $optInTimePeriod; | |
| } while ($i <= $endIdx); | |
| $outNBElement = $outIdx; | |
| $outBegIdx = $startIdx; | |
| return ReturnCode::Success; | |
| } | |
| /** | |
| * @param array $inReal | |
| * @param array $inMovAvg | |
| * @param int $inMovAvgBegIdx | |
| * @param int $inMovAvgNbElement | |
| * @param int $timePeriod | |
| * @param array $output | |
| * | |
| * @return int | |
| */ | |
| protected static function TA_INT_stddev_using_precalc_ma(array $inReal, array &$inMovAvg, int $inMovAvgBegIdx, int $inMovAvgNbElement, int $timePeriod, array &$output): int | |
| { | |
| //double $tempReal, $periodTotal2, $meanValue2; | |
| //int $outIdx; | |
| //int $startSum, $endSum; | |
| $startSum = 1 + $inMovAvgBegIdx - $timePeriod; | |
| $endSum = $inMovAvgBegIdx; | |
| $periodTotal2 = 0; | |
| for ($outIdx = $startSum; $outIdx < $endSum; $outIdx++) { | |
| $tempReal = $inReal[$outIdx]; | |
| $tempReal *= $tempReal; | |
| $periodTotal2 += $tempReal; | |
| } | |
| for ($outIdx = 0; $outIdx < $inMovAvgNbElement; $outIdx++, $startSum++, $endSum++) { | |
| $tempReal = $inReal[$endSum]; | |
| $tempReal *= $tempReal; | |
| $periodTotal2 += $tempReal; | |
| $meanValue2 = $periodTotal2 / $timePeriod; | |
| $tempReal = $inReal[$startSum]; | |
| $tempReal *= $tempReal; | |
| $periodTotal2 -= $tempReal; | |
| $tempReal = $inMovAvg[$outIdx]; | |
| $tempReal *= $tempReal; | |
| $meanValue2 -= $tempReal; | |
| if (!($meanValue2 < 0.00000001)) { | |
| $output[$outIdx] = sqrt($meanValue2); | |
| } else { | |
| $output[$outIdx] = (double)0.0; | |
| } | |
| } | |
| 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 | |
| */ | |
| protected static function TA_INT_VAR(int $startIdx, int $endIdx, array $inReal, int $optInTimePeriod, int &$outBegIdx, int &$outNBElement, array &$outReal): int | |
| { | |
| //double $tempReal, $periodTotal1, $periodTotal2, $meanValue1, $meanValue2; | |
| //int $i, $outIdx, $trailingIdx, $nbInitialElementNeeded; | |
| $nbInitialElementNeeded = ($optInTimePeriod - 1); | |
| if ($startIdx < $nbInitialElementNeeded) { | |
| $startIdx = $nbInitialElementNeeded; | |
| } | |
| if ($startIdx > $endIdx) { | |
| $outBegIdx = 0; | |
| $outNBElement = 0; | |
| return ReturnCode::Success; | |
| } | |
| $periodTotal1 = 0; | |
| $periodTotal2 = 0; | |
| $trailingIdx = $startIdx - $nbInitialElementNeeded; | |
| $i = $trailingIdx; | |
| if ($optInTimePeriod > 1) { | |
| while ($i < $startIdx) { | |
| $tempReal = $inReal[$i++]; | |
| $periodTotal1 += $tempReal; | |
| $tempReal *= $tempReal; | |
| $periodTotal2 += $tempReal; | |
| } | |
| } | |
| $outIdx = 0; | |
| do { | |
| $tempReal = $inReal[$i++]; | |
| $periodTotal1 += $tempReal; | |
| $tempReal *= $tempReal; | |
| $periodTotal2 += $tempReal; | |
| $meanValue1 = $periodTotal1 / $optInTimePeriod; | |
| $meanValue2 = $periodTotal2 / $optInTimePeriod; | |
| $tempReal = $inReal[$trailingIdx++]; | |
| $periodTotal1 -= $tempReal; | |
| $tempReal *= $tempReal; | |
| $periodTotal2 -= $tempReal; | |
| $outReal[$outIdx++] = $meanValue2 - $meanValue1 * $meanValue1; | |
| } while ($i <= $endIdx); | |
| $outNBElement = $outIdx; | |
| $outBegIdx = $startIdx; | |
| return ReturnCode::Success; | |
| } | |
| } |