# Sanity check - How to price callables

This question is meant as a sanity check whether i got the workflow right for pricing callable bonds. If anyone finds a mistake, or has a suggestion, please answer.

The workflow is:

1. For every call date calculate:
• The probability that the bond is called
• The plain vanilla price of the bond as if it had a maturity to the call date
2. Calculate the weighted average price of the bond with the following code

`

````# Assume a callable with call dates t = 1...T-1 and normal maturity T
# CallProps - Vec of Probabilities that the bond is called at times t
# FullPrices - Vec of prices of a bond if it had maturity at t, T.
NoCallProps = 1-CallProps
CumNoCallProps = c(1,cumprod(NoCallProps))
WeightedPrice = 0

for(i in 1:length(FullPrices))
{
WeightedPrice = WeightedPrice + CumNoCallProps[i] * (CallProps[i] * FullPrices[i])
}
````

`

The call propabilities are calculated by Monte Carlo:

• take the current yield and simulate rate development between now and the call date with a CIR process (taken from the MATLAB library and adapted to R)
• compare the yield at the call date with the coupon of the bond, and call, if the yield is lower than the coupon
• Calculate the average of the calls for the number of replications.
-

The code above has no commenting and the variables are not well defined. You should at a minimum be using pseudocode if you want any feedback. This algo seems to be missing the recursive dynamic I describe but since the variables are not defined no one can evaluate this. – Quant Guy Jun 30 '12 at 15:04

## 1 Answer

You have the right intuition but the approach is not quite right.

The issuer has the right to call back the bond at a pre-defined call price. So your decision criterion is "call when the value of the bond >= contractual call price". We are comparing prices in the decision rule, not the YTM of the callable bond with the coupon of the bond.

Note that typically the call price is above par value (reflecting a call premium).

So you need to value the bond under various interest rate scenarios according to your Monte Carlo simulation. After you simulate your interest rate paths, you will also need to use a recursive backward induction algorithm to value the callable bond at each node in a binomial tree. Take a weighted average of bond prices along each interest rate path to arrive at the value of the bond (first starting at the terminal nodes at maturity then working to back to the present day) remembering to use the discount rate prevailing at that point in time. Also, at any node you assign the call value in lieu of an otherwise option-free bond value wherever the option-free bond value is greater than the callable price (since these are the cases where it is rational for the issuer to call the bond). This is depicted in Node(D,D) below.

This is best visualized by a binomial tree:

Some examples are in the attached paper by Frank Fabozzi.

-

Thanks for the reply. Seems I have taken a shortcut assuming a call price of 100 in every case - should I be able to expect the users that they will be able to provide the call price (this is for a software to calculate Solvency II risks in the standard formula). Theoretically I am using a truncated tree, in which i either have a terminal node in each date, if the bond is called with probability $p_t$, or the bond is not called, and i get to the next node with $1-p_t$ – Owe Jessen Jul 2 '12 at 8:04
{"extraction_info": {"found_math": true, "script_math_tex": 0, "script_math_asciimath": 0, "math_annotations": 0, "math_alttext": 0, "mathml": 0, "mathjax_tag": 0, "mathjax_inline_tex": 2, "mathjax_display_tex": 0, "mathjax_asciimath": 0, "img_math": 0, "codecogs_latex": 0, "wp_latex": 0, "mimetex.cgi": 0, "/images/math/codecogs": 0, "mathtex.cgi": 0}, "config": {"markdown_headings": true, "markdown_code": true, "boilerplate_config": {"ratio_threshold": 0.18, "absolute_threshold": 10, "end_threshold": 15, "enable": true}, "remove_buttons": true, "remove_image_figures": true, "remove_link_clusters": true, "table_config": {"min_rows": 2, "min_cols": 3, "format": "github"}, "remove_chinese": true, "remove_edit_buttons": true, "extract_latex": true}, "english_confidence": 0.9164083003997803, "perplexity_flag": "middle"}