approaches to calibrating a Heston model

Discussion in 'Options' started by stochastix, Mar 2, 2023.

  1. lariati

    lariati

    I just started messing with chatGPT4. Here is the version it gives for the below as a python function.

    import numpy as np
    def heston_char_function(t, w, v_bar, v_0, s_0, r, lam, theta, sigma):
    i_w = 1j * w

    g = (lam - r * i_w) / (lam + r * i_w)

    C = (((r * i_w - lam * theta) / sigma**2) * (1 - np.exp(-lam * t))
    + (theta / (2 * lam)) * ((lam - r * i_w) * t - 2 * np.log((1 - g * np.exp(-lam * t)) / (1 - g))))

    D = ((1 / sigma**2) * (1 - np.exp(-lam * t)) * ((r * i_w - lam * theta) / lam - 1 / 2)
    + (1 / lam**2) * ((lam - r * i_w) * (1 - np.exp(-lam * t)) - 2 * (np.log(1 - g * np.exp(-lam * t)) - g * np.exp(-lam * t))))

    phi_h = np.exp(C * v_bar + D * v_0 + i_w * np.log(s_0 * np.exp(r * t)))

    return phi_h

    # Example parameters
    t = 1
    w = 0.5
    v_bar = 0.04
    v_0 = 0.04
    s_0 = 100
    r = 0.03
    lam = 2
    theta = 0.04
    sigma = 0.3

    # Compute the Heston characteristic function
    result = heston_char_function(t, w, v_bar, v_0, s_0, r, lam, theta, sigma)
    print("Heston Characteristic Function: ", result)

    No clue on any of that but it does give an answer in a jupyter notebook. I tried GPT4 on a more obscure javascript library that it hallucinated nonsense but got things right on the 3rd try with feedback from the output.

    It is just lunacy that chatGPT3.5 is outdated already lol. GPT4 looks like it did much better on math related tests in the paper so hopefully programming takes a nice jump. Seems very hard to test this though.


     
    #41     Mar 14, 2023
    stochastix likes this.
  2. you can probably test it on some reference prices at
    https://financepress.com/2019/02/15/heston-model-reference-prices/

    gpt-4 seems much better, it knows that the W function is the Newton flow of the exponential function, I got it to verify this even though i couldnt find a paper explicitly stating it:

    https://math.stackexchange.com/ques...n-the-newton-flow-of-the-exponential-function

    and I updated my paper with the closed-form formula it helped me derive.. this is a publishable result but i probably wont mess with it
     
    #42     Mar 14, 2023
    lariati likes this.
  3. there are multitudes of papers on how to compute the option prices once you have the characteristic function, they all involve the inverse Fourier transform in one form of the other because by definition the probability density is the inverse Fourier transform of the characteristic function and the characteristic function is the Fourier transform of the density
    , see https://en.wikipedia.org/wiki/Carr–Madan_formula
     
    #43     Mar 14, 2023
  4. panzerman

    panzerman

    Since you brought up the Fourier Transform:



    What does option pricing have to do with converting a periodic function in the time domain into the frequency domain?
     
    #44     Mar 14, 2023
  5. the function doesn't have to be periodic. Was that a rhetorical question? videos is not my favorite format for learning and understanding, i always learn math by pontificating on theorems in black and white and doing thought experiments or code experiments or just working out the calculus.. its a bit of a rush each time you figure out how some shit works .. the guys explanation ends up being long winded and ironically he had to use fourier transforms implicitly in the operation of the DSP devices he used to produce the video and also similiar to hear the sound on the computer from the data stream
     
    #45     Mar 14, 2023
  6. Section 3.1 of Perfect hedging in rough Heston models: Generalized rough Heston models as limit of nearly unstable Hawkes processes

    In this section, the authors explore the connection between generalized rough Heston models and nearly unstable Hawkes processes. They explain that a microscopic price model based on two-dimensional Hawkes processes converges to a rough Heston log-price with constant mean-reversion after suitable rescaling. However, this method has limitations when it comes to computing prices and hedging portfolios using classical Fourier inversion methods.

    To address this issue, the authors propose an alternative approach similar to the one presented in another study. They consider a sequence of one-dimensional Hawkes processes with intensity given by:

    λTt = µT + ∫(from 0 to t) aT * ϕ(t - s) * dNsT

    Here, µT and aT are positive constants with aT < 1, and ϕ is an integrable function. The authors show that, under certain conditions on the parameters, the intensity process λTt asymptotically behaves as the variance process of a rough Heston model with constant mean-reversion and an initial variance equal to zero.

    To obtain a time-dependent mean-reversion level and a non-zero starting value in the limit, the authors draw inspiration from another study, which suggests that a time-dependent µT is a way to modify some parameters in the limit. This approach helps to better understand the relationship between generalized rough Heston models and nearly unstable Hawkes processes, and ultimately aids in managing financial risks more effectively.
     
    #46     Mar 15, 2023
  7. time-dependent µT means µT becomes µ(T) rather than just being multiplied its an arbitrary function
     
    #47     Mar 15, 2023
  8. package bonanzai.instruments.options.vix;



    import java.util.ArrayList;

    importjava.util.Collections;

    import java.util.List;



    import com.ib.client.ClientSocket;

    import com.ib.client.TagValue;

    importcom.ib.client.TickType;

    import com.ib.contracts.Contract;

    import com.ib.contracts.ContractDetails;



    publicclassVIXHedging

    {



    // Define constants for contract multipliers

    privatestaticfinalintVIX_CONTRACT_MULTIPLIER = 1000;

    privatestaticfinalintSPX_CONTRACT_MULTIPLIER = 100;



    // Define constant for gamma adjustment

    privatestaticfinaldoubleGAMMA_ADJUSTMENT_CONSTANT = 1.5;



    publicstaticvoidmain(String[] args)

    {



    // Set up connection to TWS

    ClientSocketclient = new ClientSocket(null);

    client.connect("localhost", 7496, 0);



    // Define VIX and SPX contracts

    ContractvixContract = new Contract();

    vixContract.symbol("VIX");

    vixContract.secType("FUT");

    vixContract.exchange("CFE");

    vixContract.currency("USD");

    vixContract.expirationDate = "20230315";



    ContractspxContract = new Contract();

    spxContract.symbol("SPX");

    spxContract.secType("OPT");

    spxContract.exchange("SMART");

    spxContract.currency("USD");

    spxContract.expirationDate = "20230315";

    spxContract.multiplier(Integer.toString(SPX_CONTRACT_MULTIPLIER));



    // Define range of strikes to consider

    doubleminStrike = 1000.0;
    package bonanzai.instruments.options.vix;

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;

    import com.ib.client.ClientSocket;
    import com.ib.client.TagValue;
    import com.ib.client.TickType;
    import com.ib.contracts.Contract;
    import com.ib.contracts.ContractDetails;

    public class VIXHedging
    {

    // Define constants for contract multipliers
    private static final int VIX_CONTRACT_MULTIPLIER = 1000;
    private static final int SPX_CONTRACT_MULTIPLIER = 100;

    // Define constant for gamma adjustment
    private static final double GAMMA_ADJUSTMENT_CONSTANT = 1.5;

    public static void main(String[] args)
    {

    // Set up connection to TWS
    ClientSocket client = new ClientSocket(null);
    client.connect("localhost", 7496, 0);

    // Define VIX and SPX contracts
    Contract vixContract = new Contract();
    vixContract.symbol("VIX");
    vixContract.secType("FUT");
    vixContract.exchange("CFE");
    vixContract.currency("USD");
    vixContract.expirationDate = "20230315";

    Contract spxContract = new Contract();
    spxContract.symbol("SPX");
    spxContract.secType("OPT");
    spxContract.exchange("SMART");
    spxContract.currency("USD");
    spxContract.expirationDate = "20230315";
    spxContract.multiplier(Integer.toString(SPX_CONTRACT_MULTIPLIER));

    // Define range of strikes to consider
    double minStrike = 1000.0;
    double maxStrike = 5000.0;
    double strikeIncrement = 50.0;

    // Define list to store SPX options and their deltas
    List<OptionDelta> spxOptions = new ArrayList<>();

    double T = 7; // 7 days til expation

    // Loop over strikes to retrieve SPX option deltas
    for (double strike = minStrike; strike <= maxStrike; strike += strikeIncrement)
    {
    spxContract.strikePrice = strike;
    spxContract.right = "C"; // assume all calls for simplicity

    // Retrieve contract details to get delta
    List<ContractDetails> contractDetails = new ArrayList<>();
    client.reqContractDetails(0, spxContract);
    assert false : "todo, if i surive";
    double delta = contractDetails.get(0).getGreeks().getDelta();

    // Create OptionDelta object to store strike and delta
    OptionDelta optionDelta = new OptionDelta(strike,
    delta,
    Double.NaN,
    T);

    // Add OptionDelta object to list
    spxOptions.add(optionDelta);
    }

    // Retrieve VIX option deltas using VIX pricing model
    List<Double> vixOptionDeltas = getVIXOptionDeltas();

    // Calculate hedge ratios for each SPX option
    List<HedgeRatio> hedgeRatios = new ArrayList<>();
    for (int i = 0; i < spxOptions.size(); i++)
    {
    OptionDelta spxOption = spxOptions.get(i);
    double deltaVIX = vixOptionDeltas.get(i);
    double hedgeRatio = (deltaVIX * VIX_CONTRACT_MULTIPLIER)
    / (spxOption.getDelta() * SPX_CONTRACT_MULTIPLIER);
    client.reqMarketData(0, spxContract, "SPX", false, new ArrayList<TagValue>());
    assert false : "todo, dont blow up";
    double gamma = Double.NaN;
    double gammaAdjustment = 1 + 0.5 * spxOption.getGamma()
    * Math.pow(spxOption.getStrike() / GAMMA_ADJUSTMENT_CONSTANT, 2)
    / (Math.pow(gamma, 2)
    * spxOption.getTimeToMaturity());
    hedgeRatios.add(new HedgeRatio(spxOption.getStrike(),
    hedgeRatio * gammaAdjustment));
    }
    // Print out hedge ratios
    for (HedgeRatio hedgeRatio : hedgeRatios)
    {
    System.out.println("Strike: " + hedgeRatio.getStrike() + ", Ratio: " + hedgeRatio.getRatio());
    }

    // Disconnect from TWS
    client.disconnect();
    }

    private static List<Double> getVIXOptionDeltas()
    {
    // TODO: Implement function to calculate VIX option deltas using VIX pricing
    // model
    return null;
    }

    public static class OptionDelta
    {
    private final double strike;
    private final double delta;
    private final double gamma;
    private final double timeToMaturity;

    public OptionDelta(double strike, double delta, double gamma, double timeToMaturity)
    {
    this.strike = strike;
    this.delta = delta;
    this.gamma = gamma;
    this.timeToMaturity = timeToMaturity;
    }

    public double getStrike()
    {
    return strike;
    }

    public double getDelta()
    {
    return delta;
    }

    public double getGamma()
    {
    return gamma;
    }

    public double getTimeToMaturity()
    {
    return timeToMaturity;
    }
    }

    public static class HedgeRatio
    {
    private final double strike;
    private final double ratio;

    public HedgeRatio(double strike, double ratio)
    {
    this.strike = strike;
    this.ratio = ratio;
    }

    public double getStrike()
    {
    return strike;
    }

    public double getRatio()
    {
    return ratio;
    }
    }
    }
    doublemaxStrike = 5000.0;

    doublestrikeIncrement = 50.0;



    // Define list to store SPX options and their deltas

    List<OptionDelta> spxOptions = new ArrayList<>();



    doubleT = 7; // 7 days tilexpation



    // Loop over strikes to retrieve SPX option deltas

    for (doublestrike = minStrike; strike <= maxStrike; strike += strikeIncrement)
    package bonanzai.instruments.options.vix;

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;

    import com.ib.client.ClientSocket;
    import com.ib.client.TagValue;
    import com.ib.client.TickType;
    import com.ib.contracts.Contract;
    import com.ib.contracts.ContractDetails;

    public class VIXHedging
    {

    // Define constants for contract multipliers
    private static final int VIX_CONTRACT_MULTIPLIER = 1000;
    private static final int SPX_CONTRACT_MULTIPLIER = 100;

    // Define constant for gamma adjustment
    private static final double GAMMA_ADJUSTMENT_CONSTANT = 1.5;

    public static void main(String[] args)
    {

    // Set up connection to TWS
    ClientSocket client = new ClientSocket(null);
    client.connect("localhost", 7496, 0);

    // Define VIX and SPX contracts
    Contract vixContract = new Contract();
    vixContract.symbol("VIX");
    vixContract.secType("FUT");
    vixContract.exchange("CFE");
    vixContract.currency("USD");
    vixContract.expirationDate = "20230315";

    Contract spxContract = new Contract();
    spxContract.symbol("SPX");
    spxContract.secType("OPT");
    spxContract.exchange("SMART");
    spxContract.currency("USD");
    spxContract.expirationDate = "20230315";
    spxContract.multiplier(Integer.toString(SPX_CONTRACT_MULTIPLIER));

    // Define range of strikes to consider
    double minStrike = 1000.0;
    double maxStrike = 5000.0;
    double strikeIncrement = 50.0;

    // Define list to store SPX options and their deltas
    List<OptionDelta> spxOptions = new ArrayList<>();

    double T = 7; // 7 days til expation

    // Loop over strikes to retrieve SPX option deltas
    for (double strike = minStrike; strike <= maxStrike; strike += strikeIncrement)
    {
    spxContract.strikePrice = strike;
    spxContract.right = "C"; // assume all calls for simplicity

    // Retrieve contract details to get delta
    List<ContractDetails> contractDetails = new ArrayList<>();
    client.reqContractDetails(0, spxContract);
    assert false : "todo, if i surive";
    double delta = contractDetails.get(0).getGreeks().getDelta();

    // Create OptionDelta object to store strike and delta
    OptionDelta optionDelta = new OptionDelta(strike,
    delta,
    Double.NaN,
    T);

    // Add OptionDelta object to list
    spxOptions.add(optionDelta);
    }

    // Retrieve VIX option deltas using VIX pricing model
    List<Double> vixOptionDeltas = getVIXOptionDeltas();

    // Calculate hedge ratios for each SPX option
    List<HedgeRatio> hedgeRatios = new ArrayList<>();
    for (int i = 0; i < spxOptions.size(); i++)
    {
    OptionDelta spxOption = spxOptions.get(i);
    double deltaVIX = vixOptionDeltas.get(i);
    double hedgeRatio = (deltaVIX * VIX_CONTRACT_MULTIPLIER)
    / (spxOption.getDelta() * SPX_CONTRACT_MULTIPLIER);
    client.reqMarketData(0, spxContract, "SPX", false, new ArrayList<TagValue>());
    assert false : "todo, dont blow up";
    double gamma = Double.NaN;
    double gammaAdjustment = 1 + 0.5 * spxOption.getGamma()
    * Math.pow(spxOption.getStrike() / GAMMA_ADJUSTMENT_CONSTANT, 2)
    / (Math.pow(gamma, 2)
    * spxOption.getTimeToMaturity());
    hedgeRatios.add(new HedgeRatio(spxOption.getStrike(),
    hedgeRatio * gammaAdjustment));
    }
    // Print out hedge ratios
    for (HedgeRatio hedgeRatio : hedgeRatios)
    {
    System.out.println("Strike: " + hedgeRatio.getStrike() + ", Ratio: " + hedgeRatio.getRatio());
    }

    // Disconnect from TWS
    client.disconnect();
    }

    private static List<Double> getVIXOptionDeltas()
    {
    // TODO: Implement function to calculate VIX option deltas using VIX pricing
    // model
    return null;
    }

    public static class OptionDelta
    {
    private final double strike;
    private final double delta;
    private final double gamma;
    private final double timeToMaturity;

    public OptionDelta(double strike, double delta, double gamma, double timeToMaturity)
    {
    this.strike = strike;
    this.delta = delta;
    this.gamma = gamma;
    this.timeToMaturity = timeToMaturity;
    }

    public double getStrike()
    {
    return strike;
    }

    public double getDelta()
    {
    return delta;
    }

    public double getGamma()
    {
    return gamma;
    }

    public double getTimeToMaturity()
    {
    return timeToMaturity;
    }
    }

    public static class HedgeRatio
    {
    private final double strike;
    private final double ratio;

    public HedgeRatio(double strike, double ratio)
    {
    this.strike = strike;
    this.ratio = ratio;
    }

    public double getStrike()
    {
    return strike;
    }

    public double getRatio()
    {
    return ratio;
    }
    }
    }
    {

    spxContract.strikePrice = strike;

    spxContract.right = "C"; // assume all calls for simplicity



    // Retrieve contract details to get delta

    List<ContractDetails> contractDetails = new ArrayList<>();

    client.reqContractDetails(0, spxContract);

    assertfalse : "todo, if i surive";

    doubledelta = contractDetails.get(0).getGreeks().getDelta();



    // Create OptionDelta object to store strike and delta

    OptionDeltaoptionDelta = new OptionDelta(strike,

    delta,

    Double.NaN,

    T);



    // Add OptionDelta object to list

    spxOptions.add(optionDelta);

    }



    // Retrieve VIX option deltas using VIX pricing model

    List<Double> vixOptionDeltas = getVIXOptionDeltas();



    // Calculate hedge ratios for each SPX option

    List<HedgeRatio> hedgeRatios = new ArrayList<>();

    for (inti = 0; i < spxOptions.size(); i++)

    {

    OptionDeltaspxOption = spxOptions.get(i);

    doubledeltaVIX = vixOptionDeltas.get(i);

    doublehedgeRatio = (deltaVIX * VIX_CONTRACT_MULTIPLIER)

    / (spxOption.getDelta() * SPX_CONTRACT_MULTIPLIER);

    client.reqMarketData(0, spxContract, "SPX", false, new ArrayList<TagValue>());

    assertfalse : "todo, dont blow up";

    doublegamma = Double.NaN;

    doublegammaAdjustment = 1 + 0.5 * spxOption.getGamma()

    * Math.pow(spxOption.getStrike() / GAMMA_ADJUSTMENT_CONSTANT, 2)

    / (Math.pow(gamma, 2)

    * spxOption.getTimeToMaturity());

    hedgeRatios.add(new HedgeRatio(spxOption.getStrike(),

    hedgeRatio * gammaAdjustment));

    }

    // Print out hedge ratios

    for (HedgeRatiohedgeRatio : hedgeRatios)

    {

    System.out.println("Strike: " + hedgeRatio.getStrike() + ", Ratio: " + hedgeRatio.getRatio());

    }



    // Disconnect from TWS

    client.disconnect();

    }



    privatestaticList<Double> getVIXOptionDeltas()

    {

    // TODO: Implement function to calculate VIX option deltas using VIX pricing

    // model

    returnnull;

    }



    publicstaticclassOptionDelta

    {

    privatefinaldoublestrike;

    privatefinaldoubledelta;

    privatefinaldoublegamma;

    privatefinaldoubletimeToMaturity;



    publicOptionDelta(doublestrike, doubledelta, doublegamma, doubletimeToMaturity)

    {

    this.strike = strike;

    this.delta = delta;

    this.gamma = gamma;

    this.timeToMaturity = timeToMaturity;

    }



    publicdoublegetStrike()

    {

    returnstrike;

    }



    publicdoublegetDelta()

    {

    returndelta;

    }



    publicdoublegetGamma()

    {

    returngamma;

    }



    publicdoublegetTimeToMaturity()

    {

    returntimeToMaturity;

    }

    }



    publicstaticclassHedgeRatio

    {

    privatefinaldoublestrike;

    privatefinaldoubleratio;



    publicHedgeRatio(doublestrike, doubleratio)

    {

    this.strike = strike;

    this.ratio = ratio;

    }



    publicdoublegetStrike()

    {

    returnstrike;

    }



    publicdoublegetRatio()

    {

    returnratio;

    }

    }

    }
     
    #48     Mar 15, 2023
  9. had to start somewhere
     
    #49     Mar 15, 2023
  10. lariati

    lariati

    That is really cool. It hadn't really occurred to me that was outputting a price hah.
    I would actually rather not get it in my head that I could actually trade options with this. This is really a perfect thread of why I don't trade options. It is crazy to me that people trade options without knowing all this.

    chatGPT4 seems like it can get to a working answer much better even if the first pass is wrong. 3.5 felt like it tended to go off the rails if the first answer was wrong. I read in the released paper though it still only gets about 75% on leet code easy questions, 25% on medium and helpless on leet code hard questions.

     
    #50     Mar 15, 2023
    stochastix likes this.