How do I use eps in this situation where I am taking differences of cumulative sums - matlab

First, the data:
orig = reshape([0.0000000000000000 0.3480000000000000 0.7570000000000000 1.3009999999999999 2.8300000000000001 4.7519999999999998 5.2660000000000000 5.8120000000000003 14.3360000000000000 15.3390000000000000 ],[10 1])
change = reshape([0.0000000000000000 0.3480000000000000 0.0000000000000000 0.9530000000000000 1.5290000000000001 1.9219999999999997 0.5140000000000002 0.5460000000000003 0.0000000000000000 9.5270000000000010 ],[10 1])
change = cumsum(change)
orig is a vector of seconds elapsed. change is a vector derived by taking differences between (some) elements of orig. The cumulative sum of change has some elements actually equal to the corresponding element in orig.
However, due to precision issues:
diff = orig - change
gives
diff =
0
0
0.409
0
0
0
0
0
8.524
-1.77635683940025e-15
It seems that if I run the following command:
diff(abs(diff) <= eps(orig)) = 0
then this sets entries which should be zero, but are not due to precision issues, to be zero.
My question is, is this the correct way to do it? Why is the comparison <= instead of <? Should the statement be:
diff(abs(diff) < k*eps(orig)) = 0
for some k > 1 to give some tolerance? If so, how would one pick k?
In case it is necessary to know how change is derived from orig, the following alternate example also shows this behaviour:
orig = reshape([0.0000000000000000 0.3480000000000000 0.7570000000000000 1.3009999999999999 2.8300000000000001 4.7519999999999998 5.2660000000000000 5.8120000000000003 14.3360000000000000 15.3390000000000000 ],[10 1])
change = orig - [0; orig(1:end-1)]
change = cumsum(change)
diff = orig - change

The following statement will be true only if the "almost zero" happens because 1 bit is offseted.
abs(diff) <= eps(orig)
1 bit is a ridiculously high precision to ask, a precision that most likely you can not achieve. Generally, you need to define your treshold yourself, such as
abs(diff) <= 1e-12
You also ask how to choose this value. Answer: there is no way we can tell you that. Its algorithm, application, unit, computer, [...] specific.
You are computing distance between particles? Maybe you need a smaller tolerance. You are doing economic profit calculus? 1e-12 is then a decimal you won't get in cash, for sure. Use 1e-4 instead. Or are you using an algorithm that does numerical approximations? Then you need a higher tolerance. How much tolerance you are OK with is, and will always be, a user choice.
Note: you need to be aware of the types you are using to set this minimum threshold right. MATLAB uses double as default, but if you are using other types, them this threshold is too strict. As an alternative, you can use
abs(diff) <= 100*eps(class(diff))
If your data type is not fixed/known.

Related

Matlab standard deviation - treat vector as probabilities, not values

I have a vector in Matlab that looks something like:
vect = 0
100
300
500
700
1000
500
300
200
0
When normalised, each value should indicate the probability of a certain value, and my values are just 1 to 10 (i.e. 0% chance of 1, 100/sum(vect) chance of 2, etc).
How do I work out statistics on the value (in particular standard deviation)..? If I do mean(vect), I just end up with 360, and I get a similarly large value for standard deviation. The mean value should, of course, be around 5. I'm sure it wouldn't be too hard to code up manually at all, but there must be a way of doing this directly in Matlab, so I figured I'd ask!
I am not really sure if matlab have any built in function for this, but it is no big deal. Both are one liners anyway
vect = [0; 100; 300; 500; 700; 1000; 500; 300; 200; 0];
prob = vect./sum(vect);
val = [1:10].';
meanVal = sum(prob.*val);
stDev = sqrt( sum( prob.*val.^2 ) -sum(prob.*val)^2 );
EDIT:
There are two functions that does this. They are called mean and std as well. But they take a probability distribution object instead.
If you call stem(vect) you'll see that vect is the probability density function of a normally distributed variable, hence you can fit a normal distribution to vect without normalization
x = (1:length(vect))';
pdf = fitdist(x, 'normal', 'freq', vect);
The result has an average value of 5.63889 and a standard deviation of 1.66944.

