Skip to content

Commit 83edc8d

Browse files
Chaluvadisyurkevi
authored andcommitted
added financial examples
1 parent 6661cae commit 83edc8d

File tree

3 files changed

+253
-0
lines changed

3 files changed

+253
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#!/usr/bin/python
2+
3+
#######################################################
4+
# Copyright (c) 2024, ArrayFire
5+
# All rights reserved.
6+
#
7+
# This file is distributed under 3-clause BSD license.
8+
# The complete license agreement can be obtained at:
9+
# http://arrayfire.com/licenses/BSD-3-Clause
10+
########################################################
11+
12+
import math
13+
import sys
14+
from time import time
15+
16+
# TODO: Remove -1 from sync() after default value has been put in
17+
import arrayfire as af
18+
19+
sqrt2 = math.sqrt(2.0)
20+
21+
22+
def cnd(x):
23+
temp = x > 0
24+
return temp * (0.5 + af.erf(x / sqrt2) / 2) + (1 - temp) * (0.5 - af.erf((-x) / sqrt2) / 2)
25+
26+
27+
def black_scholes(S, X, R, V, T):
28+
# S = Underlying stock price
29+
# X = Strike Price
30+
# R = Risk free rate of interest
31+
# V = Volatility
32+
# T = Time to maturity
33+
34+
d1 = af.log(S / X)
35+
d1 = d1 + (R + (V * V) * 0.5) * T
36+
d1 = d1 / (V * af.sqrt(T))
37+
38+
d2 = d1 - (V * af.sqrt(T))
39+
cnd_d1 = cnd(d1)
40+
cnd_d2 = cnd(d2)
41+
42+
C = S * cnd_d1 - (X * af.exp((-R) * T) * cnd_d2)
43+
P = X * af.exp((-R) * T) * (1 - cnd_d2) - (S * (1 - cnd_d1))
44+
45+
return (C, P)
46+
47+
48+
if __name__ == "__main__":
49+
if len(sys.argv) > 1:
50+
af.set_device(int(sys.argv[1]))
51+
af.info()
52+
53+
M = 4000
54+
55+
S = af.randu((M, 1))
56+
X = af.randu((M, 1))
57+
R = af.randu((M, 1))
58+
V = af.randu((M, 1))
59+
T = af.randu((M, 1))
60+
61+
(C, P) = black_scholes(S, X, R, V, T)
62+
af.eval(C)
63+
af.eval(P)
64+
af.sync(-1)
65+
66+
num_iter = 100
67+
for N in range(50, 501, 50):
68+
S = af.randu((M, N))
69+
X = af.randu((M, N))
70+
R = af.randu((M, N))
71+
V = af.randu((M, N))
72+
T = af.randu((M, N))
73+
af.sync(-1)
74+
75+
print("Input data size: %d elements" % (M * N))
76+
77+
start = time()
78+
for i in range(num_iter):
79+
(C, P) = black_scholes(S, X, R, V, T)
80+
af.eval(C)
81+
af.eval(P)
82+
af.sync(-1)
83+
sec = (time() - start) / num_iter
84+
85+
print("Mean GPU Time: %0.6f ms\n\n" % (1000.0 * sec))

