QuantLib: Building Key Rate Risks - python-3.x

I was able to build a discount curve for the Treasury market. However, I'm looking to use this to find the key rate risks of an individual bond (and eventually a portfolio of bonds).
The key rate risk I'm looking for is if I have a 30Y bond and we shift the 1y rate that was used to discount the bond, while holding the other rates constant, how much does the price of the bond change by? Repeating this for the tenors (eg. 2Y, 5Y, 7Y, etc) and summing the result should get you to the overall duration of the bond, but provides a better view of how the risk exposure breaks down.
http://www.investinganswers.com/financial-dictionary/bonds/key-rate-duration-6725
Is anyone aware of any documentation that demonstrates how to do this? Thank you.

Given that you have already built the bond and the discount curve, and you have linked them in some way similar to:
discount_handle = RelinkableYieldTermStructureHandle(discount_curve)
bond.setPricingEngine(DiscountingBondEngine(discount_handle))
you can first add a spread over the existing discount curve and then use the modified curve to price the bond. Something like:
nodes = [ 1, 2, 5, 7, 10 ] # the durations
dates = [ today + Period(n, Years) for n in nodes ]
spreads = [ SimpleQuote(0.0) for n in nodes ] # null spreads to begin
new_curve = SpreadedLinearZeroInterpolatedTermStructure(
YieldTermStructureHandle(discount_curve),
[ QuoteHandle(q) for q in spreads ],
dates)
will give you a new curve with initial spreads all at 0 (and a horrible class name) that you can use instead of the original discount curve:
discount_handle.linkTo(new_curve)
After the above, the bond should still return the same price (since the spreads are all null).
When you want to calculate a particular key-rate duration, you can move the corresponding quote: for instance, if you want to bump the 5-years quote (the third in the list above), execute
spreads[2].setValue(0.001) # 10 bps
the curve will update accordingly, and the bond price should change.
A note: the above will interpolate between spreads, so if you move the 5-years points by 10 bps and you leave the 2-years point unchanged, then a rate around 3 years would move by about 3 bps. To mitigate this (in case that's not what you want), you can add more points to the curve and restrict the range that varies. For instance, if you add a point at 5 years minus one month and another at 5 years plus 1 month, then moving the 5-years point will only affect the two months around it.

Related

Excel Solver issues

I want to setup a system by which employees have a set number of points that they can use to weight against each holiday, basically if they don't want to work on a certain holiday they would set a large number of points on that day. We would then setup holiday assignments such that there are two people on each holiday and each person works 2 holidays; there are 8 employees with 8 "holidays", so the matrix is 8x8.
I setup a preference array that has a preference number for each employee, call it P.
I setup an assignment array for year 1, call it Y1.
I then take SUM(P*Y1) to get the total points for Year 1.
I solve to minimize SUM(P*Y1), subject to the constraints above: 2 holidays/employee, 2 employees/holiday. Assignments are integers <=1.
The solver gives a solution that looks reasonable.
I then repeat the formula above, but I use a new assignment array for year 2, Y2.
I then setup a matrix of Y1+Y2, giving the total points over two years.
I also setup a matrix of Y1*Y2=0, ie no repeat assignments.
I use Solver to minimize SUM(PY1+PY2) by changing the year 2 assignments, Y2. Again, with the constraints of 2 employees per holiday, 2 holidays per employee.
I expect it to give me the second lowest point total possible. It does not, it gives me the same solution as in Y1, and Y1Y2<>0.
Is this my math, or is it the Solver? It gives the absolute minimum without following the constraint of not repeating any values, ie Y1Y2=0.

How to create exponential growth in excel over a year

So I am trying to build an excel model where every month the numbers will increase exponentially to a point at the end of the year which is driven by annual expectations. Currently I have it divided by 12 and each year there are huge jumps over the previous making the chart/growth very jumpy. For illustration purposes, lets say for 2020 the desired number for the year is 12. In the current state, I would get 1 per month (12/12), however, what I want is for it to be growing gradually/exponentially, so for example 0.2, 0.5, 0.9 etc with December being the largest, and the sum for the entire year equaling 12. Then the next year (2021), starting in January, it would take into account the December 2020 number and grow from there again to the desired number (lets say total 24 for 2021) and so on. I'd love for it to have a more exponential / hockey stick-like growth.
What would be a good way to do this?
The function RRI can be used to find an interest rate which will give you a given target value. This can be used to find terms in a geometric series which have a given sum (which is what you seem to be asking for).
For example, say you want 12 exponentially increasing numbers which, when added to 100, gets you to 2000. Starting with 100, repeatedly multiply by (1 + RRI(12,100,2000)). To get the numbers that you want (which will be 12 numbers which sum to 1900) just calculate the difference each month:
I think the simplest way to solve this is by using Goal Seek. First you need to build a sheet like this:
You choose the starting value in January (B1) and every month is a constant growth rate (D1) bigger than the previous month. You also calculate the total sum at the bottom in B13.
Now you use goal seek to find the growth rate which makes the sum equal to 12:
The answer I get for a starting value of 0.1 is a growth rate of 1.376:

Estimating linear fit as a moving average

Say I have the following data:
Year Day Amount
2015 1 2
2015 2 3
2015 3 4
2015 4 5
Using window functions or aggregations, I want to get a number for each row that represents the "linearity based on the previous n rows". In this simple example, for the row with day = 4, linearity would be pretty high, for obvious reasons, based on the previous n days, where n is 3.
Issues pop up when some of the previous days do not exist, and in that case, I would just want to use a default value of -1, for example to indicate otherwise.
I don't have an exact value I want to represent the linearity, but as an example, similar to correlation coefficients, 1 could represent high linearity, while 0 none.
Edit:
What I have done as a makeshift use-case was add a column to each row representing the day (and taking year into account), and used a window function, with lag to find the previous 4 values (if they existed). After getting (or not getting these values), I made a simple calculation to calculate the difference of each combination of points, and used division to see how close they were to each other (1 would be the best). I apologize, I cannot share any code due to an agreement of code sharing.
generate series with all dates you want to estimate
left outer join it with input
replace null values for Amount with a valuet to estimate
convert to RDD
generate keys with lower bound -> for 2015 4 generate keys [2015 4, 2015 3, 2015 2] amd flatten
groupByKey
estimate for groups

FV and PV formula's in Excel

I'm trying to calculate a lifetime value of a customer. Let's assume a new customer pays $100K per year and stays for 5 years. Let's discount any future years' payments with 10% rate.
This is manual calculation:
Year 1 $100,000.00
Year 2 $90,000.00
Year 3 $81,000.00
Year 4 $72,900.00
Year 5 $65,610.00
---------------------
Total $409,510.00
I can get the same value by using FV with negative rate.
FV(-0.1,5,-100000,0,0) = $409,510.00
What I'm trying to do is to get the same value using PV. And it's not exactly the same:
PV(0.1,5,-100000,0,1) = $416,986.54
I'm not sure what am I missing here. Does MS Office Excel 2010 PV understand discounting differently?
If you calculate out what PV is doing manually, the formula is actually this, for each individual year:
=Base Amount / (1 + Discount Rate) ^ Periods
Vs what FV is doing manually, the formula is this (which you seem to know based on coming to the same answer in your data):
=Base Amount * (1 - Discount Rate) ^ Periods
The reason for the difference in calculation is the mathematical difference between the two items - for background see here: http://www.investopedia.com/walkthrough/corporate-finance/3/time-value-money/future-value.aspx and here: http://www.investopedia.com/walkthrough/corporate-finance/3/time-value-money/present-value-discounting.aspx.
In short, if you have $100k today, and invest it in something which gives you 10% each year, then each year you add 10% of the current balance to get the new balance. ie: in year 1 you add 100k * 10% = 10k, giving a new total of 110k; in year 2 you add 110k * 10% = 11k, giving a new total of 121k, etc. - Mathematically, each year's amount is given by the formula listed above for the FV calculation.
Where this gets tricky is that you are giving yourself a negative interest rate - meaning every year, the value is decreasing each year by 10%. You have attempted to use the FV calculation with a negative interest rate, but that's not quite correct. What you should be using is the PV formula.
For the PV formula, if you know that you will receive 100k each year, you need to determine how much cash you would have needed originally, in order to earn the same amount - that is the present value of the cash flow stream. Now, you need to 'gross-up' the value of each year's income stream. The formula for this gross-up is derived mathematically and results in what I have above there for PV. Think about it like this - if there's a shirt that normally costs $100 and is now 30% off, you can see that you simply multiply it by 30%, to get $70. But if you see of shirt on sale for $70, and it's 30% off, then to determine the original base price you need to take $70 & divide by .3 - which gives us $100.
To prove to yourself that the PV formula is appropriate, take the income stream of, say, year 4 [3 periods of interest later, assuming first payment is received in day 0]: 100k / (1 + 10%)^3 = $75,131. Now, work backwards - if you want to know the future value of a $75k investment held for 3 periods of interest compounded annually with a 10% annual rate, you go: 75,131 * (1 + 10%) ^ 3 = 100k.
This is an important financial distinction, and you should read over the sources I've linked to ensure you understand it.
There is a difference in the calculation. FV takes 100,000 and discounts it by 10% to the number X so that X is 90% of the original value (i.e. X=90,000). PV by contrast discounts it to the number X such that 100,000 is 10% more than X. Quick math says X will be 10/11 of 100,000, i.e. 90909.09.
Indeed, if we apply this calculation 5 times:
Year 1 $100,000.00
Year 2 $90,909.09
Year 3 $82,644.63
Year 4 $75,131.48
Year 5 $68,301.35
---------------------
Total $416,986.5
I don't know if there is a way to make them behave the same way (I don't think there is, as they're calculating different things), but since FV solves your problem why not just use that?

Trying to either pull or recreate trendline data using LINEST

I am trying to recreate the formula from a trendline on a graph. basically my company is trying to predict the corn yields for next year. all of the actual programmers are out for the week so they passed it on to me(web developer:D). Ive attempted the LINEST formula multiple times with no luck.
basically in column B I have the years(1-15, trying to project 16) and Column C i have the actual trend data. i am probably doing this wrong however
EX =LINEST(C16:C30,B16:B30,FALSE,FALSE)
Any help would be appreciated. just tell me if you need the actual file or more information. Thanks in advance!
The fourth argument, concerning the return of additional regression statistics, is optional and is taken as FALSE if omitted, so seems not required for your purposes. The third argument, concerning the intercept with the Y-axis (the value of y when x is 0), is also optional but taken as TRUE if omitted. In your case TRUE seems appropriate so the third parameter seems not required for your purposes.
With your data spanning 15 years, if ending with the current year, it is conveniently 2001-2015 bdi and has no information about the value of y (production) in year 2000 (ie when x is 0) but this is unlikely to have been 0, as would be taken to be the case if the third argument is FALSE.
In a simplified example, take production of 50 in 2001, increasing by an (unrealistically!) constant 5 each year. By 2015 this has reached 120, so for 2016 at the same rate of increase production of 125 should be expected. Your formula returns 9.35 so would predict production of 129.35, though we know to expect 125, as given by:
=LINEST(C16:C30,B16:B30)
when added to the latest available (120).
The former is too high a predicted increase because it assumes growth was from 0 to 120 in sixteen years, rather than what I have taken to be from 50 to 120 in fifteen.
As has been mentioned by #Byron Wall, Excel has the TREND function that may be used for linear extrapolation to obtain the next (16th) value like so:
=TREND(C16:C30,B16:B30,16)
This directly returns 125 for the, simplified, sample data.
HOWEVER, all the above assumes growth is linear. Taking say Brazilian corn production (Million tons) over the period (offset one year) this has been roughly (based on USDA.gov):
The red line is the Linear trend and green a fourth order Polynomial. They happen both to end up at the same place for one year ahead (the hollow bar) but predict different results from the latest six years:
It may be worth charting the data you have, and adding different trend lines, before deciding whether linear extrapolation seems the most promising for forecasting purposes. ‘Wavy’ (cyclical) progress is evident in many datasets.

Resources