Previous Page | Next Page

The FCMP Procedure

Special Functions and CALL Routines: Other Functions


The SOLVE Function


Overview of the SOLVE Function

The SOLVE function computes implicit values of a function. It is a special purpose function that is automatically provided by the FCMP procedure for convenience.


Syntax of the SOLVE Function

The syntax of the SOLVE function has the following form:

answer = SOLVE ('function-name', options-array, expected-value, argument-1, argument-2, ..., argument-n);

where

answer

specifies the value that is returned from the SOLVE function.

'function-name'

specifies the name of the function. Enclose function-name in quotation marks.

options-array

specifies an array of options to use with the SOLVE function. Options-array is used to control and monitor the root-finding process. Options-array can be a missing value (.), or it can have up to five of the following elements in the following order:

initial-value

specifies the starting value for the implied value. The default for the first call is 0.001. If the same line of code is executed again, then options-array uses the previously found implied value.

absolute-criterion

specifies a value for convergence. The absolute value of the difference between the expected value and the predicted value must be less than the value of absolute-criterion for convergence.

Default: 1.0e-12
relative-criterion

specifies a value for convergence. When the change in the computed implied value is less than the value of relative-criterion, then convergence is assumed.

Default: 1.0e-6
maximum-iterations

specifies the maximum number of iterations to use to find the solution.

Default: 100
solve-status

can be one of the following values:

0

successful.

1

could not decrease the error.

2

could not compute a change vector.

3

maximum number of iterations exceeded.

4

initial objective function is missing.

expected-value

specifies the expected value of the function of interest.

argument

specifies the arguments to pass to the function that is being minimized.


Details of the SOLVE Function

The SOLVE function finds the value of the specified argument that makes the expression of the following form equal to zero.

expected-value - function-name (argument-1,argument-2, ..., argument-n)

You specify the argument of interest with a missing value (.), which appears in place of the argument in the parameter list that is shown above. If the SOLVE function finds the value, then the value that is returned for this function is the implied value.

The following is an example of an options array:

array opts[5] initial abconv relconv maxiter (.5 .001 1.0e-6 100);

where

The solve status is the fifth element in the array. You can display this value by specifying opts[5] in the output list.


Example 1: Computing a Square Root Value

The following SOLVE function example computes a value of x that satisfies the equation y=1/sqrt(x). Note that you must first define functions and subroutines before you can use them in the SOLVE function. In this example, the function INVERSESQRT is first defined and then used in the SOLVE function.

options pageno=1 nodate ls=80 ps=64;

proc fcmp;
      /* define the function */
   function inversesqrt(x);
      return(1/sqrt(x));
   endsub;

   y = 20;
   x = solve("inversesqrt", {.}, y, .);
   put x;
run;

Results from Computing a Square Root Value

                                 The SAS System                                1

                               The FCMP Procedure

0.0025

Example 2: Calculating the Garman-Kohlhagen Implied Volatility

In this example, the subroutine GKIMPVOL calculates the Garman-Kohlhagen implied volatility for FX options by using the SOLVE function with the GARKHPRC function.

In this example, note the following:

proc fcmp;
   function garkhprc(type$, buysell$, amount, E, t, S, rd, rf, sig)
      kind=pricing label='FX option pricing';

   if buysell='Buy' then sign=1.;
   else do;
      if buysell='Sell' then sign=-1.;
      else sign=.;
   end;

   if type='Call' then
      garkhprc=sign*amount*(E+t+S+rd+rf+sig);
   else do;
      if type='Put' then
         garkhprc=sign*amount*(E+t+S+rd+rf+sig);
      else garkhprc=.;
   end;
   return(garkhprc);
   endsub;
   
   subroutine gkimpvol(n, premium[*], typeflag[*], amt_lc[*],
                       strike[*], matdate[*], valudate, xrate,
                       rd, rf, sigma);
   outargs sigma;

   array solvopts[1] initial (0.20);
   sigma = 0;
   do i = 1 to n;
      maturity = (matdate[i] - valudate) / 365.25;
      stk_opt = 1./strike[i];
      amt_opt = amt_lc[i] * strike[i];
      price = premium[i] * amt_lc[i];

      if typeflag[i] eq 0 then type = "Call";
      if typeflag[i] eq 1 then type = "Put";

         /* solve for volatility */
      sigma = sigma + solve("GARKHPRC", solvopts, price,
                            type, "Buy", amt_opt, stk_opt,
                            maturity, xrate, rd, rf, .);
   end;
   sigma = sigma / n;