why one number is larger than a identical number in Matlab?

I have a program in which
e=0.01;
test3=Ask(1,2)-Bid(1,2);
(Bid and Ask are both matrices generated by a for loop).
I know that sometimes test3 could equal to e, but matlab gave me this:
>>test3
e
test3==e
test3>e
test3 =
0.0100
e =
0.0100
ans =
0
ans =
1
What's wrong with it? Thank you!
EDIT: I tried format long and then I got
Ask(1,2) =
8.620000000000001
Bid(1,2) =
8.609999999999999
test3 =
0.010000000000002
no wonder I got it wrong. But actually I've already use price=roundn(r*v,-2) and both Ask(1,2) and Bid(1,2) equal to some price so they should have two decimal places only. What can I do now if I want to round them to exactly two decimal places? Thanks again!
In general, roundoff error makes it difficult to ever compare numbers in floating point.
0.1 is a nice decimal number 1/10, but stored on a computer in binary it is a repeating fraction and not stored exactly.
So just for example:
x = 0.2;
y = 0.1 + 0.1;
x == y
will not be true.
[Well, unfortunately, as rwong points out below, this actually isn't true. I should have tried it! Octave is being a bit too smart for me at this hour. Still, in general, there will be roundoff!]
Sometimes the error will be big enough to see in the 16th digit, which is why you got the comment to try format long. But sometimes it might not be visible. The bottom line is:
NEVER USE == for two decimal numbers. It is almost always false, and usually that's meaningless.
what you want is to test if two numbers are very close to each other, which is:
abs(x-y) < 0.00001
for some small limit.
If test3 = 0.01000000000000001 or some such and e = 0.01 then you are likely to get this sort of result what happens when you print test3-e will give you a clue - this is why in the safety critical field float == float is always something that raises an alarm bell with auditors.

why am I getting imaginary numbers instead of a simple answer

this is just part of the code that matters and needs to be fixed. I don't know what i'm doing wrong here. all the variables are simple numbers, it's true that one is needed for that other, but there shouldn't be anything wrong with that. the answer for which I'm getting imaginary numbers is supposed to be part of a loop, so it's important I get it right. please ignore the variables that are not needed, as i just wrote a part of the code
the answer i get is:
KrInitialFirstPart = 0.000000000000000e+00 - 1.466747615972368e+05i
clear all;
clc;
% the initial position components
rInitial= 10; %kpc
zInitial= 0; %kpc
% the initial velocity components
vrInitial= 0; %km/s
vzInitial= 150; %tangential velocity component
vtInitial= 150; %not used
% the height
h= rInitial*vzInitial; %angulan momentum constant
tInitial=0;
Dt=1e-3;
e=0.99;
pc=11613.5;
KrInitialFirstPart= -4*pi*pc*sqrt( 1-(e^2) / (e^3) )*rInitial
format long
Here
sqrt( 1-(e^2) / (e^3) )
you have here
e=0.99;
so e < 1 and so e^3 is less than e^2.
Therefore
(e^2)/(e^3) > 1.
The division operation binds tighter than (i.e is evaluated ahead of) the subtraction so you are taking a square root of a negative number. Hence the imaginary component in your result.
Perhaps you require
sqrt( (1-(e^2)) / (e^3) )
which is guaranteed to yield a real number result since
1 - e^2 > 0
for your specified e

Implied Volatility in Matlab

I'm trying to calculate the implied volatility using the Black-Scholes formula in Matlab (2012b), but somehow have problems with some strike prices.
For instance blsimpv(1558,1440,0.0024,(1/12),116.4) will return NaN.
I thought it probably would be some problem with the function and therefore searched the internet for some other matlab scripts and customized it to my custom needs, but unfortunately I'm still not able to return a valid implied volatility.
function sigma=impvol(C,S,K,r,T)
%F=S*exp((r).*T);
%G=C.*exp(r.*T);
%alpha=log(F./K)./sqrt(T);
%beta=0.5*sqrt(T);
%a=beta.*(F+K);
%b=sqrt(2*pi)*(0.5*(F-K)-G);
%c=alpha.*(F-K);
%disc=max(0,b.^2-4*a.*c);
%sigma0=(-b+sqrt(disc))./(2*a);
i=-1000;
while i<=5000
sigma0=i/1000;
sigma=NewtonMethod(sigma0);
if sigma<=10 && sigma>=-10
fprintf('This is sigma %f',sigma)
end
i=i+1;
end
end
function s1=NewtonMethod(s0)
s1=s0;
count=0;
f=#(x) call(S,K,r,x,T)-C;
fprime=#(x) call_vega(S,K,r,x,T);
max_count=1e4;
while max(abs(f(s1)))>1e-7 && count<max_count
count=count+1;
s0=s1;
s1=s0-f(s0)./fprime(s0);
end
end
end
function d=d1(S,K,r,sigma,T)
d=(log(S./K)+(r+sigma.^2*0.5).*(T))./(sigma.*sqrt(T));
end
function d=d2(S,K,r,sigma,T)
d=(log(S./K)+(r-sigma.^2*0.5).*(T))./(sigma.*sqrt(T));
end
function p=Phi(x)
p=0.5*(1.+erf(x/sqrt(2)));
end
function p=PhiPrime(x)
p=exp(-0.5*x.^2)/sqrt(2*pi);
end
function c=call(S,K,r,sigma,T)
c=S.*Phi(d1(S,K,r,sigma,T))-K.*exp(-r.*(T)).*Phi(d2(S,K,r,sigma,T));
end
function v=call_vega(S,K,r,sigma,T)
v=S.*PhiPrime(d1(S,K,r,sigma,T)).*sqrt(T);
end
Running impvol(116.4,1558,1440,0.0024,(1/12)) will however unfortunately return the value 'Inf'. There somehow is a problem with the Newton-Rhapson method not converging but I am kind of clueless how to solve this. Does anyone know how to solve this problem or know some other way how to calculate the implied volatility?
Thank u in advance already for your help!
Kind regards,
Henk
I would definitely suggest this code: Fast Matrixwise Black-Scholes Implied Volatility
It is able to compute the entire surface in one shot and - my experience - I found it much more reliable than blsimpv() or impvol() which are other functions implemented in matlab.
Newton-Rhapson method does not work well for implied volatility. You should use the bisection method (not sure how it is used in Matlab). It is described in http://en.wikipedia.org/wiki/Bisection_method. For completeness, it works this way:
1) Pick an arbitrary high (impossible) volatility like high=200%/year.
2) Pick lowest possible volatility (low=0%).
2a) Calculate option premium for 0% volatility, if actual premium is lower than that, it means negative volatility (which is "impossible").
3) While implied volatility is not found:
3.1) If "high" and "low" are very near (e.g. equal up to 5th decimal), either one is your implied volatility. If not...
3.2) Calculate average between "high" and "low". avg=(high+low)/2
3.3) Calculate option premium for avg volatility.
3.4) If actual premium is higher then p(avg), make min=avg, because implied volatility must lie between avg and max.
3.4a) If actual premium is lower than p(avg), make max=avg, because implied vol must lie between min and avg.
The main disvantage of bisect is that you have to pick a maximum value, so your function won't find implied volatilities bigger than that. But something like 200%/year should be high enough for real-world usage.
I use yet another method more like Newton's method, hence not limited to a range, since vega is a derivative, but with a "linearization" fix to avoid hunting and failure due to small vegas:
def implied_volatility(type, premium, S, K, r, s_dummy, t):
if S <= 0.000001 or K <= 0.000001 or t <= 0.000001 or premium <= 0.000001:
return 0.0
s = 0.35
for cycle in range(0, 120):
ext_premium = type(S, K, r, s, t)
if abs(premium - ext_premium) < 0.005:
return s
ext_vega = type.vega(S, K, r, s, t)
# print S, K, r, s, t, premium, ext_premium, ext_vega
if ext_vega < 0.0000001:
# Avoids zero division if stuck
ext_vega = 0.0000001
s_new = s - (ext_premium - premium) / ext_vega
if abs(s_new - s) > 1.00:
# estimated s is too different from previous;
# it is better to go linearly, since
# vega is too small to give a good guess
if s_new > s:
s += 1.0
else:
s -= 1.0
else:
s = s_new
if s < 0.0:
# No volatility < 0%
s = 0.0001
if s > 99.99:
# No point calculating volatilities > 9999%/year
return 100.0
return 0.0
Still, I think that bisect is your best bet.
I created a simple function that conducts a sort of trial and error calculation if the output from blsimpv is NaN. This slows down the computation time significantly for me but it always gives me a desirable result.
The function is shown to be used below
BSIVC(t,i)= blsimpv(S(t,i),K,r,tau(t),HestonCiter(t,i))
if isnan(BSIVC(t,i));
BSIVC(t,i)= secondIVcalc(HestonCiter(t,i),S(t,i),K,r,q,tau(t))
end
The function itself is described below:
function IV= secondIVcalc(HestonC,S,K,r,q,T)
lowCdif = 1;
a=0;
while lowCdif>0.0001
a= a+0.00001
lowCdif = HestonC - BSCprice(S,K,r,q,a,T);
end
IV= a;
end
Please note that BSCprice is not an in-built function in matlab.
Just to make the code clearer-
BSCprice is of the format BSCprice(Underlying Asset Price, Strike Price, interest rate, dividend yield, implied vol, time to maturity).

