44import java .util .ArrayList ;
55import java .util .Arrays ;
66import java .util .Comparator ;
7+ import java .util .HashMap ;
78import java .util .List ;
89import java .util .stream .IntStream ;
910import java .util .stream .Stream ;
3233import net .finmath .time .daycount .DayCountConvention_ACT_360 ;
3334
3435
35- public class InterestRateAnalyticCalibration {
36+ public class InterestRateAnalyticCalibrator {
3637
3738 public static String DISCOUNT_EUR_OIS = "discount-EUR-OIS" ;
3839 public static String FORWARD_EUR_6M = "forward-EUR-6M" ;
3940 private static String FORWARD_EUR_OIS = "forward-EUR-OIS" ;
4041 private static String FIXED_EUR_6M = "fixed-EUR-6M" ;
4142
42- private List < CalibrationDataItem > fixings ;
43-
44- public InterestRateAnalyticCalibration () {
45- this . fixings = new ArrayList <>();
43+
44+ public enum CURVE_NAME {
45+ ESTR ,
46+ EURIBOR06M
4647 }
4748
4849
50+
51+ private HashMap <CURVE_NAME , List <CalibrationDataItem >> fixings = new HashMap <>();
52+
53+ public InterestRateAnalyticCalibrator () {
54+ }
55+
56+
57+
4958 public AnalyticModel getCalibratedModel (LocalDate referenceDate , double [] discountCurveQuotes , double [] forwardCurveQuotes ) throws CloneNotSupportedException , SolverException {
5059
5160 final AnalyticModelFromCurvesAndVols model = new AnalyticModelFromCurvesAndVols (new Curve [] { getDiscountCurveEurOIS (referenceDate ), getForwardCurveEurOIS (referenceDate ), getForwardCurveEur6M (referenceDate )});
@@ -58,19 +67,37 @@ public AnalyticModel getCalibratedModel(LocalDate referenceDate, double[] discou
5867 return calibratedCurves .getModel ();
5968 }
6069
70+
71+ public void addFixingItem (CURVE_NAME curveName , LocalDate fixingDate , Double fixing ) {
72+ switch (curveName ) {
73+ case ESTR :
74+ this .fixings .computeIfAbsent (curveName , k -> new ArrayList <>()).add (createFixingItemEurOIS (fixingDate , fixing ));
75+ break ;
76+ case EURIBOR06M :
77+ this .fixings .computeIfAbsent (curveName , k -> new ArrayList <>()).add (createFixingItemEur6M (fixingDate , fixing ));
78+ break ;
79+ }
80+ }
81+
6182
62- public void addFixingItem (CalibrationDataItem fixingItem ) {
63- this .fixings .add (fixingItem );
83+ private CalibrationDataItem createFixingItemEur6M (LocalDate fixingDate , Double fixing ) {
84+ CalibrationDataItem .Spec spec = new CalibrationDataItem .Spec ("EURIBOR06M" , "Euribor6M" , "FIXING" , "6M" );
85+ CalibrationDataItem item = new CalibrationDataItem (spec , fixing , fixingDate .atStartOfDay ());
86+ return item ;
6487 }
6588
89+ private CalibrationDataItem createFixingItemEurOIS (LocalDate fixingDate , Double fixing ) {
90+ CalibrationDataItem .Spec spec = new CalibrationDataItem .Spec ("IREURDRFO_N" , "ESTR" , "FIXING" , "1D" );
91+ CalibrationDataItem item = new CalibrationDataItem (spec , fixing , fixingDate .atStartOfDay ());
92+ return item ;
93+ }
6694
6795 private DiscountCurveInterpolation getDiscountCurveEurOIS (LocalDate referenceDate ) {
6896 ArrayList <Double > fixingValuesList = new ArrayList <>();
6997 ArrayList <Double > fixingTimesList = new ArrayList <>();
7098 ArrayList <Double > dfList = new ArrayList <>();
7199 ArrayList <Double > dfTimesList = new ArrayList <>();
72- fixings .stream ().filter (x -> x .getCurveName ().equals ("ESTR" ))
73- .sorted (Comparator .comparing (CalibrationDataItem ::getDate ).reversed ())
100+ this .fixings .getOrDefault (CURVE_NAME .ESTR , new ArrayList <>()).stream ().sorted (Comparator .comparing (CalibrationDataItem ::getDate ).reversed ())
74101 .forEach (x -> {
75102 double time = FloatingpointDate .getFloatingPointDateFromDate (
76103 referenceDate ,
@@ -116,7 +143,7 @@ private ForwardCurve getForwardCurveEurOIS(LocalDate referenceDate) {
116143 }
117144
118145 private ForwardCurve getForwardCurveEur6M (LocalDate referenceDate ) {
119- double [] fixingTimes = fixings .stream (). filter ( x -> x . getCurveName (). equals ( "Euribor6M" ) ).map (x -> x .getDate ())
146+ double [] fixingTimes = this . fixings .getOrDefault ( CURVE_NAME . EURIBOR06M , new ArrayList <>()). stream ( ).map (x -> x .getDate ())
120147 .map (x -> FloatingpointDate .getFloatingPointDateFromDate (referenceDate , x ))
121148 .mapToDouble (Double ::doubleValue ).sorted ().toArray ();
122149 if (fixingTimes .length == 0 ) { //if there are no fixings return empty curve
@@ -131,7 +158,7 @@ private ForwardCurve getForwardCurveEur6M(LocalDate referenceDate) {
131158 ForwardCurveInterpolation .InterpolationEntityForward .FORWARD ,
132159 DISCOUNT_EUR_OIS );
133160 }
134- double [] fixingValues = fixings .stream (). filter ( x -> x . getCurveName (). equals ( "Euribor6M" ) )
161+ double [] fixingValues = this . fixings .getOrDefault ( CURVE_NAME . EURIBOR06M , new ArrayList <>()). stream ( )
135162 .sorted (Comparator .comparing (CalibrationDataItem ::getDate )).map (CalibrationDataItem ::getQuote )
136163 .mapToDouble (Double ::doubleValue ).toArray ();
137164 ForwardCurve fixedPart = ForwardCurveInterpolation .createForwardCurveFromForwards (FIXED_EUR_6M ,
@@ -165,6 +192,10 @@ private static CalibratedCurves.CalibrationSpec[] getCalibrationSpecsEurOIS(Loca
165192 final String [] maturities = { "1D" , "7D" , "14D" , "21D" , "1M" , "2M" , "3M" , "4M" , "5M" , "6M" , "7M" , "8M" , "9M" , "10M" , "11M" , "1Y" , "15M" , "18M" , "21M" , "2Y" , "3Y" , "4Y" , "5Y" , "6Y" , "7Y" , "8Y" , "9Y" , "10Y" , "12Y" , "15Y" , "20Y" , "25Y" , "30Y" };
166193 final String [] frequency = { "tenor" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" , "annual" };
167194
195+ if (quotes .length != maturities .length ) {
196+ throw new IllegalArgumentException ("Size of provided quotes does not match the number of EUR-OIS bootstrapp instruments" );
197+ }
198+
168199 CalibratedCurves .CalibrationSpec [] specs = new CalibratedCurves .CalibrationSpec [maturities .length ];
169200 BusinessdayCalendar calendar = new BusinessdayCalendarExcludingTARGETHolidays ();
170201 // The first product is an overnight cash deposit, followed by 32 swaps
@@ -190,10 +221,14 @@ private static CalibratedCurves.CalibrationSpec[] getCalibrationSpecsEur6M(Local
190221 final String [] daycountConventionsFloat = { "" , "" , "" , "" , "" , "" , "" , "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" };
191222 final String [] daycountConventions = { "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" , "ACT/360" , "E30/360" , "E30/360" , "E30/360" , "E30/360" , "E30/360" , "E30/360" , "E30/360" , "E30/360" , "E30/360" , "E30/360" , "E30/360" , "E30/360" , "E30/360" , "E30/360" };
192223
224+ if (quotes .length != maturities .length ) {
225+ throw new IllegalArgumentException ("Size of provided quotes does not match the number of EUR-6M bootstrapp instruments" );
226+ }
227+
193228 CalibratedCurves .CalibrationSpec [] specs = new CalibratedCurves .CalibrationSpec [maturities .length ];
194229 BusinessdayCalendar calendar = new BusinessdayCalendarExcludingTARGETHolidays ();
195230 // The first 7 product are FRAs, followed by 14 swaps
196- for (int i =0 ; i < 8 ; i ++) {
231+ for (int i =0 ; i < 7 ; i ++) {
197232 int nMonthMaturity = Integer .parseInt (maturities [i ].replace ("M" , "" ));
198233 int nMonthOffset = nMonthMaturity - Integer .parseInt (tenorLabel .replace ("M" , "" ));
199234 String startOffsetLabel = nMonthOffset + "M" ;
0 commit comments