Mohit Tanwani
Mohit Tanwani

Reputation: 6628

Exponential Moving Average in php

I want to calculate the EMA (Exponential Moving Average) value in PHP.

I've tried with following code but it's giving me 500 error.

$real = array(12,15,17,19,21,25,28,12,15,16);
$timePeriod = 3;
$data = trader_ema($real,$timePeriod);
var_dump($data);

PHP: EMA calculation function trader-ema

Tried with long time Googling but not getting any help on this in PHP. So, I've no clue what needs to be done to calculate the EMA value.

Edit-1: Installed extensions

I've installed all the necessary extensions, Now I am getting the output. But it doesn't seems giving proper output.

I think PHP function for calculating EMA is not working properly. Any help in this would be greatly appreciated.

Upvotes: 3

Views: 6036

Answers (2)

quickshiftin
quickshiftin

Reputation: 69681

The trader extension for PHP actually looks quite promising. The underlying code looks very mature, and I notice at the time of writing the latest stable PHP module (0.5.1) was released at the first of this year with support for PHP8.

It may take some reading of the documentation, for example the note around trader_set_unstable_period, and god-forbid, the trader source code to become proficient.

If I do a quick installation of the trader module in a PHP Docker container

apt-get update
pecl install trader
docker-php-ext-enable trader

using the article from here as a benchmark

ema-benchmark-numbers

and put together a simple test script comparing the function supplied by @Tryke and trader_ema

function exponentialMovingAverage(array $numbers, int $n): array
{
     $m   = count($numbers);
     $α   = 2 / ($n + 1);
     $EMA = [];

     // Start off by seeding with the first data point
     $EMA[] = $numbers[0];

     // Each day after: EMAtoday = α⋅xtoday + (1-α)EMAyesterday
     for ($i = 1; $i < $m; $i++) {
        $EMA[] = ($α * $numbers[$i]) + ((1 - $α) * $EMA[$i - 1]);
     }

     return $EMA;
}

function merge_results($input, $avgs) {
    $results = [];
    $empty = count($input) - count($avgs);
    foreach($input as $i => $price) {
        $results[] = $i < $empty ? [$price, null] : [$price, round($avgs[$i], 2)];
    }
    return $results;
}

$real = [
    22.27,
    22.19,
    22.08,
    22.17,
    22.18,
    22.13,
    22.23,
    22.43,
    22.24,
    22.29,
    22.15,
    22.39,
    22.38,
    22.61,
    23.36,
    24.05,
    23.75,
    23.83,
    23.95,
    23.63,
    23.82,
    23.87,
    23.65,
    23.19,
    23.10,
    23.33,
    22.68,
    23.10,
    22.40,
    22.17
];

$timePeriod = 10;
$traderData = trader_ema($real,$timePeriod);
echo "trader ema\n";
var_dump(merge_results($real, $traderData));


$phpData = exponentialMovingAverage($real, 3);
echo "\n\nphp ema\n";
var_dump(merge_results($real, $phpData));

The results of the trader_ema match exactly. The results from Tryke's function do not. It seems to have results starting on the first day, whereas my expectation (and the output of the trader_ema and benchmark numbers reflect) is that there are no results until the $timePeriod has elapsed. See this note from the Investopedia article on EMA

Calculating the EMA requires one more observation than the SMA. Suppose that you want to use 20 days as the number of observations for the EMA. Then, you must wait until the 20th day to obtain the SMA. On the 21st day, you can then use the SMA from the previous day as the first EMA for yesterday.

Upvotes: 1

Tryke
Tryke

Reputation: 69

I recommend to use the math library from: https://github.com/markrogoyski/math-php

public static function exponentialMovingAverage(array $numbers, int $n): array
{
     $m   = count($numbers);
     $α   = 2 / ($n + 1);
     $EMA = [];

     // Start off by seeding with the first data point
     $EMA[] = $numbers[0];

     // Each day after: EMAtoday = α⋅xtoday + (1-α)EMAyesterday
     for ($i = 1; $i < $m; $i++) {
        $EMA[] = ($α * $numbers[$i]) + ((1 - $α) * $EMA[$i - 1]);
     }

     return $EMA;
}

Upvotes: 6

Related Questions