You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
3.6 KiB
TypeScript
96 lines
3.6 KiB
TypeScript
import { useSetAtom, atom as $ } from "jotai";
|
|
import { useMemo } from "react";
|
|
|
|
// from [https://stackoverflow.com/a/14873282]
|
|
function erf(x) {
|
|
// save the sign of x
|
|
var sign = (x >= 0) ? 1 : -1;
|
|
x = Math.abs(x);
|
|
|
|
// constants
|
|
var a1 = 0.254829592;
|
|
var a2 = -0.284496736;
|
|
var a3 = 1.421413741;
|
|
var a4 = -1.453152027;
|
|
var a5 = 1.061405429;
|
|
var p = 0.3275911;
|
|
|
|
// A&S formula 7.1.26
|
|
var t = 1.0/(1.0 + p*x);
|
|
var y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);
|
|
return sign * y; // erf(-x) = -erf(x);
|
|
}
|
|
|
|
// produced by ChatGPT
|
|
export function calculateImpliedVolatility({optionPrice, underlyingPrice, strikePrice, timeToExpiration, riskFreeRate=0.03, optionType='call', maxIterations = 100, tolerance = 0.0001}) {
|
|
let iv = 0.5; // Initial guess for implied volatility
|
|
let epsilon = 1e-6; // Small value to avoid division by zero
|
|
|
|
for (let i = 0; i < maxIterations; i++) {
|
|
const optionPriceEstimate = calculateOptionPrice(underlyingPrice, strikePrice, timeToExpiration, iv, riskFreeRate, optionType);
|
|
const vega = calculateVega(underlyingPrice, strikePrice, timeToExpiration, iv, riskFreeRate);
|
|
const diff = optionPrice - optionPriceEstimate;
|
|
|
|
if (Math.abs(diff) < tolerance) {
|
|
return iv;
|
|
}
|
|
|
|
iv = iv + (diff / (vega || epsilon)); // Avoid division by zero
|
|
}
|
|
|
|
return NaN; // If max iterations are reached, return NaN (no convergence)
|
|
}
|
|
|
|
function calculateOptionPrice(S, K, T, impliedVolatility, r, optionType) {
|
|
const d1 = (Math.log(S / K) + (r + (impliedVolatility ** 2) / 2) * T) / (impliedVolatility * Math.sqrt(T));
|
|
const d2 = d1 - impliedVolatility * Math.sqrt(T);
|
|
|
|
if (optionType === 'call') {
|
|
return S * Math.exp(-r * T) * cumulativeDistributionFunction(d1) - K * Math.exp(-r * T) * cumulativeDistributionFunction(d2);
|
|
} else if (optionType === 'put') {
|
|
return K * Math.exp(-r * T) * cumulativeDistributionFunction(-d2) - S * Math.exp(-r * T) * cumulativeDistributionFunction(-d1);
|
|
} else {
|
|
throw new Error('Invalid option type. Use "call" or "put".');
|
|
}
|
|
}
|
|
|
|
function calculateVega(S, K, T, impliedVolatility, r) {
|
|
const d1 = (Math.log(S / K) + (r + (impliedVolatility ** 2) / 2) * T) / (impliedVolatility * Math.sqrt(T));
|
|
return S * Math.sqrt(T) * probabilityDensityFunction(d1);
|
|
}
|
|
|
|
function cumulativeDistributionFunction(x) {
|
|
return 0.5 * (1 + erf(x / Math.sqrt(2)));
|
|
}
|
|
|
|
function probabilityDensityFunction(x) {
|
|
return Math.exp(-0.5 * x ** 2) / Math.sqrt(2 * Math.PI);
|
|
}
|
|
|
|
// Example usage
|
|
/*
|
|
const optionPrice = 5.25; // Example option price
|
|
const underlyingPrice = 50; // Example underlying stock price
|
|
const strikePrice = 50; // Example strike price
|
|
const timeToExpiration = 0.25; // Example time to expiration (in years)
|
|
const riskFreeRate = 0.03; // Example risk-free interest rate
|
|
const optionType = 'call'; // Example option type ('call' or 'put')
|
|
|
|
const impliedVolatility = calculateImpliedVolatility({optionPrice, underlyingPrice, strikePrice, timeToExpiration, riskFreeRate, optionType});
|
|
console.log('Implied Volatility:', impliedVolatility);
|
|
*/
|
|
|
|
export function useLocalAtom(initialValue, deps){
|
|
return useMemo(()=>$(initialValue), deps);
|
|
}
|
|
|
|
/**
|
|
* Define a "command": a function that mutates state. It's passed `get` and `set` functions to access Jotai atoms, in addition to any other parameters.
|
|
* The function is memoized and is returned in the form of a Jotai "set" atom. It's called like any other function.
|
|
* @param fn The function to memoize
|
|
* @param deps Dependency array; when to re-memoize the function
|
|
* @returns
|
|
*/
|
|
export function useCommand(fn, deps){
|
|
return useSetAtom(useMemo(()=>$(null, fn),deps));
|
|
} |