Main Content

Pricing and Hedging a Portfolio Using the Black-Karasinski Model

This example illustrates how MATLAB® can be used to create a portfolio of interest-rate derivatives securities, and price it using the Black-Karasinski interest-rate model. The example also shows some hedging strategies to minimize exposure to market movements.

Create the Interest-Rate Term Structure Based on Reported Data

The structure RateSpec is an interest-rate term structure that defines the initial rate specification from which the tree rates are derived. Use the information of annualized zero coupon rates in the table below to populate the RateSpec structure.

  From             To           Rate
27 Feb 2007    27 Feb 2008      0.0493
27 Feb 2007    27 Feb 2009      0.0459
27 Feb 2007    27 Feb 2010      0.0450
27 Feb 2007    27 Feb 2012      0.0446
27 Feb 2007    27 Feb 2014      0.0445
27 Feb 2007    27 Feb 2017      0.0450
27 Feb 2007    27 Feb 2027      0.0473

This data could be retrieved from the Federal Reserve Statistical Release page by using the Datafeed Toolbox™. In this case, the Datafeed Toolbox™ will connect to FRED® and pull back the rates of the following treasury notes.

  Terms    Symbol
 =======   ======
    1   =  DGS1
    2   =  DGS2
    3   =  DGS3
    5   =  DGS5
    7   =  DGS7
    10  =  DGS10
    20  =  DGS20

Create the connection object:

  c = fred;

Create the symbol fetch list:

FredNames   = { ...    
  'DGS1'; ...      % 1  Year
  'DGS2'; ...      % 2  Year
  'DGS3'; ...      % 3  Year
  'DGS5'; ...      % 5  Year
  'DGS7'; ...      % 7  Year
  'DGS10'; ...     % 10 Year
  'DGS20'};        % 20 Year

Define the Terms:

Terms = [ 1; ...      % 1  Year
          2; ...      % 2  Year
          3; ...      % 3  Year
          5; ...      % 5  Year
          7; ...      % 7  Year
         10; ...      % 10 Year
         20];         % 20 Year

Set the StartDate to Feb 27, 2007:

  StartDate = datenum('Feb-27-2007');
  FredRet = fetch(c,FredNames,StartDate); 

Set the ValuationDate based on the StartDate:

  ValuationDate = StartDate;
  EndDates = [];
  Rates =[];

Create the EndDates:

  for idx = 1:length(FredRet)    
   %Pull the rates associated with Feb 27, 2007. All the Fred Rates come
   %back as percents
   Rates = [Rates; ...
       FredRet(idx).Data(1,2) / 100];
    %Determine the EndDates by adding the Term to the year of the
    %StartDate      
    EndDates = [EndDates; ...
       round(datenum(...
           year(StartDate)+ Terms(idx,1), ...
           month(StartDate),...
           day(StartDate)))];
  end

Use the function intenvset to create the RateSpec with the following data:

Compounding = 1;
StartDate = datetime(2007,2,27);
Rates = [0.0493; 0.0459; 0.0450; 0.0446; 0.0446; 0.0450; 0.0473];
EndDates = [datetime(2008,2,27); datetime(2009,2,27) ; datetime(2010,2,27) ; datetime(2012,2,27) ; datetime(2014,2,27) ; datetime(2017,2,27) ; datetime(2027,2,27)];  
ValuationDate = StartDate;

RateSpec = intenvset('Compounding',Compounding,'StartDates', StartDate,...
                     'EndDates', EndDates, 'Rates', Rates,'ValuationDate', ValuationDate)
RateSpec = struct with fields:
           FinObj: 'RateSpec'
      Compounding: 1
             Disc: [7x1 double]
            Rates: [7x1 double]
         EndTimes: [7x1 double]
       StartTimes: [7x1 double]
         EndDates: [7x1 double]
       StartDates: 733100
    ValuationDate: 733100
            Basis: 0
     EndMonthRule: 1

Specify the Volatility Model

Create the structure VolSpec that specifies the volatility process with the following data.

