<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Market analysis using Kalman Paris]]></title><description><![CDATA[Market analysis using Kalman Paris]]></description><link>https://market-analysis-using-kalman-paris.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sun, 21 Jun 2026 02:37:18 GMT</lastBuildDate><atom:link href="https://market-analysis-using-kalman-paris.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Market Analysis using Kalman Paris]]></title><description><![CDATA[From Noisy Songs to Stock Profits: How I Taught My Computer to “Hear” the Market
Turning signal processing math into a market-neutral trading bot using Cointegration, Kalman Filters, and Mean Reversion
Introduction
Ever tried listening to your favori...]]></description><link>https://market-analysis-using-kalman-paris.hashnode.dev/market-analysis-using-kalman-paris</link><guid isPermaLink="true">https://market-analysis-using-kalman-paris.hashnode.dev/market-analysis-using-kalman-paris</guid><category><![CDATA[ML]]></category><category><![CDATA[trading, ]]></category><category><![CDATA[quantum computing]]></category><category><![CDATA[AI]]></category><category><![CDATA[finance]]></category><category><![CDATA[Kalman Filter]]></category><dc:creator><![CDATA[Aritra Hui]]></dc:creator><pubDate>Mon, 09 Feb 2026 17:54:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1770654063069/c2a5fe91-62a3-4f68-8049-d8bd9bca18ee.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-from-noisy-songs-to-stock-profits-how-i-taught-my-computer-to-hear-the-market">From Noisy Songs to Stock Profits: How I Taught My Computer to “Hear” the Market</h2>
<p><em>Turning signal processing math into a market-neutral trading bot using Cointegration, Kalman Filters, and Mean Reversion</em></p>
<h2 id="heading-introduction">Introduction</h2>
<p>Ever tried listening to your favorite song while someone is vacuuming right next to you? You can still catch the melody. Your brain filters out the noise and focus on what matters. That idea became the foundation of this project. In my previous post on <strong>MFCCs</strong>, I explored how computers extract human voice signals from noisy audio. But while looking at a <strong>stock price</strong> chart one night, something clicked in my mind</p>
<h2 id="heading-the-wait-what-moment"><strong>The "Wait, What?" Moment</strong></h2>
<p><strong><em>Price charts look exactly like sound waves.</em></strong></p>
<p>Random spikes. Hidden patterns. Underlying rhythm buried in chaos.</p>
<p>So, <strong>What if we treated financial data like audio signals?</strong></p>
<p>Filter the noise, extract the structure and then trade the pattern.</p>
<p>This blog walks through the full system I built from theory to Python implementation.</p>
<h2 id="heading-signal-processing-audio-vs-finance">Signal Processing: Audio vs Finance</h2>
<p>At their core, both domains deal with signals over time.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770653250658/43c31757-0847-40e7-beb3-d1daf0e6fbe7.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-plaintext">AUDIO SIGNAL PROCESSING        FINANCIAL SIGNAL PROCESSING
-----------------------        ---------------------------
Raw sound waves                Raw price data
Noise filtering                Market noise filtering
Feature extraction             Spread extraction
Voice detection                Trading signals
</code></pre>
<p>Same mathematics but different application.</p>
<h2 id="heading-step-1-cointegration-the-drunk-guy-and-his-dog">Step 1 — Cointegration: The Drunk Guy and His Dog</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770664209983/a5a83702-d399-4e1f-95d1-d1d7368b19d4.png" alt class="image--center mx-auto" /></p>
<p>Imagine:</p>
<ul>
<li><p>A drunk guy stumbling home</p>
</li>
<li><p>His dog running around</p>
</li>
<li><p>Both connected by a leash</p>
</li>
</ul>
<p><strong>Individually</strong> → random movement<br /><strong>Together</strong> → constrained distance</p>
<p>That leash is <strong>cointegration</strong>.</p>
<p>In markets, some assets move together long-term because of economic linkage.</p>
<p>Examples:</p>
<ul>
<li><p>Gold ↔ Silver</p>
</li>
<li><p>Coke ↔ Pepsi</p>
</li>
<li><p>Bitcoin ↔ Ethereum</p>
</li>
</ul>
<p><strong><em>We don't bet on where Gold is going.<br />We bet on the leash stretching too far and snapping back.</em></strong></p>
<p>We trade <strong>distance between them</strong>.</p>
<p>When the leash stretches too far → we bet on snap back.</p>
<h2 id="heading-step-2-mean-reversion-the-rubber-band-model">Step 2 — Mean Reversion: The Rubber Band Model</h2>
<p>Normal stock prices behave like balloons — they drift.</p>
<p>But spreads between cointegrated assets behave like rubber bands.</p>
<p>They revert to a long-term average.</p>
<p>This behavior is modeled by the <strong>Ornstein-Uhlenbeck Process</strong>.</p>
<h3 id="heading-key-parameters">Key Parameters</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Dial</strong></td><td><strong>What It Means</strong></td><td><strong>Real-World Analogy</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>θ (theta)</strong> : Mean Reversion Speed</td><td>How fast the rubber band snaps back</td><td>Tight rubber band = fast snap. Loose = slow</td></tr>
<tr>
<td><strong>μ (mu)</strong> : Long-Term Mean</td><td>Where the ball "wants" to be</td><td>The resting point. Home base</td></tr>
<tr>
<td><strong>σ (sigma)</strong> : Volatility</td><td>How wildly it bounces around</td><td>Calm day = small bounces. Crazy day = wild shaking</td></tr>
</tbody>
</table>
</div><p><strong>High θ?</strong> The spread snaps back quickly → More trading opportunities → More profit.<br /><strong>High σ?</strong> Lots of bouncing → Noisier signal → Harder to trade.</p>
<p>This technique measures these dials in real-time and decides is this rubber band stretched enough to bet on?</p>
<h2 id="heading-step-3-z-score-the-stretch-meter">Step 3 — Z-Score: The Stretch Meter</h2>
<p>We need a way to measure how “abnormal” the spread is.</p>
<p>That’s where Z-Score comes in.</p>
<p>Interpretation:</p>
<pre><code class="lang-plaintext">   THE Z-SCORE THERMOMETER

    +3.0  ┃  🔴 EXTREMELY EXPENSIVE (rare!)
    +2.0  ┃  🔴 Very expensive
    +1.5  ┃  🟡 ──── SELL SIGNAL ──── ←── Robot screams "SELL!"
    +1.0  ┃  
     0.0  ┃  🟢 Normal. Chill. Do nothing.
    -1.0  ┃  
    -1.5  ┃  🟡 ──── BUY SIGNAL ──── ←── Robot screams "BUY!"
    -2.0  ┃  🔵 Very cheap
    -3.0  ┃  🔵 EXTREMELY CHEAP (rare!)
