Logo

ProportionalDividends

Updated 2024-02-13 19:40:28.203000

Syntax

SELECT [westclintech].[wct].[ProportionalDividends](
  <@CallPut, nvarchar(4000),>
 ,<@AmEur, nvarchar(4000),>
 ,<@AssetPrice, float,>
 ,<@StrikePrice, float,>
 ,<@TimeToMaturity, float,>
 ,<@RiskFreeRate, float,>
 ,<@Dividend_RangeQuery, nvarchar(max),>
 ,<@Volatility, float,>
 ,<@NumberOfSteps, int,>
 ,<@RV, nvarchar(4000),>)

Description

Use the scalar function ProportionalDividends to calculate the price and Greeks of an American or European option paying proportional dividends using a Cox Ross Rubinstein Binomial as described in The Complete Guide to Option Pricing Formulas, Second Edition, by Espen Gaarder Haug, PhD.

Arguments

@RiskFreeRate

the annualized, continuously compounded zero-coupon risk-free rate over the life of the option. @RiskFreeRate is an expression of type float or of a type that can be implicitly converted to float.

@TimeToMaturity

the time to expiration of the option, expressed in years. @TimeToMaturity is an expression of type float or of a type that can be implicitly converted to float.

@RV

identifies the calculation to be performed. @RV is an expression of type nvarchar or of a type that can be implicitly converted to nvarchar. @RV is not case-sensitive. The following values are acceptable for @RV.

{"columns":[{"field":"@RV"},{"field":"Returns"}],"rows":[{"@RV":"'P' , 'PRICE'","Returns":"Price"},{"@RV":"'D' , 'DELTA'","Returns":"Delta"},{"@RV":"'G' , 'GAMMA'","Returns":"Gamma"},{"@RV":"'T' , 'THETA'","Returns":"Theta"},{"@RV":"'V' , 'VEGA'","Returns":"Vega"},{"@RV":"'R' , 'RHO'","Returns":"Rho"},{"@RV":"'L' , 'LAMBDA'","Returns":"Lambda"},{"@RV":"'DDDV' , 'VANNA' , 'DVEGADSPOT' , 'DDELTADVOL'","Returns":"DdeltaDvol"},{"@RV":"'DVV' , 'DDELTADVOLDVOL'","Returns":"DdeltaDvolDvol"},{"@RV":"'DT' , 'CHARM' , 'DDELTADTIME'","Returns":"DdeltaDtime"},{"@RV":"'GV' , 'ZOMMA' , 'DGAMMADVOL'","Returns":"DgammaDvol"},{"@RV":"'GP' , 'GAMMAP'","Returns":"GammaP"},{"@RV":"'DVDV' , 'VOMMA' , 'VOLGA' , 'DVEGADVOL'","Returns":"DvegaDvol"},{"@RV":"'VP' , 'VEGAP'","Returns":"VegaP"},{"@RV":"'S' , 'SPEED' , 'DGAMMADSPOT'","Returns":"DgammaDspot"},{"@RV":"'DX' , 'DELTAX'","Returns":"Delta X"},{"@RV":"'RND' , 'RISKNEUTRALDENSITY'","Returns":"Risk Neutral Density"},{"@RV":"'VVV' , 'ULTIMA' , 'DVOMMADVOL'","Returns":"DvommaDvol"},{"@RV":"'VT' , 'VETA' , 'DVEGADTIME'","Returns":"DvegaDtime"},{"@RV":"'GT' , 'COLOR' , 'DGAMMADTIME'","Returns":"DgammaDtime"}]}

@Dividend_RangeQuery

a string containing an SQL statement which, when executed, provides the function with the times and proportions of the dividends to be used in the calculation. The results of the SQL must contain exactly two columns, the first being the time value, as a float or as a value that implicitly converts to float, and the second being the proportion as float, or as a value that implicitly converts to float. @Dividend_RangeQuery is an expression of type nvarchar or of a type that can be implicitly converted to nvarchar.

@AmEur

