- add README live-demo badge - tighten engine validation for jump grids and detector indices - replace flaky FastAPI TestClient web tests with direct handler tests - remove unused httpx dev dependency - clean stale frontend comments - re-execute notebooks with clean sequential outputs
6.9 KiB
Adaptive Barrier Monitor
A five-notebook quantitative-finance project connecting random walks, Brownian motion, geometric Brownian motion, first-passage times, Brownian bridges, and state-dependent monitoring.
The motivating question is:
A stock is monitored for a large move over a short window. Continuous polling is expensive. What probability model describes a hidden barrier crossing, and how can that model inform a sampling schedule?
The project is written for a mathematically mature reader who wants to see how Gaussian processes, conditioning, stochastic calculus, and Monte Carlo methods appear in a practical monitoring problem.
Core results and scope
Under geometric Brownian motion,
\frac{dS_t}{S_t}=\mu dt+\sigma dW_t,
the relative log-price X_t=\log(S_t/S_0) is arithmetic Brownian motion. A
10% drop corresponds to the lower log barrier B=\log(0.9).
For zero drift, the probability of touching the barrier by time T is
P(\tau_B\leq T)=2\Phi\left(\frac{B}{\sigma\sqrt{T}}\right).
At 30% annualised volatility, a 10% move in five trading minutes is roughly a 49-standard-deviation diffusion event. Pure GBM therefore assigns it probability below ordinary floating-point resolution; jumps and market microstructure are essential for realistic extreme-move modelling.
Conditional on two observations x_0,x_T>B, the Brownian-bridge probability
that the hidden path crossed the barrier is
P_{\mathrm{cross}}
=\exp\left(
-\frac{2(x_0-B)(x_T-B)}{\sigma^2\Delta t}
\right).
If both endpoint distances are set equal to D, inversion gives
\Delta t_{\mathrm{sym}}
=\frac{2D^2}{\sigma^2\log(1/\varepsilon)}.
This inversion is exact conditional on both endpoints being known. In a
live scheduler, the future endpoint is unknown; the implementation substitutes
the current distance for both endpoints. Thus \varepsilon is a local
diffusion-design parameter, not an unconditional miss guarantee, and it does
not control jumps. A hard maximum polling interval remains necessary.
Notebooks
| # | Notebook | Main topics |
|---|---|---|
| 01 | Random walks to Brownian motion | Log returns, the \min(s,t) covariance kernel, Cholesky sampling, Brownian scaling |
| 02 | GBM and Itô's lemma | Multiplicative prices, exact GBM simulation, Itô correction |
| 03 | First passage and reflection | Reflection principle, Bachelier–Lévy formula, hitting-time diagnostics |
| 04 | Brownian bridges and hidden crossings | Gaussian conditioning, Schur complements, bridge crossing probabilities |
| 05 | Adaptive barrier monitoring | Unit-consistent scheduler, practical polling cap, controlled jump stress test, model-risk discussion |
The analytical formulae are checked against Monte Carlo simulation in the notebooks.
Interactive web application
The FastAPI/Plotly demo compares two sampling schedules on the same simulated paths. The adaptive schedule uses the local symmetric-endpoint bridge proxy, while the fixed baseline can run in either of two modes:
- Equal budget: the fixed schedule receives exactly the adaptive schedule's sample count on each path, isolating where observations are placed.
- Fixed cadence: the fixed schedule samples at a user-selected interval, so detection quality, lag, and total observation cost can be compared directly.
A barrier event counts as detected only if a sampled point remains beyond the barrier within a configurable number of simulation steps. The comparison is therefore explicit and reproducible rather than based on an unrestricted "eventually detected" definition.
The demo supports GBM and an optional Merton jump-diffusion stress mode. When
jumps are enabled, the interface explicitly warns that the Brownian diffusion
parameter \varepsilon does not bound jump-event misses.
Run locally
python -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[webapp]"
python -m uvicorn webapp.app:app --host 127.0.0.1 --port 8055
Open http://127.0.0.1:8055.
Docker
docker compose -f docker-compose.webapp.yml up --build
For an existing Caddy Docker network:
docker compose -f docker-compose.webapp.proxy.yml up --build -d
The container runs as a non-root user and includes an HTTP health check.
Run the notebooks
python -m venv .venv
source .venv/bin/activate
pip install -e ".[notebooks]"
jupyter lab notebooks/
Notebooks that request market data cache successful downloads under
data/cache/. Their analytical and simulation sections remain usable when the
network fetch is unavailable.
Tests
pip install -e ".[dev,webapp]"
pytest
The test suite covers:
- inversion of the Brownian-bridge formula;
- vectorised interval calculations and input validation;
- consistent time/volatility units in the adaptive schedule;
- enforcement of the detection deadline;
- exact per-path sample-budget equality;
- equivalence of zero-intensity jump diffusion and GBM;
- aggregate simulation invariants.
Project structure
adaptive-barrier-monitor/
├── notebooks/ # five executed research notebooks
├── src/adaptive_barrier/
│ ├── __init__.py
│ └── engine.py # samplers, closed forms, scheduler, evaluation
├── tests/
│ └── test_engine.py
├── webapp/
│ ├── app.py # FastAPI API
│ ├── Dockerfile
│ └── static/ # vanilla JS, Plotly, CSS
├── .github/workflows/tests.yml
├── pyproject.toml
├── requirements.txt
├── requirements-webapp.txt
├── requirements-dev.txt
├── bibliography.md
├── LICENSE
└── webapp.md
Model limitations
- Online endpoint uncertainty: the bridge crossing formula is conditional on both endpoints; the scheduler uses a local approximation before the next endpoint exists.
- Jump risk: diffusion-derived polling cannot guarantee detection of sudden jump-and-recovery events.
- No market microstructure model: bid–ask bounce, asynchronous feeds, exchange halts, queueing, and packet latency are not represented.
- Simulation-grid dependence: the web demo's detection deadline is measured
in simulated grid steps; changing
n_stepschanges its physical duration. - Educational calibration: jump parameters in the sandbox are user-controlled stress parameters, not production estimates.
Tech stack
Python, NumPy, SciPy, pandas, SymPy, Matplotlib, FastAPI, Pydantic, Uvicorn, Plotly.js, Docker, pytest.
License
MIT — see LICENSE.