The FCMP Procedure |
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.
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
specifies the value that is returned from the SOLVE function.
specifies the name of the function. Enclose function-name in quotation marks.
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:
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.
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 |
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 |
specifies the maximum number of iterations to use to find the solution.
Default: | 100 |
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. |
specifies the expected value of the function of interest.
specifies the arguments to pass to the function that is being minimized.
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
initial (initial-value) = .5
abconv (absolute-criterion) = .001
relconv (relative-criterion) = 1.0e-6
maxiter (maximum-iterations) = 100
The solve status is the fifth element in the array. You can display this value by specifying opts[5] in the output list.
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
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:
The options_array is SOLVOPTS, which requires an initial value.
The expected value is the price of the FX option.
The missing argument in the subroutine is the volatility (sigma).
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;
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:
The options_array is OPTS.
The missing argument in the function is the volatility (VOLTY).
PUT statements are used to write the implied volatility (BSVOLTY), the initial value, and the solve status.
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.
The DYNAMIC_ARRAY Subroutine |
The DYNAMIC_ARRAY subroutine enables an array that is declared within a function to change size in an efficient manner.
The syntax of the DYNAMIC_ARRAY subroutine has the following form:
CALL DYNAMIC_ARRAY(array-name, new-dim1-size, ..., new-dimN-size); |
where
specifies the name of a temporary array.
specifies a new size for the temporary array.
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.
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.
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;
Copyright © 2010 by SAS Institute Inc., Cary, NC, USA. All rights reserved.