Untitled

 avatar
unknown
python
12 days ago
3.3 kB
3
Indexable
import numpy as np
from datetime import datetime

def generate_ig(mu, lambda_, size=None):
    """Generate inverse Gaussian samples with mean mu and shape lambda_."""
    if size is None:
        size = 1
    if isinstance(size, int):
        size = (size,)
    Z = np.random.normal(0, 1, size=size)
    term1 = (mu**2 * Z**2) / (2 * lambda_)
    term2 = (mu / (2 * lambda_)) * np.sqrt(4 * mu * lambda_ * Z**2 + mu**2 * Z**4)
    V = mu + term1 - term2
    U = np.random.uniform(0, 1, size=size)
    mask = U <= mu / (mu + V)
    return np.where(mask, V, mu**2 / V)

def simulate_gh_bridge(start_date: str, start_price: float, 
                       end_date: str, end_price: float, 
                       current_date: str, n_paths: int, 
                       expected_return: float, volatility: float, 
                       alpha: float = 1.0) -> np.ndarray:
    """
    Simulate bridge paths with generalized hyperbolic increments.
    
    Parameters:
    - start_date (str): 'YYYY-MM-DD'
    - start_price (float): Starting price
    - end_date (str): 'YYYY-MM-DD'
    - end_price (float): Ending price
    - current_date (str): 'YYYY-MM-DD', between start and end
    - n_paths (int): Number of paths
    - expected_return (float): Annual expected return
    - volatility (float): Annual volatility
    - alpha (float): GH tail parameter (default 1.0)
    
    Returns:
    - np.ndarray: Shape (n_steps, n_paths) with simulated prices
    """
    # Date handling
    start_dt = datetime.strptime(start_date, '%Y-%m-%d')
    end_dt = datetime.strptime(end_date, '%Y-%m-%d')
    current_dt = datetime.strptime(current_date, '%Y-%m-%d')
    if not (start_dt <= current_dt <= end_dt):
        raise ValueError("Current date must be between start and end dates")
    
    # Time setup
    total_time = (end_dt - start_dt).days / 365.25
    n_steps = (end_dt - start_dt).days + 1
    dt = total_time / (n_steps - 1) if n_steps > 1 else 0
    
    # Parameters
    drift = (expected_return - 0.5 * volatility**2) * dt
    delta = alpha * volatility**2 * dt
    mu_ig = delta / alpha
    lambda_ig = delta * alpha  # Controls kurtosis
    
    # Generate increments
    V = generate_ig(mu_ig, lambda_ig, size=(n_steps-1, n_paths))
    Z = np.random.normal(0, 1, (n_steps-1, n_paths))
    increments = np.sqrt(V) * Z
    
    # Cumulative process
    M = np.vstack([np.zeros((1, n_paths)), np.cumsum(increments, axis=0)])
    t = np.linspace(0, total_time, n_steps)
    bridge_factor = t / total_time if total_time > 0 else np.zeros(n_steps)
    
    # Log prices
    log_S = (np.log(start_price) + drift * t[:, None] + M - 
             bridge_factor[:, None] * M[-1, :] + 
             bridge_factor[:, None] * (np.log(end_price / start_price) - drift * total_time))
    
    # Prices
    paths = np.exp(log_S)
    paths[0, :] = start_price  # Ensure exact start
    paths[-1, :] = end_price   # Ensure exact end
    
    return paths

# Example
if __name__ == "__main__":
    paths = simulate_gh_bridge(
        start_date="2025-01-01", start_price=100.0,
        end_date="2025-03-04", end_price=110.0,
        current_date="2025-02-01", n_paths=5,
        expected_return=0.05, volatility=0.2, alpha=1.0
    )
    print(f"Paths shape: {paths.shape}")
    print(f"Sample path:\n{paths[:, 0]}")
Editor is loading...
Leave a Comment