examples/financial/heston_model.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/usr/bin/python
2+
3+
##############################################################################################
4+
# Copyright (c) 2015, Michael Nowotny
5+
# All rights reserved.
6+
#
7+
# Redistribution and use in source and binary forms, with or without modification,
8+
# are permitted provided that the following conditions are met:
9+
#
10+
# 1. Redistributions of source code must retain the above copyright notice,
11+
# this list of conditions and the following disclaimer.
12+
#
13+
# 2. Redistributions in binary form must reproduce the above copyright notice,
14+
# this list of conditions and the following disclaimer in the documentation and/or other
15+
# materials provided with the distribution.
16+
#
17+
# 3. Neither the name of the copyright holder nor the names of its contributors may be used
18+
# to endorse or promote products derived from this software without specific
19+
# prior written permission.
20+
#
21+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24+
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25+
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27+
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32+
###############################################################################################
33+
34+
import math
35+
import time
36+
37+
import arrayfire as af
38+
39+
40+
def simulateHestonModel(T, N, R, mu, kappa, vBar, sigmaV, rho, x0, v0):
41+
42+
deltaT = T / (float)(N - 1)
43+
44+
x = [af.constant(x0, (R,)), af.constant(0, (R,))]
45+
v = [af.constant(v0, (R,)), af.constant(0, (R,))]
46+
47+
sqrtDeltaT = math.sqrt(deltaT)
48+
sqrtOneMinusRhoSquare = math.sqrt(1 - rho**2)
49+
50+
m = af.constant(0, (2,))
51+
m[0] = rho
52+
m[1] = sqrtOneMinusRhoSquare
53+
zeroArray = af.constant(0, (R, 1))
54+
55+
for t in range(1, N):
56+
tPrevious = (t + 1) % 2
57+
tCurrent = t % 2
58+
59+
dBt = af.randn((R, 2)) * sqrtDeltaT
60+
61+
vLag = af.maxof(v[tPrevious], zeroArray)
62+
sqrtVLag = af.sqrt(vLag)
63+
64+
x[tCurrent] = x[tPrevious] + (mu - 0.5 * vLag) * deltaT + sqrtVLag * dBt[:, 0]
65+
v[tCurrent] = vLag + kappa * (vBar - vLag) * deltaT + sigmaV * (sqrtVLag * af.matmul(dBt, m))
66+
67+
return (x[tCurrent], af.maxof(v[tCurrent], zeroArray))
68+
69+
70+
def main():
71+
T = 1
72+
nT = 20 * T
73+
R_first = 1000
74+
R = 5000000
75+
76+
x0 = 0 # initial log stock price
77+
v0 = 0.087**2 # initial volatility
78+
r = math.log(1.0319) # risk-free rate
79+
rho = -0.82 # instantaneous correlation between Brownian motions
80+
sigmaV = 0.14 # variance of volatility
81+
kappa = 3.46 # mean reversion speed
82+
vBar = 0.008 # mean variance
83+
k = math.log(0.95) # strike price
84+
85+
# first run
86+
(x, v) = simulateHestonModel(T, nT, R_first, r, kappa, vBar, sigmaV, rho, x0, v0)
87+
88+
# Price plain vanilla call option
89+
tic = time.time()
90+
(x, v) = simulateHestonModel(T, nT, R, r, kappa, vBar, sigmaV, rho, x0, v0)
91+
af.sync(-1)
92+
toc = time.time() - tic
93+
K = math.exp(k)
94+
zeroConstant = af.constant(0, (R,))
95+
C_CPU = math.exp(-r * T) * af.mean(af.maxof(af.exp(x) - K, zeroConstant))
96+
print("Time elapsed = {} secs".format(toc))
97+
print("Call price = {}".format(C_CPU))
98+
print(af.mean(v))
99+
100+
101+
if __name__ == "__main__":
102+
main()
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#!/usr/bin/python
2+
3+
#######################################################
4+
# Copyright (c) 2024, ArrayFire
5+
# All rights reserved.
6+
#
7+
# This file is distributed under 3-clause BSD license.
8+
# The complete license agreement can be obtained at:
9+
# http://arrayfire.com/licenses/BSD-3-Clause
10+
########################################################
11+
12+
import math
13+
import sys
14+
from time import time
15+
16+
import arrayfire as af
17+
18+
19+
def monte_carlo_options(N, K, t, vol, r, strike, steps, use_barrier=True, B=None, ty=af.float32):
20+
payoff = af.constant(0, (N, 1), dtype=ty)
21+
22+
dt = t / float(steps - 1)
23+
s = af.constant(strike, (N, 1), dtype=ty)
24+
25+
randmat = af.randn((N, steps - 1), dtype=ty)
26+
randmat = af.exp((r - (vol * vol * 0.5)) * dt + vol * math.sqrt(dt) * randmat)
27+
28+
S = af.product(af.join(1, s, randmat), 1)
29+
30+
if use_barrier:
31+
S = S * af.all_true(S < B, 1)
32+
33+
payoff = af.maxof(0, S - K)
34+
return af.mean(payoff) * math.exp(-r * t)
35+
36+
37+
def monte_carlo_simulate(N, use_barrier, num_iter=10):
38+
steps = 180
39+
stock_price = 100.0
40+
maturity = 0.5
41+
volatility = 0.3
42+
rate = 0.01
43+
strike = 100
44+
barrier = 115.0
45+
46+
start = time()
47+
for i in range(num_iter):
48+
monte_carlo_options(N, stock_price, maturity, volatility, rate, strike, steps, use_barrier, barrier)
49+
50+
return (time() - start) / num_iter
51+
52+
53+
if __name__ == "__main__":
54+
if len(sys.argv) > 1:
55+
af.set_device(int(sys.argv[1]))
56+
af.info()
57+
58+
monte_carlo_simulate(1000, use_barrier=False)
59+
monte_carlo_simulate(1000, use_barrier=True)
60+
af.sync(-1)
61+
62+
for n in range(10000, 100001, 10000):
63+
print(
64+
"Time for %7d paths - vanilla method: %4.3f ms, barrier method: % 4.3f ms\n"
65+
% (n, 1000 * monte_carlo_simulate(n, False, 100), 1000 * monte_carlo_simulate(n, True, 100))
66+
)

0 commit comments

Comments
 (0)