Matlab, graphing functions

I have a homework problem, I think I did it correctly but need to make sure 100%. Can anyone check for me, before I hand it in?
Thank you.
Question:
Plot the function given by f (x) = 2 sin(2x) − 3 cos(x/2) over the in-
terval [0, 2π] using steps of length .001 (How?). Use the commands max and min to estimate the maximum and minimum points. Include the maximum and minimum points as tick marks on the x-axis and the maximum and minimum values as tick marks on the y-axis.
My code:
x=linspace(0,2*pi,6280);
f=#(x)...
2.*sin(2.*x)-3.*cos(x./2);
%f = #(x)2.*sin(2.*x)-3.*cos(x./2)
g=#(x)...
-1*(2.*sin(2.*x)-3.*cos(x./2));
%g = #(x)-1*(2.*sin(2.*x)-3.*cos(x./2))
[x3,y5]=fminbnd(g,0,2*pi);
%x3 = 4.0968
%y3 = -3.2647
[x2,y4]=fminbnd(f,0,2*pi);
%x2 =2.1864
%y2 = -3.2647
y2=max(f(x));
y3=min(f(x));
plot(x,f(x));
set(gca,'XTick',[x2 x3]);
set(gca,'YTick',[y2 y3]);
(*after I paste this code here, it appeared not as nice as I had it in my program, don't know why)
To create a vector with certain step do
x=0:0.001:2*pi;
Why do you have g(x) function and why are you using fminbind? Use MIN and MAX, return index of those values and find related x values.
[ymin, minindex] = min(f(x));
xmin = x(minindex);
For general case if you have multiple min/max values, index will contain only the first occurrence. Instead you can do:
minindex = find(y==ymin);
Or for real values to avoid precision error:
minindex = find(abs(y-ymin)<=eps);
Also your last statement returns error Values must be monotonically increasing. To avoid it sort your tick values.
set(gca,'XTick',sort([xmin xmax]));
set(gca,'YTick',sort([ymin ymax]));