DEV Community

Cover image for Porting physics to finance: How I learned market mechanics by building a trading simulator
Frank Tore
Frank Tore

Posted on

Porting physics to finance: How I learned market mechanics by building a trading simulator

A few weeks ago, a friend asked me a question that perfectly summed up the current state of tech:

"So, did you build a trading bot yet? Everyone has one now. Mine hasn't started earning yet, but soon... oh, very soon."

My immediate, instinctive thought was: Nope. I’m not building a trading bot.

Right now, the internet points you in exactly one direction: wrap a Python script around an LLM, write a moving-average crossover strategy, hook it up to a broker API, and wait for the passive income.

Trusting a generic momentum script with live execution seemed like a great way to aggressively automate losing money.

But that conversation planted a seed. I didn't want a "bot." But what about a systematic copilot?

So, I didn’t build a trading bot - I built a lab where a physics-style equilibrium has to earn its keep against daily market data, on paper, before anyone trusts it with money.

I don't have a background in finance, but I know mathematics and backend architecture. I wanted to see if I could take a mental model from a completely different industry, port it over, and test it against the European ETF market.

The result is FunTrade - an open-source, paper-first, long-only daily research simulator for UCITS mutual funds and ETFs. No on-chain crypto trading, no HFT, and no broker hooks.

Here's how I built it by mashing different domains together and going against the hype.

The Hypothesis: Rubber bands vs. Momentum

I previously used perturbation theory to model energy markets - defining a stable baseline and measuring localized shocks against it to predict shifts.

I had a hypothesis: What if the ETF market isn't just a momentum trend, but a rubber band?

Instead of assuming "the trend is your friend," I wanted to test if extreme market movements eventually snap back to a slow-moving baseline (mean-reversion).

I also had to sharpen the metaphor. A market doesn’t behave like a perfect “always snap back to yesterday’s price” machine: every stretch changes its effective state, and repeated extreme pulls start to look less like elasticity and more like a regime shift.

In FunTrade that’s not hand-waving - it’s enforced with two layers.

First, the equilibrium anchor H0H_0 isn’t fixed; it’s a seasonal OU baseline whose “μ” can drift as the calibration window updates (the band slowly creeps).

Second, I only treat large deviations ε\varepsilon as potentially temporary when the market still looks “elastic”: spike + consecutive-bar regime gates explicitly block mean-reversion buys when the dislocation looks structural rather than a short-lived stretch.

If you keep pulling hard enough, the model decides the band has stopped behaving like a spring - and buys are disabled.

Translating the Math

To test this, I split the logic into distinct layers:

  1. H0H_0 (The Anchor): This is the baseline equilibrium. Instead of just smoothing the last 50 days, I model a seasonal Ornstein–Uhlenbeck process on log prices. Then I “nudge” the equilibrium using macro inputs (interest rates, credit spreads, and FX = foreign-exchange rates), because currency moves change the EUR value of funds priced elsewhere - even if the local NAV hasn’t “explained” the move.
  2. H1/εH_1/ε (The Perturbation): This is the fast, daily deviation score. I compute a blended z-score (price vs. the H0H_0 band, plus volume/strength signals) to measure how statistically distant today is from the equilibrium.

Crucially, a high or low ε doesn't mean the asset is "fundamentally" cheap or expensive in the real world. It just means it is statistically dislocated from the modelled H0H_0 band.

Hitting a Wall: The "Falling Knife" Problem

When you test a hypothesis against real data, you quickly find the holes in your logic.

My initial failure mode was obvious: pure mean-reversion is dangerous. If a fund drops off a cliff due to a massive structural market panic, the pure H1H_1 math screams, "It’s a massive statistical deviation! Buy!" But in reality, catching that falling knife will destroy your portfolio, at least in the short term.

I had to adapt the system so it understood context. I went back to the architecture and added two things:

  1. Regime Validity Filters: Spike and consecutive-bar gates that explicitly block buy signals when the dislocation looks structural rather than temporary.
  2. H2H_2 (The Trend Dampener): An overlay that adjusts the ε score and optionally gates sell signals in strong uptrends, based strictly on the medium-term trend.

Grafana visualizing the slow fair-price equilibrium
Figure 1: Grafana visualizing the slow H0H_0 equilibrium band against actual price, with the fast ε perturbation scores tracking the deviations below. Red annotations mark stretches where regime filters block mean-reversion buys (possible structural dislocation, not a "buy now" signal).

The Laboratory: Strict Boundary Architecture

To actually run these tests, you can't just run a Jupyter notebook. You need a strict boundary that runs walk-forward backtests without accidentally leaking tomorrow's data into today's calibration—otherwise, you are just lying to yourself.

I built the v1 stack purely for offline rigor:

  • Storage: TimescaleDB via Docker. Essential for handling daily OHLC bars and keeping calibration stored per symbol without memory bottlenecks.
  • Engine: Python 3.12 (managed via uv) to crunch the daily matrices and sweep the data.
  • Observability: Grafana to visualize the H0H_0 bands vs. ε deviations over time, plus a Streamlit UI for human-readable daily recommendations.

Mixing it all together

Adapting a physics model taught me more about financial regime shifts and structural market failures than reading a dozen finance books ever could. Seeing those regime filters actually step in to block the system from blindly buying every crash-day ε spike was the exact moment this went from a math experiment to a functional copilot.

Funtrade Copilot recommendations
Figure 2: The Streamlit frontend: abstracting the TimescaleDB and Python calibration matrices into daily, human-readable tactical overlays.

Going against the traditional lines of thought forces you to build better systems. If you want to poke around the time-series pipelines, look at the H0/H1H_0/H_1 math, or run the offline demo on synthetic data, I open-sourced the whole thing.

GitHub Repository: https://github.com/SpektrNO/fun-trade/

To spin it up locally:

make setup && make run && make demo SYMBOL=VWCE.DE
Enter fullscreen mode Exit fullscreen mode

make demo uses synthetic bars so you can run offline; swap in make ingest for real symbols.

Has anyone else successfully (or disastrously) ported a mental model from a completely unrelated field into software architecture?

Top comments (0)