tba.gms : Financial Optimization: Financial Engineering

Description

The delivery and settlement of mortgage-backed securities is governed
by an extensive set of rules and regulations. Forward delivery
settlements of not yet pooled mortgages are on a to-be-announced
(TPA) basis. Some allowed variance allows to structure the TBAs in
a cost effective manner.


Reference

  • Dahl, H, Meeraus, A, and Zenios, S A, Some Financial Optimization Models: Risk Management. In Zenios, S A, Ed, Financial Optimization. Cambridge University Press, New York, NY, 1993.

Large Model of Type : MIP


Category : GAMS Model library


Main file : tba.gms

$title Financial Optimization: Financial Engineering (TBA,SEQ=115)

$onText
The delivery and settlement of mortgage-backed securities is governed
by an extensive set of rules and regulations. Forward delivery
settlements of not yet pooled mortgages are on a to-be-announced
(TPA) basis. Some allowed variance allows to structure the TBAs in
a cost effective manner.


Dahl, H, Meeraus, A, and Zenios, S A, Some Financial Optimization
Models: Risk Management. In Zenios, S A, Ed, Financial Optimization.
Cambridge University Press, New York, NY, 1993.

Keywords: mixed integer linear programming, financial optimization, finance
$offText

Set
   p     'gnma pools'              / gn999001*gn999011 /
   i     'tbas'                    / 20580252 /
   l     'lots'                    / l1*l4 /
   c3(p) 'class 3 high risk pools' / gn999010*gn999011 /;

* Note:
* class1  in the box
* class2  delivery within 48 hours
* class3  delayed delivery

Alias (p,pp), (i,ii), (l,ll);

Table pv(p,*) 'value of pools'
              original  adjusted
   gn999001         50        50
   gn999002        100       100
   gn999003        300       300
   gn999004        400       400
   gn999005        450       450
   gn999006        450       450
   gn999007        475       475
   gn999008        700       700
   gn999009       1000      1000
   gn999010       1000      1000
   gn999011       5000      5000;

Table tbainfo(i,*) 'tba information table'
              quantity  selling  market  variation  maxpools
   20580252       5000   100.88     100        .05         3;

Parameter
    o(p)         'original face value of pools'
    a(p)         'adjusted face value of pools'
    head         'first incremental step for allocation'
    steps        'incremental step size between head and tail'
    tail(p)      'tail of pools'
    splitcost(p) 'cost of splitting pools'
    futprice(i)  'agreed delivery price'
    mktprice(i)  'market price'
    futamt(i)    'agreed quantity'
    var(i)       'agreed upper and lower relative deviation'
    maxpools(i)  'maximum number of pools in 1 mill dollar tba lots'
    lsize(i,l)   'tba lot sizes'
    maxp(i,l)    'maximum number of pools to allocate to each lot'
    m(p,i,l)     'upper bound on the number of value incremental steps'
    mb(p)        'upper bound on the number of box incremental steps'
    n            'total number of lots in the allocation';

o(p)         = pv(p,"original");
a(p)         = pv(p,"adjusted");
head         = 25;
steps        = 5;
tail(p)      = mod((o(p)-head$(o(p) > head)),steps);
splitcost(p) = .00001;
futamt(i)    = tbainfo(i,"quantity");
futprice(i)  = tbainfo(i,"selling")/100;
mktprice(i)  = tbainfo(i,"market")/100;
var(i)       = tbainfo(i,"variation");
maxpools(i)  = tbainfo(i,"maxpools");
lsize(i,l)   = 0;

loop(l, lsize(i,l) = min(1000,futamt(i)-sum(ll$(ord(ll) < ord(l)), lsize(i,ll))));

maxp(i,l) = (maxpools(i)-2)$(lsize(i,l) < 500)
          + (maxpools(i)-1)$(lsize(i,l) >= 500 and lsize(i,l) < 1000)
          +  maxpools(i)   $(lsize(i,l) >= 1000);