</code></pre>
<ul>
<li><p><strong>Z-Score near 0:</strong> The leash is relaxed. Nothing interesting. Go get coffee.</p>
</li>
<li><p><strong>Z-Score hits +1.5:</strong> Gold is WAY too expensive relative to Silver. <strong>SELL GOLD.</strong></p>
</li>
<li><p><strong>Z-Score hits -1.5:</strong> Gold is WAY too cheap relative to Silver. <strong>BUY GOLD.</strong></p>
</li>
<li><p><strong>Z-Score comes back to 0:</strong> Close the trade. Pocket the difference.</p>
</li>
</ul>
<h2 id="heading-step-4-the-robots-brain-that-learns-kalman-filter"><strong>Step 4: The Robot's Brain That <em>Learns</em> (Kalman Filter)</strong></h2>
<p>Here's where most trading bots mess up.</p>
<p>Old-school bots calculate the relationship between Gold and Silver ONCE and assume it never changes. Like measuring your shoe size at age 5 and buying the same shoes forever.</p>
<p><strong>Spoiler: your feet grow. Markets change.</strong></p>
<p>Sometimes Gold and Silver move in lockstep. Sometimes a financial crisis hits and they stop caring about each other entirely. The "leash length" (called <strong>beta</strong>, or <strong>β</strong>) is constantly shifting.</p>
<ul>
<li><p>Predicts current relationship</p>
</li>
<li><p>Compares with new data</p>
</li>
<li><p>Measures error</p>
</li>
<li><p>Updates belief</p>
</li>
</ul>
<h2 id="heading-step-5-full-trading-pipeline">Step 5 — Full Trading Pipeline</h2>
<pre><code class="lang-plaintext">Download prices
      ↓
Log transform
      ↓
Kalman Filter → dynamic β
      ↓
Compute spread
      ↓
Compute Z-Score
      ↓
Generate signals
      ↓
