The prediction engine combines three mathematical models in logit space for mathematically sound probability adjustments that naturally stay within (0, 1):
Black-Scholes Binary Option - Base probability using distance to strike, volatility, and time remaining
EWMA Volatility - Exponentially weighted moving average of realized volatility (λ=0.94)
Logit-Space Combination - Momentum and mean reversion adjustments in log-odds space
All probability adjustments happen in logit space (log-odds) to ensure outputs remain valid probabilities without requiring manual clamping.
The probability that BTC closes above the strike price is modeled as a binary call option using the Black-Scholes framework:
P(BTC > Strike) = N(d₂)d₂ = [ln(S₀/K) - (σ²/2)×T] / (σ × √T)where: S₀ = current BTC price K = strike price (target) σ = volatility (per-second) T = time remaining (seconds) N = cumulative standard normal distribution
Exponentially Weighted Moving Average (EWMA) gives more weight to recent price movements while maintaining a continuous estimate of volatility. Key properties:
Responsive - React quickly to regime changes (crashes, pumps)
Smooth - Avoid noise from single outlier ticks
Stationary - Converge to stable values in calm markets
Per-second units - Matches Black-Scholes time convention
update(price, timestamp) { this._tickCount++ if (this._lastPrice === null) { this._lastPrice = price this._lastTimestamp = timestamp return 0 } // Log return between consecutive ticks const r = Math.log(price / this._lastPrice) // Time delta in seconds (guard against zero) const dt = Math.max((timestamp - this._lastTimestamp) / 1000, 0.001) // r²/dt gives variance per second const r2PerSec = (r * r) / dt if (!this._initialized) { this._variance = r2PerSec // Seed with first observation this._initialized = true } else { // EWMA update this._variance = this._lambda * this._variance + (1 - this._lambda) * r2PerSec } this._lastPrice = price this._lastTimestamp = timestamp const sigma = Math.sqrt(this._variance) this._sigmaHistory.push(sigma) if (this._sigmaHistory.length > 100) { this._sigmaHistory.shift() } return sigma}
Volatility is computed in per-second units, not annualized. A typical value is σ ≈ 0.00012/sec. To convert to annualized volatility: σ_annual = σ_per_sec × √(365.25 × 86400) ≈ σ_per_sec × 5615.
The engine tracks the mean of the last 100 σ values. If current volatility exceeds 2× meanSigma, the abstention system blocks trading to avoid unpredictable regime shifts.
getMeanSigma() { if (this._sigmaHistory.length === 0) return 0 const sum = this._sigmaHistory.reduce((a, b) => a + b, 0) return sum / this._sigmaHistory.length}
A 1% price move (ROC ≈ 0.01) shifts log-odds by 0.01 × 150 = 1.5
At p=0.5 (logit=0), this moves probability from 0.50 → 0.82
At p=0.7 (logit=0.85), this moves probability from 0.70 → 0.90
Reversion Weight = 80
A 0.5% deviation (signal ≈ -0.005) shifts log-odds by -0.005 × 80 = -0.4
At p=0.5, this moves probability from 0.50 → 0.40
Provides counterbalance to momentum during overextensions
Changing these weights requires re-calibration. Higher weights make the model more reactive but less stable. Lower weights reduce signal but improve calibration.