m(p,i,l) = floor(max(0, ((1 + var(i))*lsize(i,l)*o(p)/a(p) - head)/steps));
mb(p)    = floor( max(0,o(p) - head)/steps);
n        = sum((i,l)$lsize(i,l), 1);

Variable profit     'total profit';

Positive Variable
   v(p,i,l)         'allocated pool values by tba lot'
   b(p)             'adjusted face value of pools remaining in box';

Binary Variable
   z(p,i,l)         'decision whether to allocated pool to tba lot'
   zb1(p)           'auxiliary binary variable to determine splits'
   zb2(p)           'auxiliary binary variable to determine splits'
   w(i,l)           'decision whether to fail tba lot (0 = failed)'
   u0(p,i,l)        'auxiliary binary variable for minimum allocation'
   u0b(p)           'auxiliary binary variable for minimum boxing'
   ut(p,i,l)        'auxiliary binary variable for tail allocation'
   ubt(p)           'auxiliary binary variable for tail boxing'
   s(p)             'decision whether to split pools'
   f1(i,l)          'binary variable for one big pool allocation'
   f2(i,l)          'binary variable for two big pools allocation';

Integer Variable
   u(p,i,l)         'auxiliary integer variable for allocation steps'
   ub(p)            'auxiliary integer variable for box steps';

Equation
   loval(i,l)       'lower limit on allocated value by tba lot'
   upval(i,l)       'upper limit on allocated value by tba lot'
   supply(p)        'allocate value and boxed amounts'
   class3con(i,l)   'constraint on use of class 3 pools'
   splitsize(p,i,l) 'allocate head step and tail variables'
   stepcon(p,i,l)   'allocate step only after head allocation'
   tailcon(p,i,l)   'allocate tail only after head allocation'
   onetail(p)       'allocate tail only once for each pool'
   boxsize(p)       'allocate boxed head step and tail variables'
   stepboxcon(p)    'allocate boxed steps after boxed head'
   boxtailcon(p)    'allocate boxed tail after boxed head'
   zdet(p,i,l)      'determination of whether to allocate pool'
   zbox1def(p)      'definition of zb1'
   zbox2def(p)      'definition of zb2'
   splitdet(p)      'determination of whether to split'
   f1det(p,i,l)     'determination of single big allocated pools'
   f2det(p,pp,i,l)  'determination of two big pools'
   maxpool1(i,l)    'constraint on maximum pools per lot'
   maxpool2(i,l)    'constraint on maximum pools per lot'
   maxpool3(i,l)    'constraint on maximum pools per lot'
   profitdef        'definition of profits';

$sTitle Equations and Model Definition
* The value of pools assigned to a tba lot must be above the lower limit
* given by the agreement on delivery and variance, unless the lot is
* failed in which case it must be zero.
loval(i,l)$lsize(i,l).. sum(p, v(p,i,l)) =g= (1 - var(i))*lsize(i,l)*w(i,l);

* The value of pools assigned to a tba lot must be below the upper limit
* given by the agreement on delivery and variance, unless the lot is
* failed in which case it must be zero.
upval(i,l)$lsize(i,l).. sum(p, v(p,i,l)) =l= (1 + var(i))*lsize(i,l)*w(i,l);

* No more than the adjusted face value of a pool can be assigned or boxed.
supply(p).. sum((i,l)$lsize(i,l), v(p,i,l)) + b(p) =e= a(p);

* It is illegal to use only class 3 pools in a lot.
class3con(i,l)$lsize(i,l).. sum(p$(not c3(p)), v(p,i,l)) =g= w(i,l);

* Pools must be allocated in a minimum amount of head dollars of
* original face value and with increments of steps dollars original face
* value, except possibly for the tail.
splitsize(p,i,l)$lsize(i,l)..
   v(p,i,l)*o(p)/a(p) =e= head*u0(p,i,l) + steps*u(p,i,l) + tail(p)*ut(p,i,l);

