PFHedge: Deep Hedging in PyTorch

repository·main·Indexed 43 days ago

https://github.com/pfnet-research/pfhedge

A PyTorch-based framework for Deep Hedging designed to optimize hedging operations for financial derivatives using neural networks. Version 0.23.0 provides tools to define primary and derivative instruments, implement hedging strategies (including Black-Scholes and Whalley-Wilmott), and train models via Monte Carlo simulations. It includes the pfhedge.autogreek module for calculating Greeks (Delta, Gamma, Vega, Theta) and pfhedge.features for financial feature engineering.

Tokens
9.8K
Snippets
30
Records
58
Agent score
55%

What's inside PFHedge

  1. Use pfhedge.nn modules for Deep Hedging

    main
    The pfhedge.nn package provides a collection of torch.nn.Module components specifically designed for Deep Hedging workflows. These modules can be integrated into standard PyTorch models to build hedging strategies, incorporate financial models (like Black-Scholes), or define specialized loss functions.
  2. Understand the instrument hierarchy in pfhedge

    main

    PFHedge organizes financial instruments into a hierarchy of base classes that define their behavior. When building custom instruments or using existing ones, you will interact with these core abstractions:

    • BaseInstrument: The root class for all instruments.
    • BasePrimary: Represents primary instruments (underlyings) like stocks or interest rates.
    • BaseDerivative: Represents derivative instruments whose value depends on a primary instrument.
    • BaseOption and OptionMixin: Specific abstractions for option-based derivatives.

    Understanding this hierarchy allows you to correctly identify whether an instrument is an underlying asset or a derivative that needs hedging.

  3. Prepare financial instruments in PFHedge

    main

    PFHedge classifies financial instruments in pfhedge.instruments into two types:

    1. Primary instruments: Basic instruments traded on a market with accessible prices (e.g., BrownianStock, bonds, commodities).
    2. Derivative instruments: Instruments whose payoff is contingent on a primary instrument (e.g., EuropeanOption, LookbackOption, VarianceSwap).

    To use a derivative, you must first define its underlying primary instrument.

    from pfhedge.instruments import BrownianStock
    from pfhedge.instruments import EuropeanOption
    
    # Define a primary instrument (stock) with a transaction cost
    stock = BrownianStock(cost=1e-4)
    
    # Define a derivative (European Option) contingent on that stock
    derivative = EuropeanOption(stock)
  4. Use a custom PyTorch Module as a hedging model

    main

    You can use any torch.nn.Module as a hedging model. The module must follow the input/output shape convention: (N, H_in) -> (N, 1), where N is the number of Monte Carlo paths and H_in is the number of input features. To integrate with Hedger, your module should implement an inputs() method that returns the required input features.

    import torch
    import torch.nn.functional as fn
    from torch import Tensor
    from torch.nn import Module
    
    from pfhedge.nn import BlackScholes
    from pfhedge.nn import Clamp
    from pfhedge.nn import Hedger
    from pfhedge.nn import MultiLayerPerceptron
    
    
    class NoTransactionBandNet(Module):
        def __init__(self, derivative):
            super().__init__()
    
            self.delta = BlackScholes(derivative)
            self.mlp = MultiLayerPerceptron(out_features=2)
            self.clamp = Clamp()
    
        def inputs(self):
            return self.delta.inputs() + ["prev_hedge"]
    
        def forward(self, input: Tensor) -> Tensor:
            prev_hedge = input[..., [-1]]
    
            delta = self.delta(input[..., :-1])
            width = self.mlp(input[..., :-1])
    
            min = delta - fn.leaky_relu(width[..., [0]])
            max = delta + fn.leaky_relu(width[..., [1]])
    
            return self.clamp(prev_hedge, min=min, max=max)
    
    
    model = NoTransactionBandNet(derivative)
    hedger = Hedger(model, inputs=model.inputs())
  5. Use pfhedge.features with pfhedge.nn.Hedger

    main

    pfhedge.features provides a suite of feature engineering tools designed to be used with pfhedge.nn.Hedger. These features allow you to transform raw market data and derivative states into meaningful inputs for the hedging neural network.

    Available feature categories include:

    • Derivatives Features: Financial indicators like Moneyness, Barrier, TimeToMaturity, and Volatility.
    • Tensor Creation Ops: Utilities like Empty, Ones, and Zeros for managing tensor shapes.
    • Containers: Structures like FeatureList and ModuleOutput to organize feature data.
  6. Quickstart: Minimal Deep Hedging Example

    main

    To perform Deep Hedging, you need to follow three main steps: prepare a derivative instrument, define a hedger with a neural network model, and then fit the hedger to the derivative to determine the price.

    This workflow uses pfhedge.instruments to define the market and derivative, pfhedge.nn to define the hedging strategy, and the fit method to train the model.

    import torch
    from pfhedge.instruments import BrownianStock
    from pfhedge.instruments import EuropeanOption
    from pfhedge.nn import Hedger
    from pfhedge.nn import MultiLayerPerceptron
    
    torch.manual_seed(42)
    
    # 1. Prepare a derivative to hedge
    deriv = EuropeanOption(BrownianStock(cost=1e-4))
    
    # 2. Create your hedger
    model = MultiLayerPerceptron()
    hedger = Hedger(
        model, inputs=["log_moneyness", "time_to_maturity", "volatility", "prev_hedge"]
    )
    
    # 3. Fit and price
    hedger.fit(deriv)
    price = hedger.price(deriv)
    
    print("Price:", price.item())
  7. Calculate Greeks using pfhedge.autogreek

    main
    The pfhedge.autogreek module provides functions to automatically evaluate the 'Greeks'—the sensitivity of a derivative's price to its input parameters—using automatic differentiation. This allows for efficient calculation of risk metrics without requiring manual derivation of the sensitivities.
  8. Train and price derivatives with Hedger.fit() and Hedger.price()

    main

    Once a Hedger is initialized, you can train it to minimize its risk measure and then use it to calculate the derivative price.

    Training (fit)

    Calling hedger.fit(derivative, n_epochs=...) performs Monte Carlo simulations. In each epoch, the hedger generates asset price paths, executes hedging trades, and updates the model parameters based on the resulting profit and loss distribution and the chosen risk measure.

    Pricing (price)

    After training, use hedger.price(derivative) to evaluate the derivative price as the utility indifference price.

    # Train the hedger for 200 epochs
    hedger.fit(derivative, n_epochs=200)
    
    # Calculate the derivative price
    price = hedger.price(derivative)
  9. Use GPU and specific dtypes in PFHedge

    main

    To perform fitting and pricing on a specific PyTorch device (e.g., cuda:0) or with a specific dtype (e.g., torch.float64), use the .to() method on both your derivative and your hedger instances.

    dtype = torch.float64
    device = torch.device("cuda:0")
    
    derivative = EuropeanOption(BrownianStock()).to(dtype, device)
    hedger = Hedger(...).to(dtype, device)
  10. Prepare a derivative to hedge

    main

    Derivatives in PFHedge are constructed by wrapping an underlying instrument (like BrownianStock) within a derivative class (like EuropeanOption).

    Example: EuropeanOption(BrownianStock(cost=1e-4)) creates a European option where the underlying asset follows a Brownian motion with a transaction cost of $10^{-4}$.

    from pfhedge.instruments import BrownianStock
    from pfhedge.instruments import EuropeanOption
    
    deriv = EuropeanOption(BrownianStock(cost=1e-4))