Volatility = [0.011892; 0.01563; 0.02021; 0.02125; 0.02165; 0.02065; 0.01803];
Alpha = [0.0001];
VolSpec = bkvolspec(ValuationDate, EndDates, Volatility, EndDates(end), Alpha)
VolSpec = struct with fields:
             FinObj: 'BKVolSpec'
      ValuationDate: 733100
           VolDates: [7x1 double]
           VolCurve: [7x1 double]
         AlphaCurve: 1.0000e-04
         AlphaDates: 740405
    VolInterpMethod: 'linear'

Specify the Time Structure of the Tree

The structure TimeSpec specifies the time structure for an interest-rate tree. This structure defines the mapping between the observation times at each level of the tree and the corresponding dates.

TimeSpec = bktimespec(ValuationDate, EndDates)
TimeSpec = struct with fields:
           FinObj: 'BKTimeSpec'
    ValuationDate: 733100
         Maturity: [7x1 double]
      Compounding: -1
            Basis: 0
     EndMonthRule: 1

Create the BK Tree

Use the previously computed values for RateSpec, VolSpec, and TimeSpec to create the BK tree.

BKTree = bktree(VolSpec, RateSpec, TimeSpec)
BKTree = struct with fields:
      FinObj: 'BKFwdTree'
     VolSpec: [1x1 struct]
    TimeSpec: [1x1 struct]
    RateSpec: [1x1 struct]
        tObs: [0 1 2 3 5 7 10]
        dObs: [733100 733465 733831 734196 734926 735657 736753]
      CFlowT: {[7x1 double]  [6x1 double]  [5x1 double]  [4x1 double]  [3x1 double]  [2x1 double]  [20]}
       Probs: {[3x1 double]  [3x3 double]  [3x5 double]  [3x7 double]  [3x7 double]  [3x9 double]}
     Connect: {[2]  [2 3 4]  [2 3 4 5 6]  [2 3 3 4 5 5 6]  [2 3 4 5 6 7 8]  [2 2 3 4 5 6 7 8 8]}
     FwdTree: {[1.0493]  [1.0434 1.0425 1.0416]  [1.0457 1.0444 1.0432 1.0420 1.0409]  [1.1003 1.0967 1.0933 1.0899 1.0867 1.0836 1.0806]  [1.1073 1.1016 1.0962 1.0911 1.0863 1.0818 1.0775]  [1x9 double]  [1x9 double]}

Visualize the interest rate evolution along the tree by looking at the output structure BKTree. The function bktree returns an inverse discount tree, which you can convert into an interest rate tree with the cvtree function.

BKTreeR = cvtree(BKTree)
BKTreeR = struct with fields:
      FinObj: 'BKRateTree'
     VolSpec: [1x1 struct]
    TimeSpec: [1x1 struct]
    RateSpec: [1x1 struct]
        tObs: [0 1 2 3 5 7 10]
        dObs: [733100 733465 733831 734196 734926 735657 736753]
      CFlowT: {[7x1 double]  [6x1 double]  [5x1 double]  [4x1 double]  [3x1 double]  [2x1 double]  [20]}
       Probs: {[3x1 double]  [3x3 double]  [3x5 double]  [3x7 double]  [3x7 double]  [3x9 double]}
     Connect: {[2]  [2 3 4]  [2 3 4 5 6]  [2 3 3 4 5 5 6]  [2 3 4 5 6 7 8]  [2 2 3 4 5 6 7 8 8]}
    RateTree: {[0.0481]  [0.0425 0.0416 0.0408]  [0.0446 0.0434 0.0423 0.0412 0.0401]  [0.0478 0.0462 0.0446 0.0430 0.0416 0.0401 0.0388]  [0.0510 0.0484 0.0459 0.0436 0.0414 0.0393 0.0373]  [1x9 double]  [1x9 double]}

Look at the upper, middle and lower branch paths of the tree.

OldFormat = get(0, 'format');  
format short

%Rate at root node:
RateRoot      = trintreepath(BKTreeR, 0) 
RateRoot = 0.0481
%Rates along upper branch:
RatePathUp    = trintreepath(BKTreeR, [1 1 1 1 1 1]) 
RatePathUp = 7×1

    0.0481
    0.0425
    0.0446
    0.0478
    0.0510
    0.0555
    0.0620