Execute trades
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770654945350/3a2cd0cc-54cb-4c59-b47f-3a88888e1d90.jpeg" alt class="image--center mx-auto" /></p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Auto-Tune</strong></td><td><strong>Kalman Filter</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Listens to the singer's voice</td><td>Listens to market prices</td></tr>
<tr>
<td>Detects if the pitch is off</td><td>Detects if β has changed</td></tr>
<tr>
<td>Adjusts pitch in real-time</td><td>Adjusts β in real-time</td></tr>
<tr>
<td>Singer sounds perfect</td><td>Robot trades perfectly</td></tr>
</tbody>
</table>
</div><h3 id="heading-kalman-filter">Kalman Filter</h3>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run_kalman_filter</span>(<span class="hljs-params">x, y</span>):</span>
    n = len(x)
    delta = <span class="hljs-number">0.0001</span>
    Vw = delta / (<span class="hljs-number">1</span> - delta) * np.eye(<span class="hljs-number">2</span>)
    Ve = <span class="hljs-number">0.001</span>

    theta = np.zeros((<span class="hljs-number">2</span>, n))
    P = np.zeros((<span class="hljs-number">2</span>, <span class="hljs-number">2</span>, n))
    theta[:, <span class="hljs-number">0</span>] = [<span class="hljs-number">0</span>, <span class="hljs-number">0</span>]
    P[:, :, <span class="hljs-number">0</span>] = np.eye(<span class="hljs-number">2</span>) * <span class="hljs-number">1000</span>

    <span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, n):
        theta_pred = theta[:, t<span class="hljs-number">-1</span>]
        R = P[:, :, t<span class="hljs-number">-1</span>] + Vw

        H = np.array([x.iloc[t], <span class="hljs-number">1.0</span>])
        y_pred = np.dot(H, theta_pred)
        error = y.iloc[t] - y_pred

        Q = np.dot(np.dot(H, R), H.T) + Ve
        K = np.dot(R, H.T) / Q
        theta[:, t] = theta_pred + K * error
        P[:, :, t] = R - np.outer(K * Q, K)

    <span class="hljs-keyword">return</span> theta

state = run_kalman_filter(x, y)
dynamic_beta = state[<span class="hljs-number">0</span>, :]
</code></pre>
<p>Typical observations:</p>
<ul>
<li><p>Assets move together → cointegration confirmed</p>
</li>
<li><p>β changes over time → Kalman adapts</p>
</li>
<li><p>Z-Score oscillates → mean reversion visible</p>
</li>
<li><p>Trades cluster at extremes</p>
</li>
<li><p>Equity curve trends upward in stable regimes</p>
</li>
</ul>
<p>This is a <strong>market-neutral strategy</strong>.</p>
<h2 id="heading-mathematical-foundation">Mathematical Foundation</h2>
<p><strong>Ornstein-Uhlenbeck SDE:</strong> is a stochastic, continuous-time process that models mean-reverting behavior, where a variable tends to drift towards a long-term mean over time.</p>
<p><code>dS = θ(μ − S)dt + σdW</code></p>
<p>Where:</p>
<ul>
<li><p>S → Spread</p>
</li>
<li><p>θ → Reversion speed</p>
</li>
<li><p>μ → Mean</p>
</li>
<li><p>σ → Volatility</p>
</li>
<li><p>dW → Brownian noise</p>
</li>
</ul>
<p>Rubber band force vs random shocks.</p>
<p><strong>State-Space Model:</strong> A state-space model in finance is a powerful mathematical framework for analyzing complex systems with unobservable (latent) factors, using a <strong>state equation</strong> (how hidden factors evolve, e.g., market sentiment, volatility) and an <strong>observation equation</strong> (linking these states to actual data like prices).</p>
<p>Observation:</p>
<p><code>y(t) = β(t)x(t) + α(t) + ε(t)</code></p>
<p>Transition:</p>
<p><code>β(t) = β(t−1) + η(t)</code></p>
<pre><code class="lang-plaintext">OBSERVATION EQUATION:
    y(t) = β(t) × x(t) + α(t) + ε(t)

    Translation: "Silver price = β × Gold price + intercept + noise"

STATE TRANSITION:
    β(t) = β(t-1) + η(t)

    Translation: "Today's β is yesterday's β plus some small change"

KALMAN GAIN (K):
    K = (Predicted Uncertainty) / (Predicted Uncertainty + Measurement Noise)

    Translation: 
    - If we're very uncertain → K is large → Trust the new data more
    - If we're very certain  → K is small → Stick with our prediction
</code></pre>
<p>Kalman Gain balances prediction vs measurement trust.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770656331324/115140c0-f033-402b-a129-a430f153dfdc.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770656372444/e1b6d272-e0bd-4681-8e59-4f4759563729.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-takeaway"><strong>✨ The Takeaway</strong></h2>
<blockquote>
<p><strong><em>"The market isn't chaotic. It's a song with too much static. My job wasn't to predict the next note it was to hear the rhythm underneath."</em></strong></p>
</blockquote>
<p>Next time it rains, listen to the drops hitting your window. There's a rhythm in there fast, slow, fast again. That pattern? That's a mean-reverting process. You've been hearing them your whole life.</p>
<p>You're already a quant. You just didn't know it yet.</p>
]]></content:encoded></item></channel></rss>