Black Scholes function with vector inputs in Matlab - matlab

I'm trying to write a function in Matlab that calculates the Call price using the Black Scholes formula with vector inputs. I have so far:
function [C] = BlackScholesCall(S,K,t,r,sigma)
%This function calculates the call price per Black-Scholes equation
%INPUT S ... stock price at time 0
% K ... strike price
% r ... interest rate
% sigma ... volatility of the stock price measured as annual standard deviation
% t ... duration in years
%OUTPUT C ... call price
%USAGE BlackScholesCall(S,K,t,r,sigma)
for l = 1:length(K)
for z = 1:length(t)
d1 = (log(S/K(l)) + (r + 0.5*sigma^2)*t(z))/(sigma*sqrt(t(z)));
d2 = d1 - sigma*sqrt(t(z));
N1 = 0.5*(1+erf(d1/sqrt(2)));
N2 = 0.5*(1+erf(d2/sqrt(2)));
C(l) = S*N1-K(l)*exp(-r*t(z))*N2;
end
end
end
F.e. the code to call my function would be
S = 20
K = 16:21
t = 1:1:5
r = 0.02
sigma = 0.25
C = BlackScholesCall(S, K, t, r, sigma)
But when I compare this with the results of the blsprice function in Matlab, I get different results. I suspect there might be something wrong with the way I did the loop?

You are getting the same results as,
>> blsprice(S,K,r,t(end),sigma)
ans =
7.1509 6.6114 6.1092 5.6427 5.2102 4.8097
This is because by using C(l) = ... you are overwriting each element of C numel(t) times, and hence only storing/returning the last calculated values for each value of z.
At a minimum you need to use,
%C(l) = S*N1-K(l)*exp(-r*t(z))*N2;
C(z,l) = S*N1-K(l)*exp(-r*t(z))*N2;
But you should also pre-allocate your output matrix. That is, before either of the loops, you should add
C = nan(numel(K),numel(t));
Finally, you should note that you don't need to use any loops at all,
[Kmat,tmat] = meshgrid(K,t);
d1 = (log(S./Kmat) + (r + 0.5*sigma^2)*tmat)./(sigma*sqrt(tmat));
d2 = d1 - sigma*sqrt(tmat);
N1 = 0.5*(1+erf(d1/sqrt(2)));
N2 = 0.5*(1+erf(d2/sqrt(2)));
C = S*N1-Kmat.*exp(-r*tmat).*N2;

An R version could be the following.
BlackScholesCall <- function(S, K, tt, r, sigma){
f <- function(.K, .tt){
d1 <- (log(S/.K) + (r + 0.5*sigma^2)*.tt)/(sigma*sqrt(.tt))
d2 <- d1 - sigma*sqrt(.tt)
S*pnorm(d1) - .K*exp(-r*.tt)*pnorm(d2)
}
m <- length(K)
n <- length(tt)
o <- outer(K, tt, f)
last <- if(m > n) o[n:m, n] else o[m, m:n]
c(diag(o), last)
}
BlackScholesCall(S, K, tt, r, sigma)
#[1] 4.703480 4.783563 4.914990 5.059922 5.210161 5.210161 4.809748

Related

How to apply a function over a matrix and simultaneously pass parameters?