%Rates along middle branch:
RatePathMiddle = trintreepath(BKTreeR, [2 2 2 2 2 2]) 
RatePathMiddle = 7×1

    0.0481
    0.0416
    0.0423
    0.0430
    0.0436
    0.0449
    0.0484

%Rates along lower branch:
RatePathDown = trintreepath(BKTreeR, [3 3 3 3 3 3])
RatePathDown = 7×1

    0.0481
    0.0408
    0.0401
    0.0388
    0.0373
    0.0363
    0.0378

You can also display a graphical representation of the tree to examine interactively the rates on the nodes of the tree until maturity. The function treeviewer displays the structure of the rate tree in the left window. The tree visualization in the right window is blank, but by selecting Table/Diagram and clicking on the nodes you can examine the rates along the paths.

treeviewer(BKTreeR);

Figure Tree Viewer contains 2 axes objects and other objects of type uicontrol. Axes object 1 contains 137 objects of type line. Axes object 2 is empty.

Create an Instrument Portfolio

Create a portfolio consisting of two bonds instruments and an option on the 5% bond.

% Two Bonds
CouponRate = [0.04;0.05]; 
Settle = datetime(2007,2,27); 
Maturity = [datetime(2009,2,27) ; datetime(2010,2,27) ];
Period = 1;

% American Option on the 5% Bond
OptSpec = {'call'};
Strike = 98;
ExerciseDates = datetime(2010,2,27);
AmericanOpt = 1;

InstSet = instadd('Bond', CouponRate, Settle,  Maturity, Period);
InstSet = instadd(InstSet,'OptBond', 2, OptSpec, Strike, ExerciseDates, AmericanOpt);

% Assign Names and Holdings
Holdings = [10; 15;3];
Names = {'4% Bond'; '5% Bond'; 'Option 98'};

InstSet = instsetfield(InstSet, 'Index',1:3, 'FieldName', {'Quantity'}, 'Data', Holdings );
InstSet = instsetfield(InstSet, 'Index',1:3, 'FieldName', {'Name'}, 'Data', Names );

Examine the set of instruments contained in the variable InstSet.

instdisp(InstSet)
Index Type CouponRate Settle         Maturity       Period Basis EndMonthRule IssueDate FirstCouponDate LastCouponDate StartDate Face Quantity Name     
1     Bond 0.04       27-Feb-2007    27-Feb-2009    1      0     1            NaN       NaN             NaN            NaN       100  10       4% Bond  
2     Bond 0.05       27-Feb-2007    27-Feb-2010    1      0     1            NaN       NaN             NaN            NaN       100  15       5% Bond  
 
Index Type    UnderInd OptSpec Strike ExerciseDates  AmericanOpt Quantity Name     
3     OptBond 2        call    98     27-Feb-2010    1           3        Option 98
 

Price the Portfolio Using the BK Model

Calculate the price of each instrument in the portfolio.

[Price, PTree] = bkprice(BKTree, InstSet)
Price = 3×1

   98.8841
  101.3470
    3.3470

PTree = struct with fields:
     FinObj: 'BKPriceTree'
      PTree: {[3x1 double]  [3x3 double]  [3x5 double]  [3x7 double]  [3x7 double]  [3x9 double]  [3x9 double]  [3x9 double]}
     AITree: {[3x1 double]  [3x3 double]  [3x5 double]  [3x7 double]  [3x7 double]  [3x9 double]  [3x9 double]  [3x9 double]}
     ExTree: {[3x1 double]  [3x3 double]  [3x5 double]  [3x7 double]  [3x7 double]  [3x9 double]  [3x9 double]  [3x9 double]}
       tObs: [0 1 2 3 5 7 10 20]
    Connect: {[2]  [2 3 4]  [2 3 4 5 6]  [2 3 3 4 5 5 6]  [2 3 4 5 6 7 8]  [2 2 3 4 5 6 7 8 8]}
      Probs: {[3x1 double]  [3x3 double]  [3x5 double]  [3x7 double]  [3x7 double]  [3x9 double]}