identifies the option as being American ('A') or European ('E'). @AmEur is an expression of type nvarchar or of a type that can be implicitly converted to nvarchar.

@CallPut

identifies the option as being a call ('C') or a put ('P'). @CallPut is an expression of type nvarchar or of a type that can be implicitly converted to nvarchar.

@StrikePrice

the exercise price of the option. @StrikePrice is an expression of type float or of a type that can be implicitly converted to float.

@NumberOfSteps

the number of steps in the binomial tree. @NumberOfSteps is an expression of type int or of a type that can be implicitly converted to int.

@Volatility

the volatility of the relative price change of the underlying asset. @Volatility is an expression of type float or of a type that can be implicitly converted to float.

@AssetPrice

the price of the underlying asset. @AssetPrice is an expression of type float or of a type that can be implicitly converted to float.

Return Type

float

Remarks

@Volatility must be greater than zero (@Volatility > 0).

@TimeToMaturity must be greater than zero (@TimeToMaturity > 0).

@AssetPrice must be greater than zero (@AssetPrice > 0).

@StrikePrice must be greater than zero (@StrikePrice > 0).

@NumberOfSteps must be greater than 1 (@NumberOfSteps > 1).

If @RV is NULL, then @RV is set to 'P'.

Negative time values returned by @Dividend_RangeQuery are ignored.

Time values returned by @Dividend_RangeQuery that are greater than @TimeToMaturity are ignored.

If @RiskFreeRate is NULL then @RiskFreeRate is set to zero.

To get the implied volatility (given price), use PROPORTIONALDIVIDENDSIV.

Use the table-valued function PROPORTIONALDIVIDENDSTREE to see the underlying price, intrinsic value, and option value for each node on the binomial tree.

Use the table-valued function PROPORTIONALDIVIDENDSPRICENGREEKS to calculate the price, delta, gamma, theta, vega, rho and lambda in a single SELECT statement faster than calculating them individually in ProportionalDividends.

To calculate the price and Greeks using discrete dividends (where the dividend is specified with a date and a percentage) use BINOMIALDISCRETEDIVIDENDS.

Examples

DECLARE @date_start as datetime = cast('2013-12-11' as datetime);
DECLARE @date_start_string as varchar(max) = '''' + convert(varchar, @date_start, 112) + '''';
SELECT wct.ProportionalDividends(
                                    'C',
                                    'A',
                                    478,
                                    500,
                                    wct.YEARFRAC(@date_start, '2014-11-27', NULL),
                                    .0275,
                                    'SELECT *
       FROM (VALUES
(wct.YEARFRAC(' + @date_start_string + ',wct.CALCDATE(2014,2,6),NULL),0.010),
(wct.YEARFRAC(' + @date_start_string + ',wct.CALCDATE(2014,5,6),NULL),0.011),
(wct.YEARFRAC(' + @date_start_string + ',wct.CALCDATE(2014,8,6),NULL),0.012),
(wct.YEARFRAC(' + @date_start_string + ',wct.CALCDATE(2014,11,6),NULL),0.013)
            )n(T,D)',
                                    0.30,
                                    100,
                                    'P'
                                ) as [Price];

Calculate the price for an American call option expiring in one year with asset price of 478, a strike price of 500 and a volatility of 30%. The risk-free rate is 2.75%. Dividends will be paid quarterly in the following proportions.

