-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathblack_scholes_test.py
99 lines (83 loc) · 3.55 KB
/
black_scholes_test.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import asyncio
import os
import random
import pytest
from py_vollib.black_scholes import black_scholes
from starkware.starknet.compiler.compile import compile_starknet_files
from starkware.starknet.testing.starknet import Starknet
# The path to the contract source code.
CONTRACT_FILE = os.path.join(
os.path.dirname(__file__), "black_scholes_contract.cairo")
# Precision used in the black scholes Cairo library.
UNIT = 1e27
def get_precise(value):
return int(UNIT * value)
# Checks accuracy of the option price (within $0.01).
def check_price(got, expected):
assert(abs(got - expected) < 0.01)
# Returns a random tuple of (t_annualised, volatility, spot, strike, rate)
def get_random_test_input():
# Random time from 10 minutes to 5 years.
t_annualised = random.uniform(1/52560.0, 5)
# Random volatility from 0.01% to 50%.
volatility = random.uniform(0.0001, 0.5)
# Random spot price between $0.01 and $1000
spot = random.uniform(0.01, 1000)
# Random strike price between $0.01 and $1000
strike = random.uniform(0.01, 1000)
# Random interest rate between 0.01% and 50%
rate = random.uniform(0.0001, 0.5)
return (t_annualised, volatility, spot, strike, rate)
@pytest.mark.asyncio
async def test_randomized_black_scholes_options_prices():
# Create a new Starknet class that simulates the StarkNet system.
starknet = await Starknet.empty()
# Deploy the contract.
contract_def = compile_starknet_files(files=[CONTRACT_FILE],
disable_hint_validation=True)
contract = await starknet.deploy(
contract_def=contract_def,
)
# Number of random tests to run.
ITERATIONS = 10
# List of float tuple (t_annualised, volatility, spot, strike, rate).
test_inputs = []
# Query the contract for options prices.
tasks = []
for i in range(ITERATIONS):
test_input = get_random_test_input()
test_inputs.append(test_input)
tasks.append(contract.option_prices(
t_annualised=get_precise(test_input[0]),
volatility=get_precise(test_input[1]),
spot=get_precise(test_input[2]),
strike=get_precise(test_input[3]),
rate=get_precise(test_input[4])).call())
# Compare call and put prices with the python black scholes library.
print()
execution_infos = await asyncio.gather(*tasks)
for i, execution_info in enumerate(execution_infos):
(got_call, got_put) = (execution_info.result.call_price/UNIT,
execution_info.result.put_price/UNIT)
(exp_call, exp_put) = (
black_scholes('c', test_inputs[i][2], test_inputs[i][3],
test_inputs[i][0], test_inputs[i][4],
test_inputs[i][1]),
black_scholes('p', test_inputs[i][2], test_inputs[i][3],
test_inputs[i][0], test_inputs[i][4],
test_inputs[i][1]))
print()
print('Input %d:' % i)
print('t_annualised: %.5f years' % test_inputs[i][0])
print('volatility: %.5f%%' % (100 * test_inputs[i][1]))
print('spot price: $%.5f' % test_inputs[i][2])
print('strike price: $%.5f' % test_inputs[i][3])
print('interest rate: %.5f%%' % (100 * test_inputs[i][4]))
print()
print('Result %d:' % i)
print('Computed call price: $%0.5f, Expected call price: $%0.5f' % (
got_call, exp_call))
print('Computed put price: $%0.5f, Expected put price: $%0.5f' % (
got_put, exp_put))
check_price(got_call, exp_call)
check_price(got_put, exp_put)