The prices in the output vector Price correspond to the prices at observation time zero (tObs = 0), which is defined as the Valuation Date of the interest-rate tree.

In the Price vector, the first element, 98.884, represents the price of the first instrument (4% Bond); the second element, 101.347, represents the price of the second instrument (5% Bond), and 3.347 represents the price of the American call option.

You can also display a graphical representation of the price tree to examine the prices on the nodes of the tree until maturity.

treeviewer(PTree,InstSet);

Figure Tree Viewer contains 2 axes objects and other objects of type uicontrol. Axes object 1 contains 155 objects of type line. Axes object 2 is empty.

Add More Instruments to the Existing Portfolio

Add instruments to the existing portfolio: cap, floor, floating rate note, vanilla swap and a puttable and callable bond.

% Cap
StrikeC =0.035;
InstSet = instadd(InstSet,'Cap', StrikeC, Settle, datetime(2010,2,27));

% Floor
StrikeF =0.05;
InstSet = instadd(InstSet,'Floor', StrikeF, Settle, datetime(2009,2,27));

% Floating Rate Note
InstSet = instadd(InstSet,'Float', 30, Settle, datetime(2009,2,27));

% Vanilla Swap
 LegRate =[0.04 5];
 InstSet = instadd(InstSet,'Swap', LegRate, Settle, datetime(2010,2,27));

% Puttable and Callable Bonds
InstSet = instadd(InstSet,'OptEmBond', CouponRate, Settle,datetime(2010,2,27), {'put';'call'},...
                  Strike, datetime(2010,2,27),'AmericanOpt', 1, 'Period', 1);

% Process Names and Holdings
Holdings = [15 ;5 ;8; 7; 9; 4];
Names = {'3.5% Cap';'5% Floor';'30BP Float';'4%/5BP Swap'; 'PuttBond'; 'CallBond' };

InstSet = instsetfield(InstSet, 'Index',4:9, 'FieldName', {'Quantity'}, 'Data', Holdings );
InstSet = instsetfield(InstSet, 'Index',4:9, 'FieldName', {'Name'}, 'Data', Names );

Examine the set of instruments contained in the variable InstSet.

instdisp(InstSet)
Index Type CouponRate Settle         Maturity       Period Basis EndMonthRule IssueDate FirstCouponDate LastCouponDate StartDate Face Quantity Name     
1     Bond 0.04       27-Feb-2007    27-Feb-2009    1      0     1            NaN       NaN             NaN            NaN       100  10       4% Bond  
2     Bond 0.05       27-Feb-2007    27-Feb-2010    1      0     1            NaN       NaN             NaN            NaN       100  15       5% Bond  
 
Index Type    UnderInd OptSpec Strike ExerciseDates  AmericanOpt Quantity Name     
3     OptBond 2        call    98     27-Feb-2010    1           3        Option 98
 
Index Type Strike Settle         Maturity       CapReset Basis Principal Quantity Name       
4     Cap  0.035  27-Feb-2007    27-Feb-2010    1        0     100       15       3.5% Cap   
 
Index Type  Strike Settle         Maturity       FloorReset Basis Principal Quantity Name       
5     Floor 0.05   27-Feb-2007    27-Feb-2009    1          0     100       5        5% Floor   
 
Index Type  Spread Settle         Maturity       FloatReset Basis Principal EndMonthRule CapRate FloorRate Quantity Name       
6     Float 30     27-Feb-2007    27-Feb-2009    1          0     100       1            Inf     -Inf      8        30BP Float 
 
Index Type LegRate   Settle         Maturity       LegReset Basis Principal LegType EndMonthRule StartDate Quantity Name       
7     Swap [0.04  5] 27-Feb-2007    27-Feb-2010    [NaN]    0     100       [NaN]   1            NaN       7        4%/5BP Swap
 
Index Type      CouponRate Settle         Maturity       OptSpec Strike ExerciseDates                Period Basis EndMonthRule IssueDate FirstCouponDate LastCouponDate StartDate Face AmericanOpt Quantity Name       
8     OptEmBond 0.04       27-Feb-2007    27-Feb-2010    put     98     27-Feb-2007   27-Feb-2010    1      0     1            NaN       NaN             NaN            NaN       100  1           9        PuttBond   
9     OptEmBond 0.05       27-Feb-2007    27-Feb-2010    call    98     27-Feb-2007   27-Feb-2010    1      0     1            NaN       NaN             NaN            NaN       100  1           4        CallBond   
 

