Skip to content

Commit

Permalink
bye static methods, you just make things more difficult
Browse files Browse the repository at this point in the history
  • Loading branch information
romulodl committed May 19, 2020
1 parent b922602 commit 1636dd1
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 61 deletions.
15 changes: 4 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
39 changes: 20 additions & 19 deletions src/Ema.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,51 @@

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
*
* 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);
}
Expand Down
31 changes: 0 additions & 31 deletions tests/TestEma.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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);
}
}

0 comments on commit 1636dd1

Please sign in to comment.