diff --git a/README.md b/README.md index 72acecb..97056be 100644 --- a/README.md +++ b/README.md @@ -16,22 +16,15 @@ or add `romulodl/ema` to your `composer.json`. Please check the latest version i ```php $ema = new Romulodl\Ema(); -$ema->calculate(array $values, array $previous_values = []); +$ema->calculate(array $values, int $period = 9); ``` For example: ```php $ema = new Romulodl\Ema(); -$ema->calculate([10, 12, 14, 20, 14, 10, 11]); +$ema->calculate([10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]); ``` -#### What is `$previous_values` for? - -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 TradingView shows.) - ## Why did you do this? The PECL Trading extension is crap and not everyone wants to install it. diff --git a/src/Ema.php b/src/Ema.php index afa186b..37d9784 100644 --- a/src/Ema.php +++ b/src/Ema.php @@ -11,46 +11,31 @@ class Ema * 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. */ - public function calculate(array $values, array $previous_values = []) : float + public function calculate(array $values, int $period = 9) : float { - if (empty($values)) { + if (empty($values) || count($values) < $period) { throw new \Exception('[' . __METHOD__ . '] $values parameters is empty'); } - $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 - { + $mult = 2 / ($period + 1); + $prev_close = []; + $prev_ema = false; foreach ($values as $value) { if ( !is_numeric($value)) { throw new \Exception('[' . __METHOD__ . '] invalid value: '. $value); } - if (!$prev) { - $prev = !empty($previous_values) ? - $this->calculate_ema($previous_values, $mult) : - $this->sma($values); - + if (count($prev_close) < $period) { + $prev_close[] = $value; + if (count($prev_close) === $period) { + $prev_ema = array_sum($prev_close) / $period; + } continue; } - $prev = ($value - $prev) * $mult + $prev; + $prev_ema = ($value - $prev_ema) * $mult + $prev_ema; } - return $prev; + return $prev_ema; } - - private function sma(array $values) : float - { - return array_sum($values) / count($values); - } - } diff --git a/tests/TestEma.php b/tests/TestEma.php index de13a9b..becd51f 100644 --- a/tests/TestEma.php +++ b/tests/TestEma.php @@ -8,88 +8,27 @@ final class EmaTest extends TestCase { public function testCalculateEmaWithEmptyPreviousValues(): void { - $values = [ - 9148.27, - 9995, - 9807.49, - 9550.67, - 8719.53, - 8561.09, - 8808.71, - 9305.91, - 9786.80, - 9310.73 - ]; + $val = require(__DIR__ . '/values.php'); + $values = []; + foreach ($val as $v) { + $values[] = $v[2]; + } + $values = array_slice($values, -9); $ema = new Ema(); - $this->assertSame(9288.86, round($ema->calculate($values), 2)); - } - - public function testCalculateEmaWithPreviousValues(): void - { - $previous_values = [ - 7694.17, - 7774, - 7735.75, - 8784.20, - 8624.76, - 8830.52, - 8975.18, - 8900, - 8873.98, - 9022.78 - ]; - - $values = [ - 9148.27, - 9995, - 9807.49, - 9550.67, - 8719.53, - 8561.09, - 8808.71, - 9305.91, - 9786.80, - 9310.73 - ]; - - $ema = new Ema(); - $this->assertSame(9197.01, round($ema->calculate($values, $previous_values), 2)); + $this->assertSame(9147.33, round($ema->calculate($values), 2)); } public function testCalculateEmaWithMorePreviousValues(): void { - $previous_values = [ - 7483.35, - 7504.11, - 7534.01, - 7694.17, - 7774, - 7735.75, - 8784.20, - 8624.76, - 8830.52, - 8975.18, - 8900, - 8873.98, - 9022.78 - ]; - - $values = [ - 9148.27, - 9995, - 9807.49, - 9550.67, - 8719.53, - 8561.09, - 8808.71, - 9305.91, - 9786.80, - 9310.73 - ]; + $val = require(__DIR__ . '/values.php'); + $values = []; + foreach ($val as $v) { + $values[] = $v[2]; + } $ema = new Ema(); - $this->assertSame(9182.18, round($ema->calculate($values, $previous_values), 2)); + $this->assertSame(9101.36, round($ema->calculate($values), 2)); } public function testCalculateEmaWithEmptyArray(): void @@ -112,7 +51,6 @@ public function testCalculateEmaWithInvalidArray(): void 8808.71, 9305.91, 9786.80, - 9310.73 ]; $this->expectException(Exception::class); diff --git a/tests/values.php b/tests/values.php new file mode 100644 index 0000000..62d060d --- /dev/null +++ b/tests/values.php @@ -0,0 +1,267 @@ +