Hedging

The idea behind hedging is to minimize exposure to market movements. As the underlying changes, the proportions of the instruments forming the portfolio may need to be adjusted to keep the sensitivities within the desired range.

Calculate sensitivities using the BK model.

[Delta, Gamma, Vega, Price] = bksens(BKTree, InstSet);

Get the current portfolio holdings.

Holdings = instget(InstSet, 'FieldName', 'Quantity');

Create a matrix of sensitivities.

Sensitivities = [Delta Gamma Vega];

Each row of the Sensitivities matrix is associated with a different instrument in the portfolio, and each column with a different sensitivity measure.

format bank
disp([Price  Holdings  Sensitivities])
         98.88         10.00       -185.47        528.47             0
        101.35         15.00       -277.51       1045.05             0
          3.35          3.00       -223.52      11843.32             0
          2.77         15.00        250.04       2921.11         -0.00
          0.75          5.00       -132.97      11566.69             0
        100.56          8.00         -0.80          2.02             0
         -1.53          7.00       -272.08       1027.85          0.00
         98.60          9.00       -168.92      21712.82             0
         98.00          4.00        -53.99     -10798.27             0

The first column above is the dollar unit price of each instrument, the second column is the number of contracts of each instrument, and the third, fourth, and fifth columns are the dollar delta, gamma, and vega sensitivities.

The current portfolio sensitivities are a weighted average of the instruments in the portfolio.

TargetSens  = Holdings' * Sensitivities
TargetSens = 1×3

      -7249.21     317573.92         -0.00

Obtain a Neutral Sensitivity Portfolio Using hedgeslf

Suppose you want to obtain a delta, gamma and vega neutral portfolio. The function hedgeslf finds the reallocation in a portfolio of financial instruments closest to being self-financing (maintaining constant portfolio value).

[Sens, Value1, Quantity]= hedgeslf(Sensitivities, Price,Holdings)
Sens = 3×1

         -0.00
         -0.00
         -0.00

Value1 = 
       4637.54

Quantity = 9×1

         10.00
          5.26
         -5.11
          7.06
         -3.05
         12.45
         -7.36
          8.47
         10.37

The function hedgeslf returns the portfolio dollar sensitivities (Sens), the value of the rebalanced portfolio (Value1) and the new allocation for each instrument (Quantity). If Value0 and Value1 represent the portfolio value before and after rebalancing, you can verify the cost by comparing the portfolio values.

Value0 = Holdings' * Price
Value0 = 
       4637.54

In this example, the portfolio is fully hedged (simultaneous delta, gamma, and vega neutrality) and self-financing (the values of the portfolio before and after balancing (Value0 and Value1) are the same.

Adding Constraints to Hedge a Portfolio

Suppose that you want to place upper and lower bounds on the individual instruments in the portfolio. Let's say that you want to bound the position of all instruments to within +/- 11 contracts.

Applying these constraints disallows the current positions in the fifth and eighth instruments. All other instruments are currently within the upper/lower bounds.

% Specify the lower and upper bounds
LowerBounds = [-11  -11  -11  -11  -11  -11  -11  -11  -11];
UpperBounds = [ 11   11   11   11   11   11   11   11   11];

% Use the function portcons to build the constraints
ConSet = portcons('AssetLims', LowerBounds, UpperBounds);

% Apply the constraints to the portfolio
[Sens, Value, Quantity1] = hedgeslf(Sensitivities, Price, Holdings, [], ConSet)
Sens = 3×1

             0
             0
             0

Value = 
             0

Quantity1 = 9×1

             0
             0
             0
             0
             0
             0
             0
             0
             0

Observe that the hedgeslf function enforces the bounds on the fifth and eighth instruments, and the portfolio continues to be fully hedged and self-financing.

set(0, 'format', OldFormat);

See Also

|

Related Examples

More About