I have a matrix e.g. as follows:
N = magic(100);
I want to apply a function on each column and save its output in another matrix.
Here is my function
function z = nikfoo(y, lambda, p)
m = length(y);
D = diff(speye(m), 2);
w = ones(m, 1);
for it = 1:10
W = spdiags(w, 0, m, m);
C = chol(W + lambda * D' * D);
z = C \ (C' \ (w .* y));
w = p * (y > z) + (1 - p) * (y < z);
end
At first I tried to make a matrix the same size as my data
% I take the size of my matrix
[a, b] = size(N);
% make the same size matrix with zeros
corrNiki = zeros(a,b);
then I try to do it as follows
% I set the lambda as 1000 and p as 0.1
for i = 1:b
corrNiki(i) = nikfoo(N(i),1000,0.1);
end
So now I have these questions
how can I pass this function with the fixed lammda and p and save the results in corrNiki?
how can I also pass different values to the Lamda in a range and in P in a range and then save their outputs ?
for example
Lammda 1000 and P0.1 is saved in data1
Lammda 2000 and P0.01 is saved in data2
.
.
.

Mel-frequency function: error with matrix dimensions

I'm trying to make a prototype audio recognition system by following this link: http://www.ifp.illinois.edu/~minhdo/teaching/speaker_recognition/. It is quite straightforward so there is almost nothing to worry about. But my problem is with the mel-frequency function. Here is the code as provided on the website:
function m = melfb(p, n, fs)
% MELFB Determine matrix for a mel-spaced filterbank
%
% Inputs: p number of filters in filterbank
% n length of fft
% fs sample rate in Hz
%
% Outputs: x a (sparse) matrix containing the filterbank amplitudes
% size(x) = [p, 1+floor(n/2)]
%
% Usage: For example, to compute the mel-scale spectrum of a
% colum-vector signal s, with length n and sample rate fs:
%
% f = fft(s);
% m = melfb(p, n, fs);
% n2 = 1 + floor(n/2);
% z = m * abs(f(1:n2)).^2;
%
% z would contain p samples of the desired mel-scale spectrum
%
% To plot filterbanks e.g.:
%
% plot(linspace(0, (12500/2), 129), melfb(20, 256, 12500)'),
% title('Mel-spaced filterbank'), xlabel('Frequency (Hz)');
f0 = 700 / fs;
fn2 = floor(n/2);
lr = log(1 + 0.5/f0) / (p+1);
% convert to fft bin numbers with 0 for DC term
bl = n * (f0 * (exp([0 1 p p+1] * lr) - 1));
b1 = floor(bl(1)) + 1;
b2 = ceil(bl(2));
b3 = floor(bl(3));
b4 = min(fn2, ceil(bl(4))) - 1;
pf = log(1 + (b1:b4)/n/f0) / lr;
fp = floor(pf);
pm = pf - fp;
r = [fp(b2:b4) 1+fp(1:b3)];
c = [b2:b4 1:b3] + 1;
v = 2 * [1-pm(b2:b4) pm(1:b3)];
m = sparse(r, c, v, p, 1+fn2);
But it gave me an error:
Error using * Inner matrix dimensions must agree.
Error in MFFC (line 17) z = m * abs(f(1:n2)).^2;
When I include these 2 lines just before line 17:
size(m)
size(abs(f(1:n2)).^2)
It gave me :
ans =
20 65
ans =
1 65
So should I transpose the second matrix? Or should I interpret this as an row-wise multiplication and modify the code?
Edit: Here is the main function (I simply run MFCC()):
function result = MFFC()
[y Fs] = audioread('s1.wav');
% sound(y,Fs)
Frames = Frame_Blocking(y,128);
Windowed = Windowing(Frames);
spectrum = FFT_After_Windowing(Windowed);
%imagesc(mag2db(abs(spectrum)))
p = 20;
S = size(spectrum);
n = S(2);
f = spectrum;
m = melfb(p, n, Fs);
n2 = 1 + floor(n/2);
size(m)
size(abs(f(1:n2)).^2)
z = m * abs(f(1:n2)).^2;
result = z;
And here are the auxiliary functions:
function f = Frame_Blocking(y,N)
% Parameters: M = 100, N = 256
% Default : M = 100; N = 256;
M = fix(N/3);
Frames = [];
first = 1; last = N;
len = length(y);
while last <= len
Frames = [Frames; y(first:last)'];
first = first + M;
last = last + M;
end;
if last < len
first = first + M;
Frames = [Frames; y(first : len)];
end
f = Frames;
function f = Windowing(Frames)
S = size(Frames);
N = S(2);
M = S(1);
Windowed = zeros(M,N);
nn = 1:N;
wn = 0.54 - 0.46*cos(2*pi/(N-1)*(nn-1));
for ii = 1:M
Windowed(ii,:) = Frames(ii,:).*wn;
end;
f = Windowed;
function f = FFT_After_Windowing(Windowed)
spectrum = fft(Windowed);
f = spectrum;
Transpose s or transpose the resulting f (it's just a matter of convention).
There is nothing wrong with the melfb function you are using, merely with the dimensions of the signal in the example you are trying to run (in the commented lines 14-17).
% f = fft(s);
% m = melfb(p, n, fs);
% n2 = 1 + floor(n/2);
% z = m * abs(f(1:n2)).^2;
The example assumes that you are using a "colum-vector signal s". From the size of your Fourier transformed f (done via fft which respects the input signal dimensions) your input signal s is a row-vector signal.
The part that gives you the error is the actual filtering operation that requires multiplying a p x n2 matrix with a n2 x 1 column-vector (i.e., each filter's response is multiplied pointwise with the Fourier of the input signal). Since your input s is 1 x n, your f will be 1 x n and the final matrix to vector multiplication for z will give an error.
Thanks to gevang's anwer, I was able to find out my mistake. Here is how I modified the code:
function result = MFFC()
[y Fs] = audioread('s2.wav');
% sound(y,Fs)
Frames = Frame_Blocking(y,128);
Windowed = Windowing(Frames);
%spectrum = FFT_After_Windowing(Windowed');
%imagesc(mag2db(abs(spectrum)))
p = 20;
%S = size(spectrum);
%n = S(2);
%f = spectrum;
S1 = size(Windowed);
n = S1(2);
n2 = 1 + floor(n/2);
%z = zeros(S1(1),n2);
z = zeros(20,S1(1));
for ii=1: S1(1)
s = (FFT_After_Windowing(Windowed(ii,:)'));
f = fft(s);
m = melfb(p,n,Fs);
% n2 = 1 + floor(n/2);
z(:,ii) = m * abs(f(1:n2)).^2;
end;
%f = FFT_After_Windowing(Windowed');
%S = size(f);
%n = S(2);
%size(f)
%m = melfb(p, n, Fs);
%n2 = 1 + floor(n/2);
%size(m)
%size(abs(f(1:n2)).^2)
%z = m * abs(f(1:n2)).^2;
result = z;
As you can see, I naively assumed that the function deals with row-wise matrices, but in fact it deals with column vectors (and maybe column-wise matrices). So I iterate through each column of the input matrix and then combine the results.
But I don't think this is efficient and vectorized code. Also I still can't figure out how to do column-wise operations on the input matrix (Windowed - after the windowing step), instead of using a loop.

To handle rational number without losing accuracy of computation in Matlab?

I want to use this rational number in computations without losing the accuracy of the picture in Matlab:
f = 359.0 + 16241/16250.0
I think storing, for instance by f = uint64(359.0 + 16241/16250.0) loses accuracy, seen as 360 in Matlab.
I think the best way to handle the thing is never to store the value but to store its factors like
% f = a + b/c
a = 359
b = 16241
c = 16250
and then doing computation by the variables a, b and c, and giving the result as a picture.
Is this a good way to maintain the accuracy?
As you suggest, if you absolutely don't want to lose accuracy when storing a rational number, the best solution probably is to store the number in terms of its integer components.
Instead of your three components (f = a + b/c) you can reduce the reprentation to two components: f = n/d. Thus each rational number would be defined (and stored) as the two-component integer vector [n d]. For example, the number f in your example corresponds to n=5849991 and d=16250.
To simplify handling rational numbers stored this way, you could define a helper function which converts from the [n d] representation to n/d before applyling the desired operation:
useInteger = #(x, nd, fun) fun(x,double(nd(1))/double(nd(2)));
Then
>> x = sqrt(pi);
>> nd = int64([5849991 16250]);
>> useInteger(x, nd, #plus)
ans =
361.7719
>> useInteger(x, nd, #times)
ans =
638.0824
If you want to achieve arbitrarily high precision in computations, you should consider using variable-precision arithmetic (vpa) with string arguments. With that approach you get to specify how many digits you want:
>> vpa('sqrt(pi)*5849991/16250', 50)
ans =
638.08240465923757600307902117159072301901656248436
Perhaps create a Rational class and define the needed operations (plus,minus,times,etc.). Start with something like this:
Rational.m
classdef Rational
properties
n;
d;
end
methods
function obj = Rational(n,d)
GCD = gcd(n,d);
obj.n = n./GCD;
obj.d = d./GCD;
end
function d = dec(obj)
d = double(obj.n)/double(obj.d);
end
% X .* Y
function R = times(X,Y)
chkxy(X,Y);
if isnumeric(X),
N = X .* Y.n; D = Y.d;
elseif isnumeric(Y),
N = X.n .* Y; D = X.d;
else
N = X.n .* Y.n; D = X.d .* Y.d;
end
R = Rational(N,D);
end
% X * Y
function R = mtimes(X,Y)
R = times(X,Y);
end
% X ./ Y
function R = rdivide(X,Y)
if isnumeric(Y),
y = Rational(1,Y);
else
y = Rational(Y.d,Y.n);
end
R = times(X,y);
end
% X / Y
function R = mrdivide(X,Y)
R = rdivide(X,Y);
end
% X + Y
function R = plus(X,Y)
chkxy(X,Y);
if isnumeric(X),
N = X.*Y.d + Y.n; D = Y.d;
elseif isnumeric(Y),
N = Y.*X.d + X.n; D = X.d;
else
D = lcm(X.d,Y.d);
N = sum([X.n Y.n].*(D./[X.d Y.d]));
end
R = Rational(N,D);
end
% X - Y
function R = minus(X,Y)
R = plus(X,-Y);
end
% -X
function R = uminus(X)
R = Rational(-X.n,X.d);
end
function chkxy(X,Y)
if (~isa(X, 'Rational') && ~isnumeric(X)) || ...
(~isa(Y, 'Rational') && ~isnumeric(Y)),
error('X and Y must be Rational or numeric.');
end
end
end
end
Examples
Construct objects:
>> clear all % reset class definition
>> r1 = Rational(int64(1),int64(2))
r1 =
Rational with properties:
n: 1
d: 2
>> r2 = Rational(int64(3),int64(4))
r2 =
Rational with properties:
n: 3
d: 4
Add and subtract:
>> r1+r2
ans =
Rational with properties:
n: 5
d: 4
>> r1-r2
ans =
Rational with properties:
n: -1
d: 4
Multiply and divide:
>> r1*r2
ans =
Rational with properties:
n: 3
d: 8
>> r1/r2
ans =
Rational with properties:
n: 2
d: 3
Get decimal value:
>> r12 = r1/r2; % 2/3 ((1/2)/(3/4))
>> f = r12.dec
f =
0.6667
Extension to LuisMendo's answer
I got this as the error for your suggestion by py
>>> a = 638.08240465923757600307902117159072301901656248436059
>>> a
638.0824046592376 % do not know if Python is computing here with exact number
>>> b = 638.0824
>>> ave = abs(b+a)/2
>>> diff = abs(b-a)
>>> ave = abs(b+a)/2
>>> diff/ave
7.30193709165014e-09
which is more than the proposed error storing error above.
I run in WolframAlpha
x = sqrt(pi)
x*5849991/16250
and get
509.11609919757198016211937362635174599076143654820109
I am not sure if this is what you meant in your comment of your answer.
Extension to chappjc's answer.
I have now
[B,T,F] = tfrwv(data1, 1:length(data1), length(data1)); % here F double
fs = Rational(uint64(5849991), uint64(16250));
t = 1/fs;
imagesc(T*t, F*fs, B);
I run it
Error using .*
Integers can only be combined with integers of
the same class, or scalar doubles.
Error in .* (line 23)
N = X .* Y.n; D = Y.d;
Error in * (line 34)
R = times(X,Y);
How can you multiply in this class the double with Rational?

How to deal with recursive loop in MATLAB?

I am trying to compute x1^i * x2^j * x3^k * ......
This is my code so far:
for l = 1:N
f = 1;
for i = 0:2
for j = 0:2-i
for k = 0:2-j
for m = 0:2-k
g(l,f) = x1(l)^i*x2(l)^j*x3(l)^k*x4(l)^m;
f = f+1;
end
end
end
end
end
How can I do this easier or without a loop?
I do not have MATLAB on hand here, but what I'd do is make a vector X = [x1, x2, ..., xn] of bases and a vector P = [i, j, k, ..., z] of powers, and then compute prod(power(X, P)).
power() does an element-wise power function, and prod takes the product of every element in the vector.

Cannot understand this MATLAB syntax?

for i=0:255
m(i+1)=sum((0:i)'.*p(1:i+1)); end
What is happening can anyone explain. p is an array of size 256 elements same as m.
p = (0:255)';
m = zeros(1,256);
for i=0:255
m(i+1)=sum((0:i)'.*p(1:i+1));
end
m[i+1] contains the scalar product of [0,1,2,..,i] with (p[1],...,p[i+1])
You can write it as :
p = (0:255);
m = zeros(1,256);
for i=0:255
m(i+1)=sum((0:i).*p(1:i+1));
end
Or:
p = (0:255);
m = zeros(1,256);
for i=0:255
m(i+1)=(0:i)*p(1:i+1)';
end
In case you don't recall, that is the definition of scalar product
Whatever the p is, you can calculate m by:
dm = (0 : length(p) - 1)' .* p(:); % process as column vector
m = cumsum(dm);
Hint: write the formula for m[n], then for m[n+1], then subtract to get the formula:
m[n+1] - m[n] = (n - 1) * p[n]
and this is dm.