Skip to content

### Feature Request: Add Optional Zero-Padding for Indicator Outputs #11

Description

@rafaelpeter03

Description

When using technical indicators like macd and rsi from the TraderService class, the output arrays start at different indices depending on their periods (e.g., MACD with (12, 26, 9) starts at index 33, RSI with (14) starts at index 13). This makes it challenging to align the results with the original input array ($real) for consistent visualization, especially when combining multiple indicators in tools like ECharts or Plotly.

I propose adding an optional parameter to pad the indicator outputs with zeros or null at the start, aligning them with the length of the input array. This would simplify usage and improve consistency without requiring external post-processing.

Proposed Solution

Add a $padWithZeros parameter to methods like macd and rsi, defaulting to false for backward compatibility. When true, the function would automatically prepend zeros to match the length of $real.

Example implementation for macd:

/**
 * Moving Average Convergence/Divergence.
 *
 * @param array<int, mixed> $real         Array of real values.
 * @param integer           $fastPeriod   Number of period for the fast MA. Valid range from 2 to 100000.
 * @param integer           $slowPeriod   Number of period for the slow MA. Valid range from 2 to 100000.
 * @param integer           $signalPeriod Smoothing for the signal line (nb of period). Valid range from 1 to 100000.
 * @param bool              $padWithZeros Whether to pad the result with zeros to match the input length.
 * @return array<int, mixed> Returns an array with calculated data.
 */
public function macd(
    array $real,
    int $fastPeriod = 12,
    int $slowPeriod = 26,
    int $signalPeriod = 9,
    bool $padWithZeros = false
): array {
    $result = trader_macd($real, $fastPeriod, $slowPeriod, $signalPeriod);
    $this->handleErrors();

    if ($padWithZeros) {
        $startPeriod = $slowPeriod + $signalPeriod - 1; // e.g., 34 for (12, 26, 9)
        $totalLength = count($real);
        $paddedResult = [];
        foreach ($result as $key => $subArray) {
            $values = array_values($subArray);
            $zerosToAdd = $totalLength - count($values);
            $paddedValues = array_merge(array_fill(0, $zerosToAdd, 0), $values);
            $paddedResult[$key] = array_combine(range(0, $totalLength - 1), $paddedValues);
        }
        return $paddedResult;
    }

    return $result;
}

Alternative Approach

If modifying each indicator method is too intrusive, consider adding a standalone utility method to TraderService, like padIndicatorWithZeros, that works with any indicator output:

/**
 * Pads an indicator's output with zeros to match the input array length.
 *
 * @param array $indicator   The indicator result (single or multi-array)
 * @param array $inputValues The original input values
 * @return array The padded indicator
 */
public function padIndicatorWithZeros(array $indicator, array $inputValues): array {
    $totalLength = count($inputValues);
    $paddedIndicator = [];
    $isSingleArray = !is_array(reset($indicator));
    $arraysToPad = $isSingleArray ? [$indicator] : $indicator;

    foreach ($arraysToPad as $key => $subArray) {
        $values = array_values($subArray);
        $zerosToAdd = $totalLength - count($values);
        $paddedValues = array_merge(array_fill(0, $zerosToAdd, 0), $values); // or null
        $paddedIndicator[$key] = array_combine(range(0, $totalLength - 1), $paddedValues);
    }

    return $isSingleArray ? $paddedIndicator[0] : $paddedIndicator;
}

Usage:

$macd = $index->macd($values);
$macdPadded = $index->padIndicatorWithZeros($macd, $values);

$rsi = $index->rsi($values);
$rsiPadded = $index->padIndicatorWithZeros($rsi, $values);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions