Schedule#
The rateslib.scheduling
module generates swap schedules.
Scheduling swaps is a surprisingly complex
issue, especially when one wants to infer some necessary parameters from the given
information. We will give examples of the basic Schedule
s and further explain some of the more complicated inference patterns.
Summary#
Classes#
|
Generate a schedule of dates according to a regular pattern and calendar inference. |
Methods#
Tests whether the given the parameters define a regular leg schedule without stubs. |
|
Attempts to infer either a front or back stub in an unspecified schedule. |
Scheduling Examples#
Regular Schedule#
A regular schedule under a generic business day calendar. Note how this swap actually starts and end on the 1st of the month but the holiday adjusted effective and termination dates are actually the 3rd and 2nd.
In [1]: schedule = Schedule(
...: effective=dt(2022,1,1),
...: termination=dt(2023,1,1),
...: frequency="S",
...: calendar="bus",
...: payment_lag=1
...: )
...:
In [2]: schedule
Out[2]:
freq: S, stub: SHORTFRONT, roll: 1, pay lag: 1, modifier: MF
Period Unadj Acc Start Unadj Acc End Acc Start Acc End Payment
0 Regular 2022-01-01 2022-07-01 2022-01-03 2022-07-01 2022-07-04
1 Regular 2022-07-01 2023-01-01 2022-07-01 2023-01-02 2023-01-03
If the same schedule is created with the adjusted dates input as the effective and termination dates then a roll day is inferred, in this case as 2, creating a different schedule to the above.
In [3]: schedule = Schedule(
...: effective=dt(2022,1,3),
...: termination=dt(2023,1,2),
...: frequency="S",
...: calendar="bus",
...: payment_lag=1
...: )
...:
In [4]: schedule
Out[4]:
freq: S, stub: SHORTFRONT, roll: 2, pay lag: 1, modifier: MF
Period Unadj Acc Start Unadj Acc End Acc Start Acc End Payment
0 Regular 2022-01-02 2022-07-02 2022-01-03 2022-07-04 2022-07-05
1 Regular 2022-07-02 2023-01-02 2022-07-04 2023-01-02 2023-01-03
The original schedule can be obtained by directly specifying the roll day and not relying on roll day inference.
In [5]: schedule = Schedule(
...: effective=dt(2022,1,3),
...: termination=dt(2023,1,2),
...: frequency="S",
...: roll=1,
...: calendar="bus",
...: payment_lag=1
...: )
...:
In [6]: schedule
Out[6]:
freq: S, stub: SHORTFRONT, roll: 1, pay lag: 1, modifier: MF
Period Unadj Acc Start Unadj Acc End Acc Start Acc End Payment
0 Regular 2022-01-01 2022-07-01 2022-01-03 2022-07-01 2022-07-04
1 Regular 2022-07-01 2023-01-01 2022-07-01 2023-01-02 2023-01-03
Defined Stubs#
A schedule with specifically defined stubs.
In [7]: schedule = Schedule(
...: effective=dt(2021,1,1),
...: termination=dt(2021,10,1),
...: frequency="Q",
...: front_stub=dt(2021, 2, 26),
...: back_stub=dt(2021, 8, 29),
...: calendar="bus",
...: payment_lag=1
...: )
...:
In [8]: schedule
Out[8]:
freq: Q, stub: FRONTBACK, roll: 29, pay lag: 1, modifier: MF
Period Unadj Acc Start Unadj Acc End Acc Start Acc End Payment
0 Stub 2021-01-01 2021-02-28 2021-01-01 2021-02-26 2021-03-01
1 Regular 2021-02-28 2021-05-29 2021-02-26 2021-05-31 2021-06-01
2 Regular 2021-05-29 2021-08-29 2021-05-31 2021-08-30 2021-08-31
3 Stub 2021-08-29 2021-10-01 2021-08-30 2021-10-01 2021-10-04
Note that the above schedule must have a regular swap defined between stub dates. In this case the roll, inferred as 29, allows this, and the unadjusted dates are then adjusted under the business day holiday calendar to the provided stubs. Schedules that cannot be inferred validly will raise.
Stub and roll generation can also be implied if the front_stub
and/or back_stub
are blank. Only one side can be inferred however so with a dual sided stub at least
one date must be given. In the following case “FRONT” suffices as the stub
input
since the specific date is given, but “LONGBACK” provides the necessary detail for
inference. Without specifying roll here it would be inferred as 26, but an alternative,
valid value can be forced. Invalid combinations (those that do not permit regular swaps
between stub dates) raise errors.
In [9]: schedule = Schedule(
...: effective=dt(2021, 1, 1),
...: termination=dt(2021, 10, 1),
...: frequency="Q",
...: front_stub=dt(2021, 2, 26),
...: stub="FRONTLONGBACK",
...: roll=30,
...: calendar="bus",
...: payment_lag=1
...: )
...:
In [10]: schedule
Out[10]:
freq: Q, stub: FRONTLONGBACK, roll: 30, pay lag: 1, modifier: MF
Period Unadj Acc Start Unadj Acc End Acc Start Acc End Payment
0 Stub 2021-01-01 2021-02-28 2021-01-01 2021-02-26 2021-03-01
1 Regular 2021-02-28 2021-05-30 2021-02-26 2021-05-31 2021-06-01
2 Stub 2021-05-30 2021-10-01 2021-05-31 2021-10-01 2021-10-04
In [11]: try:
....: Schedule(
....: effective=dt(2021, 1, 1),
....: termination=dt(2021, 10, 1),
....: frequency="Q",
....: front_stub=dt(2021, 2, 26),
....: stub="FRONTLONGBACK",
....: roll=25,
....: calendar="bus",
....: payment_lag=1
....: )
....: except ValueError as e:
....: print(e)
....:
date, stub and roll inputs are invalid
Simple Inference#
One-sided stub inference can also be made if no stub dates are defined.
In [12]: schedule = Schedule(
....: effective=dt(2021, 1, 1),
....: termination=dt(2021, 7, 15),
....: frequency="Q",
....: stub="SHORTFRONT",
....: calendar="bus",
....: payment_lag=1
....: )
....:
In [13]: schedule
Out[13]:
freq: Q, stub: SHORTFRONT, roll: 15, pay lag: 1, modifier: MF
Period Unadj Acc Start Unadj Acc End Acc Start Acc End Payment
0 Stub 2021-01-01 2021-01-15 2021-01-01 2021-01-15 2021-01-18
1 Regular 2021-01-15 2021-04-15 2021-01-15 2021-04-15 2021-04-16
2 Regular 2021-04-15 2021-07-15 2021-04-15 2021-07-15 2021-07-16
In [14]: schedule = Schedule(
....: effective=dt(2021, 1, 1),
....: termination=dt(2021, 7, 15),
....: frequency="Q",
....: stub="LONGBACK",
....: calendar="bus",
....: payment_lag=1
....: )
....:
In [15]: schedule
Out[15]:
freq: Q, stub: LONGBACK, roll: 1, pay lag: 1, modifier: MF
Period Unadj Acc Start Unadj Acc End Acc Start Acc End Payment
0 Regular 2021-01-01 2021-04-01 2021-01-01 2021-04-01 2021-04-02
1 Stub 2021-04-01 2021-07-15 2021-04-01 2021-07-15 2021-07-16