endsub;
run;


Example 3: Calculating the Black-Scholes Implied Volatility

This SOLVE function example defines the function BLKSCH by using the built-in SAS function BLKSHCLPRC. The SOLVE function uses the BLKSCH function to calculate the Black-Scholes implied volatility of an option.

In this example, note the following:

options pageno=1 nodate ls=80 ps=64;

proc fcmp;
   opt_price = 5;
   strike = 50;
   exp = '01jul2001'd;
   eq_price = 50;
   intrate = .05;
   time = exp - date();
   array opts[5] initial abconv relconv maxiter
                 (.5 .001 1.0e-6 100);
   function blksch(strike, time, eq_price, intrate, volty);
      return(blkshclprc(strike, time/365.25, 
                        eq_price, intrate, volty));
   endsub;
   bsvolty = solve("blksch", opts, opt_price, strike,
                             time, eq_price, intrate, .);

   put 'Option Implied Volatility:' bsvolty
       'Initial value: ' opts[1]
       'Solve status: ' opts[5];
run;

Results of Calculating the Black-Scholes Implied Volatility

                                 The SAS System                                1

                               The FCMP Procedure

Option Implied Volatility: . Initial value:  0.5 Solve status:  2

Note:   SAS functions and external C functions cannot be used directly in the SOLVE function. They must be enclosed in a PROC FCMP function. In this example, the built-in SAS function BLKSHCLPRC is enclosed in the PROC FCMP function BLKSCH, and then BLKSCH is called in the SOLVE function.  [cautionend]


The DYNAMIC_ARRAY Subroutine


Overview of the DYNAMIC_ARRAY Subroutine

The DYNAMIC_ARRAY subroutine enables an array that is declared within a function to change size in an efficient manner.


Syntax of the DYNAMIC_ARRAY Subroutine

The syntax of the DYNAMIC_ARRAY subroutine has the following form:

CALL DYNAMIC_ARRAY(array-name, new-dim1-size, ..., new-dimN-size);

where

array-name

specifies the name of a temporary array.

new-dim-size

specifies a new size for the temporary array.

/NOSYMBOLS

specifies that an array of numeric or character values be created without the associated element variables. In this case, the only way you can access elements in the array is by array subscripting.

Tip: You can save memory if you do not need to access the individual array element variables by name.

The DYNAMIC_ARRAY CALL routine is passed the array to be resized and a new size for each dimension of the array. In the ALLPERMK routine, a scratch array that is the size of the number of elements being permuted is needed. When the function is created, this value is not known because it is passed in as parameter n. A dynamic array enables the routine to allocate the amount of memory that is needed, instead of having to create an array that is large enough to handle all possible cases.

When using dynamic arrays, support is limited to PROC FCMP routines. When an array is resized, the resized array is available only within the routine that resized it. It is not possible to resize a DATA step array or to return a PROC FCMP dynamic array to the DATA step.


Details

Arrays that are declared in functions and CALL routines can be resized, as well as arrays that are declared with the /NOSYMBOLS option. No other array can be resized.

The DYNAMIC_ARRAY CALL routine attempts to dynamically resize the array to match the dimensions of the target that you provide. This means that the array must be dynamic. That is, the array must be declared either in a function or subroutine, or declared with the /NOSYMBOLS option.


Example: Creating a Temporary Array

The following example creates a temporary array named TEMP. The size of the array area depends on parameters that are passed to the function.

proc fcmp;
   function avedev_wacky(data[*]);

   length = dim(data);
   array temp[1] /nosymbols;
   call dynamic_array(temp, length);

   mean=0;
   do i=1 to datalen;
      mean += data[i];
      if i>1 then temp[i]=data[i-1];
      else temp[i]=0;
   end;
   mean=mean/length;

   avedev=0;
   do i=1 to length;
      avedev += abs((data[i])-temp[i] /2-mean);
   end;
   avedev=avedev/datalen;

   return(avedev);
endsub;    
run;

Previous Page | Next Page | Top of Page