mirror of
https://github.com/velocitatem/PHANTOM.git
synced 2026-05-31 08:33:36 +00:00
58 lines
2.1 KiB
Python
58 lines
2.1 KiB
Python
"""
|
|
Numerical utilities for stable computation.
|
|
|
|
This module provides numerically stable implementations of common operations:
|
|
- safe_exp, safe_log: Avoid overflow/underflow
|
|
- softmax: Numerically stable softmax
|
|
- sigmoid, clamp: Standard transformations
|
|
- intensity_decay: Avellaneda-Stoikov fill intensity
|
|
- inventory_penalty: Quadratic inventory risk
|
|
- poisson_arrivals, hawkes_intensity: Arrival process helpers
|
|
|
|
All functions accept both scalars and numpy arrays.
|
|
"""
|
|
import numpy as np
|
|
|
|
EPS = 1e-8 # small constant to avoid division by zero
|
|
MAX_EXP = 700.0 # maximum safe exponent to avoid overflow
|
|
|
|
def safe_exp(x: np.ndarray | float) -> np.ndarray | float:
|
|
return np.exp(np.clip(x, -MAX_EXP, MAX_EXP))
|
|
|
|
def safe_log(x: np.ndarray | float) -> np.ndarray | float:
|
|
return np.log(np.maximum(x, EPS))
|
|
|
|
def clamp(x: np.ndarray | float, lo: float, hi: float) -> np.ndarray | float:
|
|
return np.clip(x, lo, hi)
|
|
|
|
def sigmoid(x: np.ndarray | float) -> np.ndarray | float:
|
|
return 1.0 / (1.0 + safe_exp(-x))
|
|
|
|
def softmax(x: np.ndarray, axis: int = -1) -> np.ndarray:
|
|
x_max = np.max(x, axis=axis, keepdims=True)
|
|
exp_x = safe_exp(x - x_max)
|
|
return exp_x / (np.sum(exp_x, axis=axis, keepdims=True) + EPS)
|
|
|
|
def geometric_series(base: float, ratio: float, n: int) -> np.ndarray:
|
|
return base * (ratio ** np.arange(n))
|
|
|
|
def ema(old: float, new: float, alpha: float = 0.1) -> float:
|
|
return alpha * new + (1 - alpha) * old
|
|
|
|
def intensity_decay(distance: float, kappa: float = 1.0) -> float:
|
|
"""Avellaneda-Stoikov style fill intensity decay with quote distance"""
|
|
return safe_exp(-kappa * distance)
|
|
|
|
def inventory_penalty(q: float, gamma: float = 0.1, sigma: float = 1.0) -> float:
|
|
"""Quadratic inventory risk penalty"""
|
|
return gamma * sigma**2 * q**2 / 2
|
|
|
|
def poisson_arrivals(rate: float, dt: float, rng: np.random.Generator) -> int:
|
|
return rng.poisson(rate * dt)
|
|
|
|
def hawkes_intensity(base: float, history: np.ndarray, alpha: float, beta: float, t: float) -> float:
|
|
"""Self-exciting Hawkes process intensity"""
|
|
if len(history) == 0: return base
|
|
decays = safe_exp(-beta * (t - history[history < t]))
|
|
return base + alpha * np.sum(decays)
|