2
$\begingroup$

I have this function

BSprice[S_, K_, r_, T_, v_, PutCall_] :=
  Module[{d, bscall},
   bscall = 0.0;
   d = (Log[S/K] + T*(r + 0.5*v^2))/(v*Sqrt[T]);
   bscall = S*Gauss[d] - Exp[-r*T]*K*Gauss[d - v*Sqrt[T]];
   If[PutCall == "Call",
    Return[bscall],
    Return[bscall - S + K*Exp[-r*T]];
    ];
   ];

and when I explicitly put in the parameter values, I get

BSprice[319.0, 355, 0.02, 35/365, 0.1584, "Call"]
0.0952009

But when I try to do substitutions, it's another story...I get

BSprice[x, k1, r, T, \[Sigma]1, "Call"] /. {x -> 319.0, k1 -> 355, 
  r -> 0.02, T -> 35/365, \[Sigma]1 -> 0.1584}
-35.3198 Null

Why does this happen? What am I doing wrong? Thanks for assistance...

The other functions needed are:

Gauss[x_] := NormSDist[x];
NormSDist[x_] :=
  Module[{t, b1, b2, b3, b4, b5, p, c},
   t = 0;
   b1 = 0.31938153;
   b2 = -0.356563782;
   b3 = 1.781477937;
   b4 = -1.821255978;
   b5 = 1.330274429;
   p = 0.2316419;
   c = 0.39894228;
   If[x >= 0,
    t = 1.0/(1.0 + p*x);
    Return[(1.0 - 
       c*Exp[-x*x/2.0]*t*(t*(t*(t*(t*b5 + b4) + b3) + b2) + b1))],
    t = 1.0/(1.0 - p*x);
    Return[(c*Exp[-x*x/2.0]*
       t*(t*(t*(t*(t*b5 + b4) + b3) + b2) + b1))]];
   ];
$\endgroup$

1 Answer 1

6
$\begingroup$

What is the problem? If you run

NormSDist[undefinedsymbol]

you will get no return value, meaning Null. The problem is that your If[x >= 0,...] cannot decide if x >= 0 is true or not, and therefore will not evaluate either of your Return.

Please see the If-documentation:

If[condition,t,f] is left unevaluated if condition evaluates to neither True nor False.

Solution. Rewrite your function NormSDist without Return. Also remove the semicolon after If and only rely on the fact that the last expression in your Module is returned:

NormSDist[x_]:=Module[{t,b1,b2,b3,b4,b5,p,c},t=0;
  b1=0.31938153;
  b2=-0.356563782;
  b3=1.781477937;
  b4=-1.821255978;
  b5=1.330274429;
  p=0.2316419;
  c=0.39894228;
  If[x>=0,
    t=1.0/(1.0+p*x);
    (1.0-c*Exp[-x*x/2.0]*t*(t*(t*(t*(t*b5+b4)+b3)+b2)+b1)), (* no Return *)
    t=1.0/(1.0-p*x);
    (c*Exp[-x*x/2.0]*t*(t*(t*(t*(t*b5+b4)+b3)+b2)+b1)) (* no Return *)
    ] (* no semicolon *)
];

Now

BSprice[x,k1,r,T,\[Sigma]1,"Call"]/. {x->319.0,k1->355,r->0.02,T->35/365,\[Sigma]1->0.1584}

also gives 0.0952009.

Comment. I never use the Return function. Various reasons for why one should not use Return are given in this old newsgroup thread. See also this Mathematica SE post.

Comment. While the above works, I would probably write this function as follows:

NormSDist[x_]:=With[{
  b1=0.31938153,
  b2=-0.356563782,
  b3=1.781477937,
  b4=-1.821255978,
  b5=1.330274429,
  p=0.2316419,
  c=0.39894228},
  With[{aux=Function[{t},c*Exp[-x*x/2.0]*t*(t*(t*(t*(t*b5+b4)+b3)+b2)+b1)]},
    If[x>=0,1.0-aux[1.0/(1.0+p*x)],aux[1.0/(1.0-p*x)]]]];

Note. There is actually a much simpler solution to your problem, namely you could change your original definition and add NumericQ as in

NormSDist[x_?NumericQ]:=...

The NumericQ prevents evaluation as long as the argument is not numeric. But I hope the answer above is more useful.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.