diff --git a/README.md b/README.md index a949d42..72acecb 100644 --- a/README.md +++ b/README.md @@ -25,21 +25,14 @@ $ema = new Romulodl\Ema(); $ema->calculate([10, 12, 14, 20, 14, 10, 11]); ``` -it also contains a static method: - -```php -Ema::calculateStatic([10, 12, 14, 20, 14, 10, 11]); -``` - #### What is `$previous_values` for? -The EMA calculation is based on the previous round of calculation. So the n round depends on n - 1 results. -Then what is n - 1 for the first calculation? If `$previous_values` is not available, it uses a simple moving average +The EMA calculation is based on the previous round of calculation. The `n` round depends on `n - 1` result. +Then what is `n - 1` for the first round? If `$previous_values` is not available, it uses a simple moving average for it. With `$previous_values` set, it will start the calculation of the EMA before and the result will be more -accurate (at least closest to what Trading view shows.) - +accurate (at least closest to what TradingView shows.) ## Why did you do this? The PECL Trading extension is crap and not everyone wants to install it. -I am building a trading bot and building more complex trading indicators that use EMA as a basic step. +I am building a trading bot and building more complex trading indicators that use the EMA as a basic step. diff --git a/src/Ema.php b/src/Ema.php index b4599e2..afa186b 100644 --- a/src/Ema.php +++ b/src/Ema.php @@ -4,18 +4,6 @@ class Ema { - private static $mult = null; - - public function calculate(array $values, array $previous_values = []) : float - { - return self::calculate_ema($values, $previous_values); - } - - public static function calculateStatic(array $values, array $previous_values = []): float - { - return self::calculate_ema($values, $previous_values); - } - /** * Calculate the EMA based on this formula * (Close - previous EMA) * (2 / n+1) + previous EMA @@ -23,31 +11,44 @@ public static function calculateStatic(array $values, array $previous_values = [ * The previous values options exists to try to smooth the current calculation * if it is empty, it will calculate the SMA for the first round. */ - private static function calculate_ema(array $values, array $previous_values = []) : float + public function calculate(array $values, array $previous_values = []) : float { if (empty($values)) { throw new \Exception('[' . __METHOD__ . '] $values parameters is empty'); } - self::$mult = self::$mult ?: 2 / (count($values) + 1); - $prev = false; + $mult = 2 / (count($values) + 1); + + return $this->calculate_ema($values, $mult, $previous_values); + } + + private function calculate_ema( + array $values, + float $mult, + array $previous_values = [], + $prev = false + ): float + { foreach ($values as $value) { if ( !is_numeric($value)) { throw new \Exception('[' . __METHOD__ . '] invalid value: '. $value); } if (!$prev) { - $prev = !empty($previous_values) ? self::calculate_ema($previous_values) : self::sma($values); + $prev = !empty($previous_values) ? + $this->calculate_ema($previous_values, $mult) : + $this->sma($values); + continue; } - $prev = ($value - $prev) * self::$mult + $prev; + $prev = ($value - $prev) * $mult + $prev; } - return $prev ?: 0; + return $prev; } - private static function sma(array $values) : float + private function sma(array $values) : float { return array_sum($values) / count($values); } diff --git a/tests/TestEma.php b/tests/TestEma.php index b40cc4a..de13a9b 100644 --- a/tests/TestEma.php +++ b/tests/TestEma.php @@ -23,7 +23,6 @@ public function testCalculateEmaWithEmptyPreviousValues(): void $ema = new Ema(); $this->assertSame(9288.86, round($ema->calculate($values), 2)); - $this->assertSame(9288.86, round(Ema::calculateStatic($values), 2)); } public function testCalculateEmaWithPreviousValues(): void @@ -56,7 +55,6 @@ public function testCalculateEmaWithPreviousValues(): void $ema = new Ema(); $this->assertSame(9197.01, round($ema->calculate($values, $previous_values), 2)); - $this->assertSame(9197.01, round(Ema::calculateStatic($values, $previous_values), 2)); } public function testCalculateEmaWithMorePreviousValues(): void @@ -92,7 +90,6 @@ public function testCalculateEmaWithMorePreviousValues(): void $ema = new Ema(); $this->assertSame(9182.18, round($ema->calculate($values, $previous_values), 2)); - $this->assertSame(9182.18, round(Ema::calculateStatic($values, $previous_values), 2)); } public function testCalculateEmaWithEmptyArray(): void @@ -101,13 +98,6 @@ public function testCalculateEmaWithEmptyArray(): void $ema = new Ema(); $ema->calculate([]); - Ema::calculateStatic([]); - } - - public function testCalculateStaticEmaWithEmptyArray(): void - { - $this->expectException(Exception::class); - Ema::calculateStatic([]); } public function testCalculateEmaWithInvalidArray(): void @@ -129,26 +119,5 @@ public function testCalculateEmaWithInvalidArray(): void $ema = new Ema(); $ema->calculate($values); - Ema::calculateStatic($values); - } - - public function testCalculateEmaStaticWithInvalidArray(): void - { - $values = [ - 9148.27, - 9995, - 9807.49, - 'hahah', - 8719.53, - 8561.09, - 8808.71, - 9305.91, - 9786.80, - 9310.73 - ]; - - $this->expectException(Exception::class); - - Ema::calculateStatic($values); } }