Skip to main content
Glama
walkingshamrock

Black-Scholes MCP Server

test_black_scholes_zomma.py5.15 kB
#!/usr/bin/env python3 # filepath: /Users/shugo/ghq/github.com/walkingshamrock/black-scholes-mcp/tests/calculators/test_black_scholes_zomma.py import unittest import math from calculators.black_scholes_zomma import calculate_zomma_value from calculators.black_scholes_common import validate_inputs, calculate_d1_d2, norm_pdf class TestBlackScholesZomma(unittest.TestCase): """ Test cases for Black-Scholes Zomma calculation. Zomma measures the rate of change of gamma with respect to changes in volatility. It is the third derivative of the option price with respect to the underlying price. """ def test_calculate_zomma_at_the_money(self): # At-the-money option (S = K) S, K, T, r, q, vol = 100, 100, 1, 0.05, 0.02, 0.2 # Calculate expected zomma value based on the formula d1, d2 = calculate_d1_d2(S, K, T, r, q, vol) gamma_numerator = math.exp(-q * T) * norm_pdf(d1) gamma_denominator = S * vol * math.sqrt(T) gamma = gamma_numerator / gamma_denominator expected_zomma = (d1 * d2 - 1) * gamma / vol # Get the actual calculation from our implementation zomma = calculate_zomma_value(S, K, T, r, q, vol) # Test that the calculated value matches our expected value self.assertAlmostEqual(zomma, expected_zomma, places=6) # Additional verification: for ATM options, zomma should be negative # when d1*d2 < 1, which is typically the case for reasonable parameters if d1 * d2 < 1: self.assertLess(zomma, 0) def test_calculate_zomma_in_the_money(self): # In-the-money call (S > K) S, K, T, r, q, vol = 110, 100, 1, 0.05, 0.02, 0.2 zomma = calculate_zomma_value(S, K, T, r, q, vol) # For ITM options, we expect the zomma to be different from ATM # We're testing the magnitude rather than the exact value d1, d2 = calculate_d1_d2(S, K, T, r, q, vol) gamma_numerator = math.exp(-q * T) * norm_pdf(d1) gamma_denominator = S * vol * math.sqrt(T) gamma = gamma_numerator / gamma_denominator expected_zomma = (d1 * d2 - 1) * gamma / vol self.assertAlmostEqual(zomma, expected_zomma, places=6) def test_calculate_zomma_out_of_the_money(self): # Out-of-the-money call (S < K) S, K, T, r, q, vol = 90, 100, 1, 0.05, 0.02, 0.2 zomma = calculate_zomma_value(S, K, T, r, q, vol) # For OTM options, we expect the zomma to be different from ATM and ITM d1, d2 = calculate_d1_d2(S, K, T, r, q, vol) gamma_numerator = math.exp(-q * T) * norm_pdf(d1) gamma_denominator = S * vol * math.sqrt(T) gamma = gamma_numerator / gamma_denominator expected_zomma = (d1 * d2 - 1) * gamma / vol self.assertAlmostEqual(zomma, expected_zomma, places=6) def test_zomma_as_volatility_changes(self): # Test how zomma changes as volatility changes S, K, T, r, q = 100, 100, 1, 0.05, 0.02 # Calculate zomma at different volatility levels zomma_low_vol = calculate_zomma_value(S, K, T, r, q, 0.1) zomma_mid_vol = calculate_zomma_value(S, K, T, r, q, 0.2) zomma_high_vol = calculate_zomma_value(S, K, T, r, q, 0.3) # Zomma should be more negative as volatility decreases for ATM options self.assertLess(zomma_low_vol, zomma_mid_vol) self.assertLess(zomma_mid_vol, zomma_high_vol) def test_zomma_symmetry_around_atm(self): # Test the symmetry of zomma around the ATM point S_base, K, T, r, q, vol = 100, 100, 1, 0.05, 0.02, 0.2 # Calculate zomma at equidistant points from ATM S_up = 110 S_down = 90 zomma_up = calculate_zomma_value(S_up, K, T, r, q, vol) zomma_atm = calculate_zomma_value(S_base, K, T, r, q, vol) zomma_down = calculate_zomma_value(S_down, K, T, r, q, vol) # Zomma should be more negative at ATM than at equidistant OTM or ITM points self.assertLess(zomma_atm, zomma_up) self.assertLess(zomma_atm, zomma_down) def test_zomma_time_impact(self): # Test how time to maturity affects zomma S, K, r, q, vol = 100, 100, 0.05, 0.02, 0.2 # Calculate zomma at different times to maturity zomma_short = calculate_zomma_value(S, K, 0.25, r, q, vol) zomma_medium = calculate_zomma_value(S, K, 1, r, q, vol) zomma_long = calculate_zomma_value(S, K, 2, r, q, vol) # For ATM options, zomma typically becomes less negative as time increases self.assertLess(zomma_short, zomma_medium) self.assertLess(zomma_medium, zomma_long) def test_zomma_with_zero_volatility(self): # Test case for very low volatility S, K, T, r, q = 100, 100, 1, 0.05, 0.02 # Extremely low volatility should cause an error with self.assertRaises(ValueError): calculate_zomma_value(S, K, T, r, q, 0) if __name__ == '__main__': unittest.main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/walkingshamrock/black-scholes-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server