* The steps increments in a split pool only applies after
* the head has been allocated for the tba lot.
stepcon(p,i,l)$lsize(i,l).. u(p,i,l) =l= m(p,i,l)*u0(p,i,l);

* The tail increment in a split pool only applies after
* the head has been allocated for the tba lot.
tailcon(p,i,l)$(lsize(i,l) and tail(p)).. ut(p,i,l) =l= u0(p,i,l);

* The tail of a pool can not be split.
onetail(p)$tail(p).. sum((i,l)$lsize(i,l), ut(p,i,l)) + ubt(p) =l= 1;

* The above size rules for split pools also apply to what remains in the box.
boxsize(p).. b(p)*o(p)/a(p) =e= head*u0b(p) + steps*ub(p) + tail(p)*ubt(p);

* This also applies to the box.
stepboxcon(p).. ub(p) =l= mb(p)*u0b(p);

* The box tail increment in a split pool only applies after
* the box head has been allocated for the pool.
boxtailcon(p)$tail(p).. ubt(p) =l= u0b(p);

* If a pool is not allocated to tba lot, the value of that allocation
* must be zero.
zdet(p,i,l)$lsize(i,l).. v(p,i,l) =l= (1+var(i))*lsize(i,l)*z(p,i,l);

* zb1 is 1 if something or nothing - but not everything - of a
* pool is boxed. It is zero if everything is boxed.
zbox1def(p).. zb1(p) =g= (a(p) - b(p))/a(p);

* zb2 is 1 if something or everything of a pool is boxed. it is zero
* if nothing remains in the box.  thus zb1 + zb2 equals 1 if
* everything or nothing remains in the box and 2 otherwise.
zbox2def(p).. zb2(p) =g= 1 - (a(p) - b(p))/a(p);

* A pool is split if it is allocated to more than one lot or - if
* allocated to only one lot - if it is not fully allocated, (i.e.,
* a fraction, but not all original value, remains in the box).
splitdet(p).. sum((i,l)$lsize(i,l), z(p,i,l)) + zb1(p) + zb2(p) - 2 =l= n*s(p);

* A single pool allocation is big if it is greater than or equal to
* the lower value requirement.
f1det(p,i,l)$lsize(i,l)..
   2*var(i)*lsize(i,l)*f1(i,l) =g= v(p,i,l) - (1-var(i))*lsize(i,l);

* A two pool allocation is big if the sum of the allocated values for
* those two pools is greater than or equal to the minimum allocation
* value requirement.
f2det(p,pp,i,l)$(lsize(i,l) and ord(p) < ord(pp))..
   2*var(i)*lsize(i,l)*f2(i,l) =g= v(p,i,l) + v(pp,i,l) - (1 - var(i))*lsize(i,l);

* No more than the specified number of pools can be allocated to a
* lot. If a big single pool allocation takes place then only that
* pool can be allocated, and if a big two pool allocation takes place
* for a tba lot, then only those two pools can be allocated to the lot.
maxpool1(i,l)$lsize(i,l).. sum(p, z(p,i,l)) =l= maxp(i,l);

maxpool2(i,l)$lsize(i,l).. sum(p, z(p,i,l)) =l= 1 + (1 - f1(i,l))*maxp(i,l);

maxpool3(i,l)$lsize(i,l).. sum(p, z(p,i,l)) =l= 2 + (1 - f2(i,l))*maxp(i,l);

* Total profit equals margin times delivery minus splitting costs.
profitdef..
   profit =e= sum((p,i,l)$lsize(i,l), (futprice(i) - mktprice(i))*v(p,i,l))
           -  sum(p, splitcost(p)*s(p));

u.up(p,i,l) = m(p,i,l);
ub.up(p)    = mb(p);

Model poolassign 'pool to tab lot assignment model' / all /;

* help the mip code along
u.prior(p,i,l) = 2;
ub.prior(p)    = 2;
poolassign.priorOpt = 1;
poolassign.optCr    = .0001;

solve poolassign maximizing profit using mip;