Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
added financial examples
  • Loading branch information
Chaluvadi authored and sakchal committed Apr 25, 2024
commit 5e21337a31a36b3a18d5d265ccf9c2a2b8e970c9
85 changes: 85 additions & 0 deletions examples/financial/black_scholes_options.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/python

#######################################################
# Copyright (c) 2024, ArrayFire
# All rights reserved.
#
# This file is distributed under 3-clause BSD license.
# The complete license agreement can be obtained at:
# http://arrayfire.com/licenses/BSD-3-Clause
########################################################

import math
import sys
from time import time

# TODO: Remove -1 from sync() after default value has been put in
import arrayfire as af

sqrt2 = math.sqrt(2.0)


def cnd(x):
temp = x > 0
return temp * (0.5 + af.erf(x / sqrt2) / 2) + (1 - temp) * (0.5 - af.erf((-x) / sqrt2) / 2)


def black_scholes(S, X, R, V, T):
# S = Underlying stock price
# X = Strike Price
# R = Risk free rate of interest
# V = Volatility
# T = Time to maturity

d1 = af.log(S / X)
d1 = d1 + (R + (V * V) * 0.5) * T
d1 = d1 / (V * af.sqrt(T))

d2 = d1 - (V * af.sqrt(T))
cnd_d1 = cnd(d1)
cnd_d2 = cnd(d2)

C = S * cnd_d1 - (X * af.exp((-R) * T) * cnd_d2)
P = X * af.exp((-R) * T) * (1 - cnd_d2) - (S * (1 - cnd_d1))

return (C, P)


if __name__ == "__main__":
if len(sys.argv) > 1:
af.set_device(int(sys.argv[1]))
af.info()

M = 4000

S = af.randu((M, 1))
X = af.randu((M, 1))
R = af.randu((M, 1))
V = af.randu((M, 1))
T = af.randu((M, 1))

(C, P) = black_scholes(S, X, R, V, T)
af.eval(C)
af.eval(P)
af.sync(-1)

num_iter = 100
for N in range(50, 501, 50):
S = af.randu((M, N))
X = af.randu((M, N))
R = af.randu((M, N))
V = af.randu((M, N))
T = af.randu((M, N))
af.sync(-1)

print("Input data size: %d elements" % (M * N))

start = time()
for i in range(num_iter):
(C, P) = black_scholes(S, X, R, V, T)
af.eval(C)
af.eval(P)
af.sync(-1)
sec = (time() - start) / num_iter

print("Mean GPU Time: %0.6f ms\n\n" % (1000.0 * sec))
102 changes: 102 additions & 0 deletions examples/financial/heston_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/usr/bin/python

##############################################################################################
# Copyright (c) 2015, Michael Nowotny
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used
# to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
###############################################################################################

import math
import time

import arrayfire as af


def simulateHestonModel(T, N, R, mu, kappa, vBar, sigmaV, rho, x0, v0):

deltaT = T / (float)(N - 1)

x = [af.constant(x0, (R,)), af.constant(0, (R,))]
v = [af.constant(v0, (R,)), af.constant(0, (R,))]

sqrtDeltaT = math.sqrt(deltaT)
sqrtOneMinusRhoSquare = math.sqrt(1 - rho**2)

m = af.constant(0, (2,))
m[0] = rho
m[1] = sqrtOneMinusRhoSquare
zeroArray = af.constant(0, (R, 1))

for t in range(1, N):
tPrevious = (t + 1) % 2
tCurrent = t % 2

dBt = af.randn((R, 2)) * sqrtDeltaT

vLag = af.maxof(v[tPrevious], zeroArray)
sqrtVLag = af.sqrt(vLag)

x[tCurrent] = x[tPrevious] + (mu - 0.5 * vLag) * deltaT + sqrtVLag * dBt[:, 0]
v[tCurrent] = vLag + kappa * (vBar - vLag) * deltaT + sigmaV * (sqrtVLag * af.matmul(dBt, m))

return (x[tCurrent], af.maxof(v[tCurrent], zeroArray))


def main():
T = 1
nT = 20 * T
R_first = 1000
R = 5000000

x0 = 0 # initial log stock price
v0 = 0.087**2 # initial volatility
r = math.log(1.0319) # risk-free rate
rho = -0.82 # instantaneous correlation between Brownian motions
sigmaV = 0.14 # variance of volatility
kappa = 3.46 # mean reversion speed
vBar = 0.008 # mean variance
k = math.log(0.95) # strike price

# first run
(x, v) = simulateHestonModel(T, nT, R_first, r, kappa, vBar, sigmaV, rho, x0, v0)

# Price plain vanilla call option
tic = time.time()
(x, v) = simulateHestonModel(T, nT, R, r, kappa, vBar, sigmaV, rho, x0, v0)
af.sync(-1)
toc = time.time() - tic
K = math.exp(k)
zeroConstant = af.constant(0, (R,))
C_CPU = math.exp(-r * T) * af.mean(af.maxof(af.exp(x) - K, zeroConstant))
print("Time elapsed = {} secs".format(toc))
print("Call price = {}".format(C_CPU))
print(af.mean(v))


if __name__ == "__main__":
main()
66 changes: 66 additions & 0 deletions examples/financial/monte_carlo_options.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/python

#######################################################
# Copyright (c) 2024, ArrayFire
# All rights reserved.
#
# This file is distributed under 3-clause BSD license.
# The complete license agreement can be obtained at:
# http://arrayfire.com/licenses/BSD-3-Clause
########################################################

import math
import sys
from time import time

import arrayfire as af


def monte_carlo_options(N, K, t, vol, r, strike, steps, use_barrier=True, B=None, ty=af.float32):
payoff = af.constant(0, (N, 1), dtype=ty)

dt = t / float(steps - 1)
s = af.constant(strike, (N, 1), dtype=ty)

randmat = af.randn((N, steps - 1), dtype=ty)
randmat = af.exp((r - (vol * vol * 0.5)) * dt + vol * math.sqrt(dt) * randmat)

S = af.product(af.join(1, s, randmat), 1)

if use_barrier:
S = S * af.all_true(S < B, 1)

payoff = af.maxof(0, S - K)
return af.mean(payoff) * math.exp(-r * t)


def monte_carlo_simulate(N, use_barrier, num_iter=10):
steps = 180
stock_price = 100.0
maturity = 0.5
volatility = 0.3
rate = 0.01
strike = 100
barrier = 115.0

start = time()
for i in range(num_iter):
monte_carlo_options(N, stock_price, maturity, volatility, rate, strike, steps, use_barrier, barrier)

return (time() - start) / num_iter


if __name__ == "__main__":
if len(sys.argv) > 1:
af.set_device(int(sys.argv[1]))
af.info()

monte_carlo_simulate(1000, use_barrier=False)
monte_carlo_simulate(1000, use_barrier=True)
af.sync(-1)

for n in range(10000, 100001, 10000):
print(
"Time for %7d paths - vanilla method: %4.3f ms, barrier method: % 4.3f ms\n"
% (n, 1000 * monte_carlo_simulate(n, False, 100), 1000 * monte_carlo_simulate(n, True, 100))
)