In the world of financial risk management, understanding how the value of financial instruments changes in response to various factors is crucial. Sensitivities, often referred to as „Greeks,“ are metrics that measure these changes. In this blog post, we’ll explore how to calculate sensitivities for two financial products using four different methods: finite differences, analytical methods, Monte Carlo simulations, and algorithmic differentiation. We’ll use C# and .NET 8 for our implementations.
Financial Products
We’ll focus on two sample financial products:
- A European call option on a stock.
- A European put option on a stock.
1. Finite-Difference Method
The finite-difference method involves perturbing the input parameters slightly and observing the change in the option price.
Example Calculation for a European Call Option:
using System;
public class FiniteDifference
{
public static double CallOptionPrice(double S, double K, double r, double T, double sigma)
{
double d1 = (Math.Log(S / K) + (r + 0.5 * sigma * sigma) * T) / (sigma * Math.Sqrt(T));
double d2 = d1 - sigma * Math.Sqrt(T);
return S * NormalCDF(d1) - K * Math.Exp(-r * T) * NormalCDF(d2);
}
public static double Delta(double S, double K, double r, double T, double sigma)
{
double epsilon = 0.01;
double priceUp = CallOptionPrice(S + epsilon, K, r, T, sigma);
double priceDown = CallOptionPrice(S - epsilon, K, r, T, sigma);
return (priceUp - priceDown) / (2 * epsilon);
}
private static double NormalCDF(double x)
{
return 0.5 * (1.0 + Math.Erf(x / Math.Sqrt(2.0)));
}
public static void Main()
{
double S = 100; // Spot price
double K = 100; // Strike price
double r = 0.05; // Risk-free rate
double T = 1; // Time to maturity in years
double sigma = 0.2; // Volatility
double delta = Delta(S, K, r, T, sigma);
Console.WriteLine($"Delta: {delta}");
}
}
2. Analytical Method
Analytical methods use closed-form solutions to calculate sensitivities directly. For the Black-Scholes model, these formulas are well-known.
Example Calculation for a European Call Option:
using System;
public class AnalyticalMethod
{
public static double CallDelta(double S, double K, double r, double T, double sigma)
{
double d1 = (Math.Log(S / K) + (r + 0.5 * sigma * sigma) * T) / (sigma * Math.Sqrt(T));
return NormalCDF(d1);
}
private static double NormalCDF(double x)
{
return 0.5 * (1.0 + Math.Erf(x / Math.Sqrt(2.0)));
}
public static void Main()
{
double S = 100; // Spot price
double K = 100; // Strike price
double r = 0.05; // Risk-free rate
double T = 1; // Time to maturity in years
double sigma = 0.2; // Volatility
double delta = CallDelta(S, K, r, T, sigma);
Console.WriteLine($"Delta: {delta}");
}
}
3. Monte Carlo Simulation
Monte Carlo simulations involve simulating many possible paths for the underlying asset’s price and averaging the results.
Example Calculation for a European Call Option:
using System;
public class MonteCarloSimulation
{
public static double MonteCarloPrice(double S, double K, double r, double T, double sigma, int numSimulations)
{
Random rand = new Random();
double sumPayoffs = 0.0;
for (int i = 0; i < numSimulations; i++)
{
double ST = S * Math.Exp((r - 0.5 * sigma * sigma) * T + sigma * Math.Sqrt(T) * NormalRandom(rand));
double payoff = Math.Max(ST - K, 0);
sumPayoffs += payoff;
}
return Math.Exp(-r * T) * (sumPayoffs / numSimulations);
}
public static double Delta(double S, double K, double r, double T, double sigma, int numSimulations)
{
double epsilon = 0.01;
double priceUp = MonteCarloPrice(S + epsilon, K, r, T, sigma, numSimulations);
double priceDown = MonteCarloPrice(S - epsilon, K, r, T, sigma, numSimulations);
return (priceUp - priceDown) / (2 * epsilon);
}
private static double NormalRandom(Random rand)
{
double u1 = 1.0 - rand.NextDouble(); // uniform(0,1] random doubles
double u2 = 1.0 - rand.NextDouble();
return Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2); // random normal(0,1)
}
public static void Main()
{
double S = 100; // Spot price
double K = 100; // Strike price
double r = 0.05; // Risk-free rate
double T = 1; // Time to maturity in years
double sigma = 0.2; // Volatility
int numSimulations = 10000;
double delta = Delta(S, K, r, T, sigma, numSimulations);
Console.WriteLine($"Delta: {delta}");
}
}
4. Algorithmic Differentiation
Algorithmic differentiation leverages techniques to compute exact derivatives efficiently.
Example Calculation for a European Call Option:
using System;
public class AlgorithmicDifferentiation
{
public static double CallPriceAndDelta(double S, double K, double r, double T, double sigma, out double delta)
{
double d1 = (Math.Log(S / K) + (r + 0.5 * sigma * sigma) * T) / (sigma * Math.Sqrt(T));
double d2 = d1 - sigma * Math.Sqrt(T);
double callPrice = S * NormalCDF(d1) - K * Math.Exp(-r * T) * NormalCDF(d2);
delta = NormalCDF(d1);
return callPrice;
}
private static double NormalCDF(double x)
{
return 0.5 * (1.0 + Math.Erf(x / Math.Sqrt(2.0)));
}
public static void Main()
{
double S = 100; // Spot price
double K = 100; // Strike price
double r = 0.05; // Risk-free rate
double T = 1; // Time to maturity in years
double sigma = 0.2; // Volatility
double delta;
double price = CallPriceAndDelta(S, K, r, T, sigma, out delta);
Console.WriteLine($"Delta: {delta}");
}
}
Conclusion
In this blog post, we demonstrated how to calculate the Delta sensitivity for a European call option using four different methods in C# with .NET 8. These methods—finite differences, analytical methods, Monte Carlo simulations, and algorithmic differentiation—each have their strengths and are used in various scenarios depending on the complexity of the financial instruments and the available computational resources.
By understanding and calculating sensitivities accurately, financial institutions can better manage their risk and make informed decisions about their trading and hedging strategies. The choice of method depends on the specific requirements of the task at hand, such as the need for precision, computational efficiency, or the complexity of the financial products involved.