PHP code example of opencck / amphp-kalman

1. Go to this page and download the library: Download opencck/amphp-kalman library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

opencck / amphp-kalman example snippets


use OpenCCK\Kalman\Domain\Entity\FilterConfig;
use OpenCCK\Kalman\Domain\Entity\GatingPolicy;
use OpenCCK\Kalman\Domain\Entity\Measurement;
use OpenCCK\Kalman\Domain\Model\Finance\LocalLinearTrend;

// σ_a: velocity-noise intensity (price units / s^1.5), half spread, tick size → R
$llt = new LocalLinearTrend(sigmaA: 0.5, halfSpread: 0.05, tick: 0.01);
$filter = $llt->filter(firstPrice: 100.0, config: FilterConfig::default()->withGating(GatingPolicy::chiSquare(0.001)));

foreach ($ticks as [$exchangeTimestampNs, $price]) {
    $result = $filter->step(Measurement::at($exchangeTimestampNs, [0 => $price]));   // predict(dt) + correct, atomic
    // $result->outcomes[0]->innovation, ->nis(); $result->logLikelihood
}

$fair = $filter->meanAt(0);                 // filtered price
$trend = LocalLinearTrend::trendScore($filter);   // v̂ / √P_vv

use OpenCCK\Kalman\Domain\Model\Finance\EtfBasket;

$etf = new EtfBasket(
    weights: [0.5, 0.3, 0.2],
    sigma: [4e-6, 1e-6, 5e-7,  1e-6, 3e-6, 2e-7,  5e-7, 2e-7, 2e-6],   // k×k return covariance per second
    sigmaA: 0.002,                        // velocity noise of the constituents
    premiumTheta: 0.05, premiumSigma: 0.01,   // OU premium of the fund over its NAV
    quoteVariances: [1e-4, 2e-4, 3e-4],   // r_i for the constituent quotes
    etfVariance: 5e-5,                    // r for the fund quote
);
$filter = $etf->filter(firstPrices: [100.0, 50.0, 20.0]);

// channels 0..k-1 are the constituents, channel k the fund; any subset per measurement is fine
$filter->step(Measurement::at($ts, [0 => 100.02, 3 => 71.9]));
$nav = $etf->nav($filter);   // Σ wᵢ p̂ᵢ

use OpenCCK\Kalman\Domain\Entity\FilterForm;
use OpenCCK\Kalman\Domain\Model\Finance\PairsHedge;

$pair = new PairsHedge(qAlpha: 1e-6, qBeta: 1e-5, sigmaEps: 0.02);   // y = α + β·x + ε
$filter = $pair->filter(alpha0: 0.0, beta0: 1.2, config: FilterConfig::default()->withForm(FilterForm::UD));

foreach ($ticks as [$ts, $y, $x]) {
    $raw = $pair->tick($ts, $y, $x);        // ['ts', 'values', 'rows'] — the observation row depends on x
    $filter->step(Measurement::at($raw['ts'], $raw['values']));
}
$z = PairsHedge::zScore($filter);          // standardised spread, the trading signal

use Amp\Pipeline\Queue;
use OpenCCK\Kalman\Infrastructure\Async\FilterSession;
use OpenCCK\Kalman\Infrastructure\Async\MeasurementBatcher;
use OpenCCK\Kalman\Infrastructure\Async\ReorderBuffer;
use OpenCCK\Kalman\Infrastructure\Ingest\IngestOrchestrator;
use OpenCCK\Kalman\Infrastructure\Ingest\WebsocketFeed;
use function Amp\async;

$feeds = [new WebsocketFeed($urlA, $decoderA), new WebsocketFeed($urlB, $decoderB)];
$handle = (new IngestOrchestrator($feeds))->start();          // Queue<Measurement> with back-pressure + stop()

$inbox = new Queue(1024);
$snapshots = new Queue(16);
$session = new FilterSession($filter, $inbox, $snapshots, snapshotEvery: 100);
$final = $session->start();                                   // owner fiber; Future<StateSnapshot>

async(static function () use ($handle, $inbox): void {
    $ordered = (new ReorderBuffer(windowNs: 2_000_000))->apply($handle->queue->iterate());   // exchange-time order inside a 2 ms window
    (new MeasurementBatcher(256))->pump($ordered, $inbox);    // arrays of ticks per queue item: loop overhead → 0
    $inbox->complete();
});
foreach ($snapshots->iterate() as $snapshot) {                // broadcast / persist
    // ...
}

use OpenCCK\Kalman\App\Calibration\Calibrator;
use OpenCCK\Kalman\App\Calibration\Parametrization;

$param = new Parametrization(['motion.sigmaA' => 'log', 'observation.variances.0' => 'log']);
$best = (new Calibrator($param))->calibrate($modelConfig, filterConfig: null, ticks: $history);
// $best['config'] — the model config at the innovation-likelihood maximum (Nelder–Mead)

use OpenCCK\Kalman\Domain\Metric\Momentum\Rsi;
use OpenCCK\Kalman\Domain\Metric\Liquidity\LiquidityDensity;
use OpenCCK\Kalman\Domain\Metric\Filtered\Derivative;

$rsi = new Rsi(period: 14);                       // Wilder's RMA, the canonical definition
foreach ($closes as $close) {
    $rsi->updatePrice($timestampNs, $close);
}
$rsi->value();                                     // 0-100, NAN until warmed up

$series = Rsi::wilder($closes, 14);                // the same definition, whole history at once

$density = LiquidityDensity::within(               // size resting within 10 bps of the mid
    $book->bidPrices, $book->bidSizes, $book->askPrices, $book->askSizes, bandBps: 10.0,
);

$rate = Derivative::ofSeries($timestamps, $series);   // d(RSI)/dt, with its own uncertainty
$rate['rate'][-1];                                    // the slope, per second
$rate['tStat'][-1];                                   // above 2 means it is real, not noise
ini
opcache.enable_cli=1        ; for CLI workers and backtests
opcache.jit=1255
opcache.jit_buffer_size=128M