e5d785f511
- 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
197 lines
6.9 KiB
Markdown
197 lines
6.9 KiB
Markdown
# Adaptive Barrier Monitor
|
||
|
||
[](https://abm.pawelsarkowicz.xyz)
|
||
|
||
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](notebooks/01_random_walks_to_brownian_motion.ipynb) | Log returns, the $\min(s,t)$ covariance kernel, Cholesky sampling, Brownian scaling |
|
||
| 02 | [GBM and Itô's lemma](notebooks/02_geometric_brownian_motion_and_ito.ipynb) | Multiplicative prices, exact GBM simulation, Itô correction |
|
||
| 03 | [First passage and reflection](notebooks/03_first_passage_and_reflection_principle.ipynb) | Reflection principle, Bachelier–Lévy formula, hitting-time diagnostics |
|
||
| 04 | [Brownian bridges and hidden crossings](notebooks/04_brownian_bridges_and_miss_probability.ipynb) | Gaussian conditioning, Schur complements, bridge crossing probabilities |
|
||
| 05 | [Adaptive barrier monitoring](notebooks/05_adaptive_barrier_monitor.ipynb) | 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
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
docker compose -f docker-compose.webapp.yml up --build
|
||
```
|
||
|
||
For an existing Caddy Docker network:
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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
|
||
|
||
```text
|
||
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_steps` changes 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`](LICENSE).
|