OpenRedukti Scripting With Ravi¶
OpenRedukti comes with a scripting language Ravi that is a dialect of Lua. It is much easier to play with and understand how OpenRedukti works by running small examples in the scripting language.
Once you have built OpenRedukti, you will find a commandline program called dylan
. To start the scripting environment
just invoke this command. It works the same way as the Lua command line.
To exit the scripting environment enter ^Z on Windows, and ^D on Unix systems.
The scripting API is a subset of the OpenRedukti C++ API, therefore not every feature is available.
Date Types¶
Dates are represented as integer values. The api for dates is as follows:
Converting to Date type¶
- reduki.date(day,month,year)
takes day, month, year and returns a date
- reduki.date(str)
Parse a string representation of date. It will detect seperator character ‘/’ or ‘-‘. The formats acceptable are yyyy/mm/dd, dd/mm/yyyy, yyyy-mm-dd, or dd-mm-yyyy
- reduki.date{ d,m,y }
takes table and converts to date
- reduki.date()
returns today’s date
Examples:
local t = {}
t.effective_date = redukti.date{1,1,2016}
t.termination_date = redukti.date{1,1,2017}
Decomposing a Date type¶
- redukti.date_parts(date)
takes a date and returns day, month, year
Examples:
function print_date(d)
local d,m,y = redukti.date_parts( d )
return string.format("%02d/%02d/%d", d, m, y)
end
print_date(redukti.date('2017/10/04'))
Date arithmetic¶
As a date value represents the number of days since 1899/12/31, you can simply add or subtract from it to get to another date. Following api is provided for adding a period to date.
- redukti.addperiod(date, period)
Adds period to date and returns resulting date Periods are entities like 1D, 4W, 1M or 15Y.
Examples:
date = redukti.date()
print(redukti.addperiod(date, '5Y')) -- add 5 years to the date
print(redukti.addperiod(date, '-1D')) -- subtract 1 day from date
Holiday Calendars¶
The api for obtaining and working with calendars is as follows:
- redukti.calendar(businesscenters)
Returns a calendar object. Suported business centers are AUSY, USNY, GBLO, EUTA, JPTO and BRSP. You can specify more than one center by separating the values by a comma.
- calendar:advance(date, period [, business_day_convention])
Advances the given date by the given period and adjusts it to be on a business day. Business day convention defaults to FOLLOWING.
- calendar:advance(date, days [, business_day_convention])
Moves the date forward or back by specified number of business days. Business day convention defaults to FOLLOWING.
Examples:
cal = redukti.calendar('USNY,GBLO') -- joint calendar
today = redukti.date() -- today's date
month_ago = cal:advance(today, "-1M", "FOLLOWING")
month_hence = cal:advance(today, "1M", "FOLLOWING")
print(today, month_ago, month_hence)
Day Count Fractions¶
- redukti.dayfraction(name)
Returns a Day Count Fraction object for the specified name - name must be ISDA / FpML compatible.
- dayfraction:fraction(d1, d2)
Calculates the day fraction between two dates.
Examples:
fraction = redukti.dayfraction('ACT/360')
today = redukti.date()
two_years_later = redukti.addperiod(today, "2Y")
print(fraction:fraction(today, two_years_later))
Indices¶
- redukti.index(currency, index_family, tenor)
Returns an index object
- redukti.index(isda_index, tenor)
Returns an index object
- index:maturity(value_date)
Returns maturity date given the value date, as per the index
- index:adjust_date(date, days)
Adds/subtracts the number of business days specified and adjusts the resulting date as per fixing calendar
- index:date_components(date)
Computes fixing date, value date and maturity date given the start date and returns all three
Examples:
idx = redukti.index('USD', 'LIBOR', '1W')
dt = redukti.date(23,10,2016)
adjusted = idx:adjust_date(dt, 1)
assert(adjusted == redukti.date(24,10,2016))
fixing_dt, value_dt, maturity_dt = idx:date_components(adjusted)
assert(maturity_dt == redukti.date(31,10,2016))
assert(value_dt == adjusted)
Automatic Differentiation¶
- redukti.adouble1{ n1, n2, … }
Returns an adouble object for each array value. The assumption is that the array values are part of a multivariate function, and therefore each value is treated as variable. The total number of variables is equal to the numeber of values in the array. The adouble objects are set up for first order derrivative computation. Note that the maximum number of allowed variables is 100 to keep memory usage in check.
- redukti.adouble1(n1, n2, …)
Same as above but input is in the form of parameters rather than an array.
- redukti.adouble2{ n1, n2, … }
As above, but the returned adouble objects are set up to compute second order derivatives too.
- redukti.adouble2(n1, n2, …)
Same as above but input is in the form of parameters rather than an array.
- adouble:gradient()
Returns the gradient as an array
- adouble:hessian()
Only available if second order derivatives are being calculated. The hessian is returned as a table of arrays where each row is an array.
- adouble:abs()
Returns the absolute value
- abouble:pow(n)
Returns adouble object raised to power n
- adouble:sqrt()
Return square root of adouble object
- adouble:exp()
Returns exp(adouble)
- adouble:log()
Returns log(adouble), where log is natural logarithm
- adouble:cos()
Returns cos(adouble)
- adouble:sin()
Return sin(adouble)
- adouble:tan()
Returns tan(adouble)
Examples:
-- compute derivate of x^2, where x = 5
x = redukti.adouble1(5.0)
ans = x:pow(2)
print(ans)
Above outputs:
{
value=25.0,
firstorder = {
[1] = 10.0
}
}
This tells you that the value of x^2 is 25.0, and derivative is 10.0 - i.e. 2*x, as you would expect.
Here is another example:
x, y, z = redukti.adouble2 {5.0, 3.0, 6.0}
-- compute x + y + z
added = x + y + z
multiplied = x * y * z
print(added)
print(multiplied)
Results in following output:
{
value=14.0,
firstorder = {
[1] = 1.0,
[2] = 1.0,
[3] = 1.0
}
secondorder = {
}
}
{
value=90.0,
firstorder = {
[1] = 18.0,
[2] = 30.0,
[3] = 15.0
}
secondorder = {
[1, 2] = 6.0,
[1, 3] = 3.0,
[2, 1] = 6.0,
[2, 3] = 5.0,
[3, 1] = 3.0,
[3, 2] = 5.0
}
}
Since the matrix data for a second order derivative can grow very large, the scripting api restricts the number of allowed variables in a single object to 100.
Another example:
x, y = redukti.adouble2 {6, 7}
ans = x:pow(2) * y:pow(2)
print(ans)
Results in:
{
value=1764.0,
firstorder = {
[1] = 588.0,
[2] = 504.0
}
secondorder = {
[1, 1] = 98.0,
[1, 2] = 168.0,
[2, 1] = 168.0,
[2, 2] = 72.0
}
}
Calculation Schedules¶
- redukti.schedule { parameters }
Builds a calculation schedule and returns 3 arrays : adjusted start dates, adjusted end dates, adjusted payment dates. Note that some payment dates may be set to 0 - this means that there is no payment in that calculation period. For instance when compounding, or in zero coupon streams, payments do not occur with every period.
The parameters may include following:
- effective_date
(required) unadjusted effective date - this defines the start of the schedule
- termination_date
(required if term not present) unadjusted termination date - this defines the end date of the schedule.
- term
(required if termination_date not present) term is the length of the transaction, e.g. 5Y.
- payment_frequency
(required) the frequency of payment, may be 1T for single payment, or supported tenor values upto 1Y.
- payment_day_convention
BusinessDayConvention to be used to adjust payment dates
- payment_business_centers
Business Centers to be use for computing payment holidays
- roll_convention
FpML defined RollConvention for deciding how to calculate period start/end dates
- calculation_frequency
the frequency of calculating accruals, also equal to the frequency at which resets occur for non-OIS streams. Must be <= payment frequency
- calculation_day_convention
the BusinessDayConvention to be used for adjusting calculation period dates
- calculation_business_centers
Business Centers to be used for computing holidays when adjusting calculation period dates
- first_regular_period_start_date
unadjusted start date of the first regular period, implies front stub
- last_regular_period_end_date
unadjusted end date of the last regular period, implies back stub
- first_payment_date
used if first payment does not occur at the first possible payment date
- last_regular_payment_date
used if last regular period payment date does not occur at the last possible regular payment date
Example:
t = {}
t.effective_date = redukti.date{1,1,2016}
t.termination_date = redukti.date{1,1,2017}
t.payment_frequency = "3M"
t.payment_business_centers = "GBLO,USNY"
t.payment_day_convention = "MODFOLLOWING"
starts, ends, pays = redukti.schedule(t)
function print_date(d)
local d,m,y = redukti.date_parts( d )
return string.format("%02d/%02d/%d", d, m, y)
end
for i=1,#starts do
print(i, ' adjusted start date ' .. print_date(starts[i]))
print(i, ' adjusted end date ' .. print_date(ends[i]))
if pays[i] ~= 0 then
print(i, 'adjusted payment date ' .. print_date(ends[i]))
else
print(i, ' no payment ')
end
end
This outputs:
1 adjusted start date 04/01/2016
1 adjusted end date 01/04/2016
1 adjusted payment date 01/04/2016
2 adjusted start date 01/04/2016
2 adjusted end date 01/07/2016
2 adjusted payment date 01/07/2016
3 adjusted start date 01/07/2016
3 adjusted end date 03/10/2016
3 adjusted payment date 03/10/2016
4 adjusted start date 03/10/2016
4 adjusted end date 03/01/2017
4 adjusted payment date 03/01/2017
Another example:
t = {}
t.effective_date = redukti.date{25,11,2016}
t.termination_date = redukti.date{25,11,2017}
t.payment_frequency = "3M"
t.payment_business_centers = "GBLO,USNY"
t.payment_day_convention = "MODFOLLOWING"
t.calculation_frequency = "1M"
t.calculation_business_centers = "GBLO,USNY"
t.calculation_day_convention = "MODFOLLOWING"
starts, ends, pays = redukti.schedule(t)
This time the output is:
1 adjusted start date 25/11/2016
1 adjusted end date 28/12/2016
1 no payment
2 adjusted start date 28/12/2016
2 adjusted end date 25/01/2017
2 no payment
3 adjusted start date 25/01/2017
3 adjusted end date 27/02/2017
3 adjusted payment date 27/02/2017
4 adjusted start date 27/02/2017
4 adjusted end date 27/03/2017
4 no payment
5 adjusted start date 27/03/2017
5 adjusted end date 25/04/2017
5 no payment
6 adjusted start date 25/04/2017
6 adjusted end date 25/05/2017
6 adjusted payment date 25/05/2017
7 adjusted start date 25/05/2017
7 adjusted end date 26/06/2017
7 no payment
8 adjusted start date 26/06/2017
8 adjusted end date 25/07/2017
8 no payment
9 adjusted start date 25/07/2017
9 adjusted end date 25/08/2017
9 adjusted payment date 25/08/2017
10 adjusted start date 25/08/2017
10 adjusted end date 25/09/2017
10 no payment
11 adjusted start date 25/09/2017
11 adjusted end date 25/10/2017
11 no payment
12 adjusted start date 25/10/2017
12 adjusted end date 27/11/2017
12 adjusted payment date 27/11/2017
Note that in the examples above I did not specify roll convention so this was inferred.
Interpolators¶
- redukti.interpolator { parameters }
Returns an interpolator object
Parameters can be following:
- x
values to be used for x axis
- y
values to be used for y axis (interpolation occurs in y axis)
- order
1 if first order derivatives are needed; 2 will generate second order derivatives also
- interpolator
The type of interpolator, e.g. Linear, LogLinear, CubicSplineNatural, LogCubicSplineNatural, MonotoneConvex
- interpolator:interpolate(x [, n])
Returns the interpolated value. If the optional parameter n is 1 the return value is an adouble containing the interpolated value as well as the derivatives computed using automatic differentiation. If the optional parameter n is 2 then the return value is an adouble but computed using numeric differentiation. The latter is for testing purposes only.
Examples:
x = {0.01, 0.02, 0.03, 0.04, 0.05}
y = {1000000.0, 20004.0, 300000.5, 4000000.0, 900000.0}
interp1 = redukti.interpolator {
x = x,
y = y,
interpolator = 'CubicSplineNatural',
order = 2
}
interp2 = redukti.interpolator {
x = x,
y = y,
interpolator = 'MonotoneConvex',
order = 2
}
print(interp1:interpolate(0.035, 1))
print(interp2:interpolate(0.035, 1))
Interest Rate Curves¶
- redukti.curve { parameters }
Sets up an interest rate curve. The parameters are as follows.
- reference_date
The date of the curve, all maturities are with respect to this date
- maturities
An array of maturity dates
- values
An array of numbers representing zero rates or discount factors
- value_type
‘ZeroRate’ or ‘DiscountFactor’ - indicates the type of value
- interpolator
Interpolator type. For ZeroRate curves, use Linear, CubicSplineNatural, MonotoneConvex. For discount factor curves, use LogLinear, LogCubicSplineNatural
- currency
Currency, forms part of curve’s id
- index_family
IndexFamily, forms part of curve’s id
- tenor
Curve’s tenor, forms part of curve’s id
- order
If 1 first order derivatives will be computed, if 2 additionally second order derivatives will be computed
- curve_type
‘Forward’ or ‘Discount’ - this is a logical marker for how the curve will be used, forms part of curve’s id
- curve:zero_rate(date)
Returns the zero rate
- curve:discount_factor(date)
Returns the discount factor
- curve:sensitivities(date)
Computes and returns sensitivities for given date with respect to the curve pillars.
- curve:values()
Returns three arrays - maturies, zero rates and discount factors
Examples:
As creating a curve manually is tedious, often it is easier to import data from files. For an example of this please see the the example in test_zerocurve.lua.
Time Series / Fixings¶
- redukti.fixing_service { data }
Creates a FixingService object. The data must be a table containing values indexed by Index type. Each value must be a table that has fixings indexed by date. That is, of the form:
{
[index1] = {
[date1] = index1value1,
[date2] = index1value2
},
[index2] = {
[date1] = index2value1,
[date2] = index2value2
}
}
- fixing_service:fixing(index, date)
Returns the fixing for given index and date. If not found then returns nil
Examples:
This too is easier to load from files, hence I will refer to the following script as an example.
Cashflows¶
- redukti.cashflows { data }
Sets up a CFCollection object and returns it.
The contents of { data }
mirrors the CFCollection protocol buffers type, except that it is expressed as a Lua table. Here is an example:
t =
{ -- Collection
-- first stream
{
-- cashflow
{
type = 'simple',
currency = 'USD',
amount = 40523611.1111111,
payment_date = redukti.date(6, 7, 2017)
},
-- cashflow
{
type = 'ois',
accrual_start_date = redukti.date(5, 7, 2016),
accrual_end_date = redukti.date(3, 7, 2017),
notional = 815000000,
index = 'USD-Federal Funds-H.15-OIS-COMPOUND',
day_count_fraction = 'ACT/360',
payment_date = redukti.date(6, 7, 2017)
},
-- cashflow
{
type = 'floating',
compounding_method = 'FLAT',
currency = 'USD',
day_count_fraction = 'ACT/360',
payment_date = redukti.date(26,10,2017),
periods = {
{
notional = 10000000,
accrual_start_date = redukti.date(26, 7, 2017),
accrual_end_date = redukti.date(28, 8, 2017),
index = 'USD-LIBOR-BBA',
tenor = '1M',
spread = -0.0009
},
{
notional = 10000000,
accrual_start_date = redukti.date(28, 8, 2017),
accrual_end_date = redukti.date(26, 9, 2017),
index = 'USD-LIBOR-BBA',
tenor = '1M',
spread = -0.0009
},
{
notional = 10000000,
accrual_start_date = redukti.date(26, 9, 2017),
accrual_end_date = redukti.date(26, 10, 2017),
index = 'USD-LIBOR-BBA',
tenor = '1M',
spread = -0.0009
}
}
}
},
-- second stream
{
-- cashflow
{
type = 'fra',
currency = 'USD',
day_count_fraction = 'ACT/360',
payment_date = redukti.date(8, 9, 2014),
notional = 15000000,
fixed_rate = 0.015,
accrual_start_date = redukti.date(8, 9, 2014),
accrual_end_date = redukti.date(20, 11, 2014),
index = 'USD-LIBOR-BBA',
tenor = '2M',
index2 = 'USD-LIBOR-BBA',
tenor2 = '3M',
}
}
}
flows = redukti.cashflows(t)
print(tostring(flows))
When you run this the output will dump the generated protocol buffers value in JSON like format.
Utility for Loading Data¶
The scripting api contains following utility for loading data from CSV files.
- redukti.loadcsv { parameters }
Loads data from a CSV file. Returns a table where each element represents a row in the CSV file.
Following parameters are supported:
- file
Specifies the path and name of the file to read from
- conversion
Contains a string where each character represents a conversion rule for a column. Following rules are allowed:
- ‘s’
Intepret as string field
- ‘n’
Interpret as number field
- ‘i’
Interpret as integer field
- ‘d’
Interpret as date field
- ‘-‘
Ignore column, field set to nil
- headings
A value of true means that the source file has headings
- fields
A value of true means that each field will be named by the column heading
Suppose that a file contains:
index,tenor,date,fixing
EUR-EONIA-OIS-COMPOUND,1D,02/01/2007,0.036
EUR-EURIBOR-Reuters,1W,02/01/2007,0.03614
EUR-EURIBOR-Reuters,2W,02/01/2007,0.03615
EUR-EURIBOR-Reuters,1M,02/01/2007,0.03629
EUR-EURIBOR-Reuters,3M,02/01/2007,0.03725
EUR-EURIBOR-Reuters,6M,02/01/2007,0.03857
EUR-EURIBOR-Reuters,12M,02/01/2007,0.0403
EUR-EONIA-OIS-COMPOUND,1D,03/01/2007,0.036
Then we can load this using following:
fixings = redukti.loadcsv { file=filename, conversion='ssdn', heading=true, fields=true }
Here is a dump of the first three lines of the table:
> table_print(fixings)
[1] => table
(
[tenor] => 1D
[index] => EUR-EONIA-OIS-COMPOUND
[fixing] => 0.036
[date] => 39084
)
[2] => table
(
[tenor] => 1W
[index] => EUR-EURIBOR-Reuters
[fixing] => 0.03614
[date] => 39084
)
[3] => table
(
[tenor] => 2W
[index] => EUR-EURIBOR-Reuters
[fixing] => 0.03615
[date] => 39084
)
Building Curves¶
- redukti.build_curves( business_date, curve_definitions, par_rates [, pricing_script] )
Builds a set of Zero Rate curves from par rates. Requires curve definitions and par rates as input.
- curve_definitions
The curve definitions must be presented as a table that mirrors the IRCurveDefinition protocol buffers message type. Values must be keyed by the IRCurveDefinition.id. Each value must be a table conatining the fields corresponding to an IRCurveDefinition. These are:
- group
CurveGroup
- curve_id
ID of the curve
- interpolator
Interpolator to be used, e.g. Linear
- currency
Currency of the curve
- index_family
IndexFamily
- interpolated_on
‘ZeroRate’ or ‘DiscountFactor’
- curve_tenor
Tenor of the curve
- maturity_generation_rule
Specifies how maturities for instruments are derived
- tenors
Optional list of tenor values used if maturities are derived from fixed tenors
- par_rates
The input par rates must be presented as a table. The elements in the table must have following fields.
- curve_id
a IRCurveDefinition.id that is defined in the curve definitions
- instrument_type
The type of instrument. This is mapped to a Ravi / Lua scripting function name.
- instrument_id
The id of the instrument - this has to be in a specific format.
- par_rate
The par rate
- forward_curve_id
IRCurveDefinition.id of the curve to be used for forward rates
- discount_curve_id
IRCurveDefinition.id of the curve to be used for discounting
- floating_tenor
The tenor to be used on floating leg of the instrument.
- pricing_script
This is a Lua script that is responsible for generating the cashflow structure for each instrument used in the curve. See the default script named
pricing.lua
that is supplied with OpenRedukti. If a name isn’t supplied the script defaults to the one used when building OpenRedukti; this is useful for testing but not very good for deployment as the path to the script is baked in at compile time!
Examples:
Please see the function build_curves
in utils.lua.
Cashflow Pricing¶
This is complex process involving several steps.
First of all you need a set of zero curves, either bootstrapped from par rates, or obtained from another source.
You need to setup a curve mapper.
You need fixings.
You need to setup a ValuationContext.
You then convert the Cashflows to an internal format ready for pricing.
Next you need to setup a curve provider.
Finally you invoke the pricing function to compute the PV and the sensitivities of the cashflows.
Curve Mapper¶
The purpose of the Curve Mapper is to allow mapping of logical curves, so that the cashflow generator can reference curves without knowing how these curves will actually be delivered. So this provides a level of indirection.
The api is described below.
- redukti.curve_mapper()
Sets up a curve mapper object
- redukti.pricing_curve_id { parameters }
Returns a logical curve id. The parameters are:
- curve_type
‘Forward’ or ‘Discount’
- currency
Currency
- index_family
IndexFamily
- tenor
Optional tenor of the curve
- curve_mapper:add_mapping( from_id, to_id )
This sets up a mapping from ‘from_id’ to ‘to_id’. Both ids must be pricing_curve_ids.
Example:
curve_mapper = redukti.curve_mapper()
f_eonia_id = redukti.pricing_curve_id { curve_type = 'F', currency = 'EUR', index_family = 'EONIA'}
d_eonia_id = redukti.pricing_curve_id { curve_type = 'D', currency = 'EUR' }
d_euribor_id = redukti.pricing_curve_id { curve_type = 'D', currency = 'EUR', index_family = 'EURIBOR'}
f_euribor_1m_id = redukti.pricing_curve_id { curve_type = 'F', currency = 'EUR', index_family = 'EURIBOR', tenor = '1M'}
f_euribor_3m_id = redukti.pricing_curve_id { curve_type = 'F', currency = 'EUR', index_family = 'EURIBOR', tenor = '3M'}
f_euribor_6m_id = redukti.pricing_curve_id { curve_type = 'F', currency = 'EUR', index_family = 'EURIBOR', tenor = '6M'}
f_euribor_12m_id = redukti.pricing_curve_id { curve_type = 'F', currency = 'EUR', index_family = 'EURIBOR', tenor = '12M'}
d_euribor_1m_id = redukti.pricing_curve_id { curve_type = 'D', currency = 'EUR', index_family = 'EURIBOR', tenor = '1M'}
d_euribor_3m_id = redukti.pricing_curve_id { curve_type = 'D', currency = 'EUR', index_family = 'EURIBOR', tenor = '3M'}
d_euribor_6m_id = redukti.pricing_curve_id { curve_type = 'D', currency = 'EUR', index_family = 'EURIBOR', tenor = '6M'}
d_euribor_12m_id = redukti.pricing_curve_id { curve_type = 'D', currency = 'EUR', index_family = 'EURIBOR', tenor = '12M'}
f_euribor_id = redukti.pricing_curve_id { curve_type = 'F', currency = 'EUR', index_family = 'EURIBOR'}
-- map request for forward EONIA curve to discount curve
curve_mapper:add_mapping( f_eonia_id, d_eonia_id )
-- map any request for EURIBOR Discount to EONIA discount
curve_mapper:add_mapping( d_euribor_id, d_eonia_id )
-- map euribor 1m to generic
curve_mapper:add_mapping( f_euribor_1m_id, f_euribor_id )
-- map euribor 12m to generic
curve_mapper:add_mapping( f_euribor_1m_id, f_euribor_id )
ValuationContext¶
- redukti.valuation_context( parameters, fixing_service)
Sets up a ValuationContex object.
- parameters
Table containing parameters. Parameters are:
- reference_date
Business date
- order
If 1 first order derivatives will be computed, if 2, second order derivatives will be computed as well.
- fixing_service
A FixingService object
Example:
utils = assert(require('utils'))
fixing_service = utils.load_fixings('../testdata/20121211/fixings.csv')
business_date = redukti.date('2012/12/11')
valuation_context = redukti.valuation_context({ reference_date = business_date, order = 1 }, fixing_service)
Cashflow Conversion¶
- redukti.prepare_cashflows_for_pricing(valuation_context, curve_mapper, cashflows)
Converts the supplied cashflows to a format suitable for pricing.
Example:
flows = deposit_rate(redukti.date(25, 7, 2013), 'EUR', 'EURIBOR', '1Y', 0.00140)
pricing_cashflows = redukti.prepare_cashflows_for_pricing(valuation_context, curve_mapper, flows)
CurveProvider¶
The CurveProvider resolves logical curve ids and maps these to actual curve objects.
- redukti.curve_provider()
Creates a curve_provider object.
- curve_provider:add_mapping(pricing_curve_id, curve)
Adds a mapping from a pricing_curve_id to a Zero Curve object.
Example:
Please see the script test_pricing.lua.
Calculate NPV and Sensitivities¶
Finally you can invoke:
- redukti.present_value(valuation_context, pricing_cashflows, curve_provider)
Computes the NPV and sensitivities and returns a PricingResult object.
- pricing_result:ok()
Tells if you pricing was successful
- pricing_result:curve_ids()
Returns an array of curve identifiers used for pricing
- pricing_result:delta(curve_id)
Given a curve id, returns the first order sensitivities as an table of values keyed by curve pillars.
Example:
Please see the script test_pricing.lua.