{"columns":[{"field":"T","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"Div","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"}],"rows":[{"T":"0.25","Div":".010"},{"T":"0.50","Div":".011"},{"T":"0.75","Div":".012"},{"T":"1.00","Div":".013"}]}

The number of steps is 100.

SELECT wct.ProportionalDividends(
                                    'C',   --Put/Call
                                    'A',   --American/European
                                    478,   --Asset Price
                                    500,   --Strike Price
                                    1,     --Time-to-maturity
                                    .0275, --Risk-free rate
                                    'SELECT *
       FROM (VALUES
            (0.25,0.010),
            (0.50,0.011),
            (0.75,0.012),
            (1.00,0.013)
            )n(T,D)'                ,
                                           --Proportional Dividends
                                    0.30,  --Volatility
                                    100,   --Number of Steps
                                    'P'    --Return Value
                                ) as [Price];

This produces the following result.

{"columns":[{"field":"Price","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"}],"rows":[{"Price":"43.17175949561"}]}

To calculate the delta for the same option:

SELECT wct.ProportionalDividends(
                                    'C',   --Put/Call
                                    'A',   --American/European
                                    478,   --Asset Price
                                    500,   --Strike Price
                                    1,     --Time-to-maturity
                                    .0275, --Risk-free rate
                                    'SELECT *
       FROM (VALUES
            (0.25,0.010),
            (0.50,0.011),
            (0.75,0.012),
            (1.00,0.013)
            )n(T,D)'                ,
                                           --Proportional Dividends
                                    0.30,  --Volatility
                                    100,   --Number of Steps
                                    'D'    --Return Value
                                ) as [Delta];

This produces the following result.

{"columns":[{"field":"Delta","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"}],"rows":[{"Delta":"0.46362277506691"}]}

In this example, using the same data, we calculate the price for all the combinations of @AmEur and @CallPut.

SELECT n.z,
       m.AE,
       wct.ProportionalDividends(
                                    n.z,   --Put/Call
                                    m.AE,  --American/European
                                    478,   --Asset Price
                                    500,   --Strike Price
                                    1,     --Time-to-maturity
                                    .0275, --Risk-free rate
                                    'SELECT *
       FROM (VALUES
            (0.25,0.010),
            (0.50,0.011),
            (0.75,0.012),
            (1.00,0.013)
            )n(T,D)'                ,
                                           --Proportional Dividends
                                    0.30,  --Volatility
                                    100,   --Number of Steps
                                    'P'    --Return Value
                                ) as [Price]
FROM
(
    VALUES
        ('P'),
        ('C')
) n (z)
    CROSS APPLY
(
    VALUES
        ('A'),
        ('E')
) m (AE);

This produces the following result.

{"columns":[{"field":"z"},{"field":"AE"},{"field":"Price","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"}],"rows":[{"z":"P","AE":"A","Price":"73.830901064052"},{"z":"P","AE":"E","Price":"72.6163355317298"},{"z":"C","AE":"A","Price":"43.17175949561"},{"z":"C","AE":"E","Price":"42.566220029483"}]}

In this example we look at how to use dates in the function, using the YEARFRAC and CALCDATE functions from XLeratorDB/financial. We will use the GETDATE () function as the start date for the calculations. The option expires on November 27th, 2014 with dividends payable on February 6th, May 6th , August 6th and November 6th, 2014.

SELECT wct.ProportionalDividends(
                                    'C',
                                    'A',
                                    478,
                                    500,
                                    wct.YEARFRAC(GETDATE(), '2014-11-27', NULL),
                                    .0275,
                                    'SELECT *
       FROM (VALUES
(wct.YEARFRAC(GETDATE(),wct.CALCDATE(2014,2,6),NULL),0.010),
(wct.YEARFRAC(GETDATE(),wct.CALCDATE(2014,5,6),NULL),0.011),
(wct.YEARFRAC(GETDATE(),wct.CALCDATE(2014,8,6),NULL),0.012),
(wct.YEARFRAC(GETDATE(),wct.CALCDATE(2014,11,6),NULL),0.013)
            )n(T,D)',
                                    0.30,
                                    100,
                                    'P'
                                ) as [Price];

This produces the following result on 2013-12-11. You results will be different.

{"columns":[{"field":"Price","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"}],"rows":[{"Price":"43.5863644912707"}]}

In this example, we use @date_start as a datetime variable to establish the starting point for calculating the time-to-expiry and @date_start_string as a string variable to be used in @Dividend_RangeQuery.

DECLARE @date_start as datetime = cast('2013-12-11' as datetime);
DECLARE @date_start_string as varchar(max) = '''' + convert(varchar, @date_start, 112) + '''';
SELECT wct.ProportionalDividends(
                                    'C',
                                    'A',
                                    478,
                                    500,
                                    wct.YEARFRAC(@date_start, '2014-11-27', NULL),
                                    .0275,
                                    'SELECT *
       FROM (VALUES
(wct.YEARFRAC(' + @date_start_string + ',wct.CALCDATE(2014,2,6),NULL),0.010),
(wct.YEARFRAC(' + @date_start_string + ',wct.CALCDATE(2014,5,6),NULL),0.011),
(wct.YEARFRAC(' + @date_start_string + ',wct.CALCDATE(2014,8,6),NULL),0.012),
(wct.YEARFRAC(' + @date_start_string + ',wct.CALCDATE(2014,11,6),NULL),0.013)
            )n(T,D)',
                                    0.30,
                                    100,
                                    'P'
                                ) as [Price];

This produces the following result.

{"columns":[{"field":"Price","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"}],"rows":[{"Price":"43.5863644912707"}]}

In this example we put some equity options trades into a table, with a separate table containing the closing price and volatilities for each ticker and a third table containing the dividend information. This example shows one way to combine the information from multiples tables to calculate the theoretical value of the option. This example holds the risk-free rate constant, which you wouldn't want to do in practice and we will add a discount factor table and calculate the interpolated risk-free rate in another example.

/*Put dividend information into a table*/
SELECT *
INTO #div
FROM
(
    VALUES
        ('ABC', '2013-12-15', 0.010),
        ('ABC', '2014-03-15', 0.0105),
        ('ABC', '2014-06-15', 0.0110),
        ('ABC', '2014-09-15', 0.0115),
        ('ABC', '2014-12-15', 0.0120),
        ('DEF', '2014-01-17', .005),
        ('DEF', '2014-04-17', .005),
        ('DEF', '2014-07-17', .005),
        ('DEF', '2014-10-17', .005),
        ('DEF', '2015-01-17', .005),
        ('GHI', '2014-02-17', .020),
        ('GHI', '2014-05-17', .021),
        ('GHI', '2014-08-17', .022),
        ('GHI', '2014-11-17', .023),
        ('GHI', '2015-02-17', .030)
) d (ticker, date_div, amt_div);

/*Put price information into a table*/
SELECT *
INTO #prices
FROM
(
    VALUES
        ('ABC', 495, 0.35),
        ('DEF', 125, 0.3),
        ('GHI', 62.5, 0.25)
) p (ticker, price, vol);

/*put the options into a table*/
SELECT *
INTO #options
FROM
(
    VALUES
        (1, 'ABC', '2014-08-09', 470, 'C'),
        (2, 'ABC', '2014-08-20', 480, 'P'),
        (3, 'ABC', '2014-11-10', 490, 'P'),
        (4, 'ABC', '2014-09-14', 500, 'C'),
        (5, 'DEF', '2014-11-14', 100, 'C'),
        (6, 'DEF', '2014-12-12', 110, 'C'),
        (7, 'DEF', '2014-08-11', 120, 'P'),
        (8, 'DEF', '2014-08-26', 130, 'C'),
        (9, 'GHI', '2014-08-04', 50, 'C'),
        (10, 'GHI', '2014-12-28', 55, 'C'),
        (11, 'GHI', '2014-10-09', 60, 'P'),
        (12, 'GHI', '2014-11-14', 65, 'C')
) o (rn, ticker, expiry, strike, z);

/*Establish the start date for calculation purposes*/
DECLARE @date_start as datetime = cast('2013-12-11' as datetime);
DECLARE @date_start_string as varchar(max) = '''' + convert(varchar, @date_start, 112) + '''';
SELECT A.rn,
       A.ticker,
       A.z,
       B.price,
       A.strike,
       A.expiry,
       B.vol,
       wct.ProportionalDividends(
                                    A.z,
                                    'A',
                                    B.price,
                                    A.strike,
                                    wct.YEARFRAC(@date_start, A.expiry, NULL),
                                    .0275,
                                    'SELECT wct.YEARFRAC(' + @date_start_string
                                    + ',date_div,NULL),amt_div FROM #div WHERE ticker = ' + ''''
                                    + CAST(A.ticker as varchar(max)) + '''',
                                    B.vol,
                                    100,
                                    'P'
                                ) as [Price]
FROM #options A
    INNER JOIN #prices B
        ON A.ticker = B.ticker;

DROP TABLE #div;
DROP TABLE #prices;
DROP TABLE #options;

This produces the following result.

{"columns":[{"field":"rn","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"ticker"},{"field":"z"},{"field":"price","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"strike","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"expiry","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"vol","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"Price","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"}],"rows":[{"rn":"1","ticker":"ABC","z":"C","price":"495.0","strike":"470","expiry":"2014-08-09","vol":"0.35","Price":"64.0896631114969"},{"rn":"2","ticker":"ABC","z":"P","price":"495.0","strike":"480","expiry":"2014-08-20","vol":"0.35","Price":"51.288937986805"},{"rn":"3","ticker":"ABC","z":"P","price":"495.0","strike":"490","expiry":"2014-11-10","vol":"0.35","Price":"65.9755648271892"},{"rn":"4","ticker":"ABC","z":"C","price":"495.0","strike":"500","expiry":"2014-09-14","vol":"0.35","Price":"54.2923033344242"},{"rn":"5","ticker":"DEF","z":"C","price":"125.0","strike":"100","expiry":"2014-11-14","vol":"0.30","Price":"29.187222547902"},{"rn":"6","ticker":"DEF","z":"C","price":"125.0","strike":"110","expiry":"2014-12-12","vol":"0.30","Price":"22.9394732937363"},{"rn":"7","ticker":"DEF","z":"P","price":"125.0","strike":"120","expiry":"2014-08-11","vol":"0.30","Price":"9.38067973328991"},{"rn":"8","ticker":"DEF","z":"C","price":"125.0","strike":"130","expiry":"2014-08-26","vol":"0.30","Price":"10.5798910486624"},{"rn":"9","ticker":"GHI","z":"C","price":"62.5","strike":"50","expiry":"2014-08-04","vol":"0.25","Price":"12.9964352107056"},{"rn":"10","ticker":"GHI","z":"C","price":"62.5","strike":"55","expiry":"2014-12-28","vol":"0.25","Price":"9.28364169798092"},{"rn":"11","ticker":"GHI","z":"P","price":"62.5","strike":"60","expiry":"2014-10-09","vol":"0.25","Price":"5.39933506908685"},{"rn":"12","ticker":"GHI","z":"C","price":"62.5","strike":"65","expiry":"2014-11-14","vol":"0.25","Price":"4.01874219890256"}]}

For large volumes of data having many options for a single ticker, it will be more efficient to calculate the time values of the dividends outside of the ProportionalDividends function and simply use the pre-calculated values in @Dividend_RangeQuery.

/*Put dividend information into a table*/
SELECT *
INTO #div
FROM (VALUES
 ('ABC','2013-12-15',0.010)
,('ABC','2014-03-15',0.0105)
,('ABC','2014-06-15',0.0110)
,('ABC','2014-09-15',0.0115)
,('ABC','2014-12-15',0.0120)
,('DEF','2014-01-17',.005)
,('DEF','2014-04-17',.005)
,('DEF','2014-07-17',.005)
,('DEF','2014-10-17',.005)
,('DEF','2015-01-17',.005)
,('GHI','2014-02-17',.020)
,('GHI','2014-05-17',.021)
,('GHI','2014-08-17',.022)
,('GHI','2014-11-17',.023)
,('GHI','2015-02-17',.030)
)d(ticker,date_div,amt_div);
 
/*Put price information into a table*/
SELECT *
INTO #prices
FROM (VALUES
       ('ABC',495,0.35)
      ,('DEF',125,0.3)
      ,('GHI',62.5,0.25)
      )p(ticker,price,vol);
 
/*put the options into a table*/
SELECT *
INTO #options
FROM (VALUES
       (1,'ABC','2014-08-09',470,'C')
      ,(2,'ABC','2014-08-20',480,'P')
      ,(3,'ABC','2014-11-10',490,'P')
      ,(4,'ABC','2014-09-14',500,'C')
      ,(5,'DEF','2014-11-14',100,'C')
      ,(6,'DEF','2014-12-12',110,'C')
      ,(7,'DEF','2014-08-11',120,'P')
      ,(8,'DEF','2014-08-26',130,'C')
      ,(9,'GHI','2014-08-04',50,'C')
      ,(10,'GHI','2014-12-28',55,'C')
      ,(11,'GHI','2014-10-09',60,'P')
      ,(12,'GHI','2014-11-14',65,'C')
      )o(rn,ticker,expiry,strike,z);
 
/*Establish the start date for calculation purposes*/
DECLARE @date_start as datetime = cast('2013-12-11' as datetime);
 
/*Put the #div values into another table with date converted to a
 fraction of a year*/
SELECT ticker
,wct.YEARFRAC(@date_start,date_div,NULL) as T
,amt_div as D
INTO #tdiv
FROM #div;
 
SELECT A.rn
,A.ticker
,A.z
,B.price
,A.strike
,A.expiry
,B.vol
,wct.ProportionalDividends(
       A.z
      ,'A'
      ,B.price
      ,A.strike
      ,wct.YEARFRAC(@date_start,A.expiry,NULL)
      ,.0275           
,'SELECT T,D FROM #tdiv WHERE ticker = ' + '''' + CAST(A.ticker as varchar(max)) + ''''
      ,B.vol           
      ,100       
      ,'P'       
      ) as [Price]
FROM #options A
INNER JOIN #prices B
ON A.ticker = B.ticker;
 
DROP TABLE #div;
DROP TABLE #prices;
DROP TABLE #options;
DROP TABLE #tdiv;

This produces the following result, which has been reformatted for presentation purposes.

{"columns":[{"field":"rn","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"ticker"},{"field":"z"},{"field":"price","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"strike","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"expiry","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"vol","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"Price","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"}],"rows":[{"rn":"1","ticker":"ABC","z":"C","price":"495.0","strike":"470","expiry":"2014-08-09","vol":"0.35","Price":"64.0896631114969"},{"rn":"2","ticker":"ABC","z":"P","price":"495.0","strike":"480","expiry":"2014-08-20","vol":"0.35","Price":"51.288937986805"},{"rn":"3","ticker":"ABC","z":"P","price":"495.0","strike":"490","expiry":"2014-11-10","vol":"0.35","Price":"65.9755648271892"},{"rn":"4","ticker":"ABC","z":"C","price":"495.0","strike":"500","expiry":"2014-09-14","vol":"0.35","Price":"54.2923033344242"},{"rn":"5","ticker":"DEF","z":"C","price":"125.0","strike":"100","expiry":"2014-11-14","vol":"0.30","Price":"29.187222547902"},{"rn":"6","ticker":"DEF","z":"C","price":"125.0","strike":"110","expiry":"2014-12-12","vol":"0.30","Price":"22.9394732937363"},{"rn":"7","ticker":"DEF","z":"P","price":"125.0","strike":"120","expiry":"2014-08-11","vol":"0.30","Price":"9.38067973328991"},{"rn":"8","ticker":"DEF","z":"C","price":"125.0","strike":"130","expiry":"2014-08-26","vol":"0.30","Price":"10.5798910486624"},{"rn":"9","ticker":"GHI","z":"C","price":"62.5","strike":"50","expiry":"2014-08-04","vol":"0.25","Price":"12.9964352107056"},{"rn":"10","ticker":"GHI","z":"C","price":"62.5","strike":"55","expiry":"2014-12-28","vol":"0.25","Price":"9.28364169798092"},{"rn":"11","ticker":"GHI","z":"P","price":"62.5","strike":"60","expiry":"2014-10-09","vol":"0.25","Price":"5.39933506908685"},{"rn":"12","ticker":"GHI","z":"C","price":"62.5","strike":"65","expiry":"2014-11-14","vol":"0.25","Price":"4.01874219890256"}]}

In this example, we will use the same inputs as above, with the exception that we will have a table of discount factors and use the DFINTERP function to convert the discount factors into risk-free rates to be used in the function.

/*Put dividend information into a table*/
SELECT *
INTO #div
FROM
(
    VALUES
        ('ABC', '2013-12-15', 0.010),
        ('ABC', '2014-03-15', 0.0105),
        ('ABC', '2014-06-15', 0.0110),
        ('ABC', '2014-09-15', 0.0115),
        ('ABC', '2014-12-15', 0.0120),
        ('DEF', '2014-01-17', .005),
        ('DEF', '2014-04-17', .005),
        ('DEF', '2014-07-17', .005),
        ('DEF', '2014-10-17', .005),
        ('DEF', '2015-01-17', .005),
        ('GHI', '2014-02-17', .020),
        ('GHI', '2014-05-17', .021),
        ('GHI', '2014-08-17', .022),
        ('GHI', '2014-11-17', .023),
        ('GHI', '2015-02-17', .030)
) d (ticker, date_div, amt_div);

/*Put price information into a table*/
SELECT *
INTO #prices
FROM
(
    VALUES
        ('ABC', 495, 0.35),
        ('DEF', 125, 0.3),
        ('GHI', 62.5, 0.25)
) p (ticker, price, vol);

/*put the options into a table*/
SELECT *
INTO #options
FROM
(
    VALUES
        (1, 'ABC', '2014-08-09', 470, 'C'),
        (2, 'ABC', '2014-08-20', 480, 'P'),
        (3, 'ABC', '2014-11-10', 490, 'P'),
        (4, 'ABC', '2014-09-14', 500, 'C'),
        (5, 'DEF', '2014-11-14', 100, 'C'),
        (6, 'DEF', '2014-12-12', 110, 'C'),
        (7, 'DEF', '2014-08-11', 120, 'P'),
        (8, 'DEF', '2014-08-26', 130, 'C'),
        (9, 'GHI', '2014-08-04', 50, 'C'),
        (10, 'GHI', '2014-12-28', 55, 'C'),
        (11, 'GHI', '2014-10-09', 60, 'P'),
        (12, 'GHI', '2014-11-14', 65, 'C')
) o (rn, ticker, expiry, strike, z);

/*Establish the start date for calculation purposes*/
DECLARE @date_start as datetime = cast('2013-12-11' as datetime);

/*Put the #div values into another table with date converted to a
 fraction of a year*/
SELECT ticker,
       wct.YEARFRAC(@date_start, date_div, NULL) as T,
       amt_div as D
INTO #tdiv
FROM #div;

/*Put the discount factors into a table*/
SELECT wct.TENOR2DATE(tenor, @date_start, NULL, '') as date_df,
       df
INTO #df
FROM
(
    SELECT 'ON',
           0.999995555575309
    UNION ALL
    SELECT 'TN',
           0.999991111170370
    UNION ALL
    SELECT '1W',
           0.999956112706425
    UNION ALL
    SELECT '2W',
           0.999916450742048
    UNION ALL
    SELECT '1M',
           0.999804481000583
    UNION ALL
    SELECT '2M',
           0.999574621744643
    UNION ALL
    SELECT '3M',
           0.999241679910437
    UNION ALL
    SELECT '6M',
           0.998800609148515
    UNION ALL
    SELECT '9M',
           0.998022836090921
    UNION ALL
    SELECT '1Y',
           0.997197057207847
    UNION ALL
    SELECT '2Y',
           0.996311568695976
) n(tenor, df);

/*Calculate the risk-free rate for each expiry date in the portfolio*/
SELECT expiry,
       wct.DFINTERP(date_df, df, expiry, @date_start, 'CC') as Rf
INTO #rates
FROM #df,
     #options
GROUP BY expiry;

SELECT A.rn,
       A.ticker,
       A.z,
       B.price,
       A.strike,
       A.expiry,
       C.rf,
       B.vol,
       wct.ProportionalDividends(
                                    A.z,
                                    'A',
                                    B.price,
                                    A.strike,
                                    wct.YEARFRAC(@date_start, A.expiry, NULL),
                                    C.rf,
                                    'SELECT T,D FROM #tdiv WHERE ticker = ' + '''' + CAST(A.ticker as varchar(max))
                                    + '''',
                                    B.vol,
                                    100,
                                    'P'
                                ) as [Price]
FROM #options A
    INNER JOIN #prices B
        ON A.ticker = B.ticker
    INNER JOIN #rates C
        ON A.expiry = C.expiry;

DROP TABLE #div;
DROP TABLE #prices;
DROP TABLE #options;
DROP TABLE #tdiv;
DROP TABLE #df;
DROP TABLE #rates;

This produces the following result, which has been reformatted for presentation purposes.

{"columns":[{"field":"rn","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"ticker"},{"field":"z"},{"field":"price","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"strike","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"expiry","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"rf","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"vol","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"},{"field":"Price","headerClass":"ag-right-aligned-header","cellClass":"ag-right-aligned-cell"}],"rows":[{"rn":"1","ticker":"ABC","z":"C","price":"495.0","strike":"470","expiry":"2014-08-09","rf":"0.0025148295484","vol":"0.35","Price":"60.9840233072764"},{"rn":"2","ticker":"ABC","z":"P","price":"495.0","strike":"480","expiry":"2014-08-20","rf":"0.00254046025359867","vol":"0.35","Price":"55.1904762104185"},{"rn":"3","ticker":"ABC","z":"P","price":"495.0","strike":"490","expiry":"2014-11-10","rf":"0.00271136136593034","vol":"0.35","Price":"71.8109761624293"},{"rn":"4","ticker":"ABC","z":"C","price":"495.0","strike":"500","expiry":"2014-09-14","rf":"0.00259872816889223","vol":"0.35","Price":"50.9856872152371"},{"rn":"5","ticker":"DEF","z":"C","price":"125.0","strike":"100","expiry":"2014-11-14","rf":"0.00271924393188473","vol":"0.30","Price":"27.944371440144"},{"rn":"6","ticker":"DEF","z":"C","price":"125.0","strike":"110","expiry":"2014-12-12","rf":"0.00277443669201486","vol":"0.30","Price":"21.5963597351264"},{"rn":"7","ticker":"DEF","z":"P","price":"125.0","strike":"120","expiry":"2014-08-11","rf":"0.00251948935491978","vol":"0.30","Price":"10.2808383857425"},{"rn":"8","ticker":"DEF","z":"C","price":"125.0","strike":"130","expiry":"2014-08-26","rf":"0.00255444247259059","vol":"0.30","Price":"9.78748158480555"},{"rn":"9","ticker":"GHI","z":"C","price":"62.5","strike":"50","expiry":"2014-08-04","rf":"0.00250318065346059","vol":"0.25","Price":"12.7382096126769"},{"rn":"10","ticker":"GHI","z":"C","price":"62.5","strike":"55","expiry":"2014-12-28","rf":"0.00274695012682584","vol":"0.25","Price":"8.85971756935813"},{"rn":"11","ticker":"GHI","z":"P","price":"62.5","strike":"60","expiry":"2014-10-09","rf":"0.00264831947260385","vol":"0.25","Price":"6.01931034341236"},{"rn":"12","ticker":"GHI","z":"C","price":"62.5","strike":"65","expiry":"2014-11-14","rf":"0.00271924393188473","vol":"0.25","Price":"3.63913505258908"}]}