Skip to content

Commit

Permalink
Added Futures Type - Custom; (#288)
Browse files Browse the repository at this point in the history
* Added Futures Type - Custom;

This is trnasfered from the C++ code: lballabio/QuantLib#1915
This allows passing custom future dates. Closes #1855: lballabio/QuantLib#1855

* Update the default case message only

---------

Co-authored-by: Xiao Gong <xiao.gong@nzfunds.co.nz>
  • Loading branch information
ninetiger and Xiao Gong committed Apr 16, 2024
1 parent 9d1a564 commit 470ffe5
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 18 deletions.
8 changes: 2 additions & 6 deletions src/QLNet/Instruments/Futures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the license for more details.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace QLNet
{
public struct Futures
Expand All @@ -28,8 +23,9 @@ public enum Type
{
IMM, /*!< Chicago Mercantile Internation Money Market, i.e.
third Wednesday of March, June, September, December */
ASX /*!< Australian Security Exchange, i.e. second Friday
ASX, /*!< Australian Security Exchange, i.e. second Friday
of March, June, September, December */
Custom /*!< Other rules */
}
}
}
35 changes: 23 additions & 12 deletions src/QLNet/Termstructures/Yield/Ratehelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,18 @@ public class FuturesRateHelper : RateHelper

switch (type)
{
case QLNet.Futures.Type.IMM:
Utils.QL_REQUIRE(QLNet.IMM.isIMMdate(iborStartDate, false), () =>
case Futures.Type.IMM:
Utils.QL_REQUIRE(IMM.isIMMdate(iborStartDate, false), () =>
iborStartDate + " is not a valid IMM date");
break;
case QLNet.Futures.Type.ASX:
case Futures.Type.ASX:
Utils.QL_REQUIRE(ASX.isASXdate(iborStartDate, false), () =>
iborStartDate + " is not a valid ASX date");
break;
case Futures.Type.Custom:
break;
default:
Utils.QL_FAIL("unknown futures type (" + type + ")");
Utils.QL_FAIL("unsupported futures type (" + type + ")");
break;
}
earliestDate_ = iborStartDate;
Expand Down Expand Up @@ -83,8 +85,10 @@ public class FuturesRateHelper : RateHelper
Utils.QL_REQUIRE(ASX.isASXdate(iborStartDate, false), () =>
iborStartDate + " is not a valid ASX date");
break;
case Futures.Type.Custom:
break;
default:
Utils.QL_FAIL("unknown futures type (" + type + ")");
Utils.QL_FAIL("unsupported futures type (" + type + ")");
break;
}
earliestDate_ = iborStartDate;
Expand Down Expand Up @@ -124,7 +128,7 @@ public class FuturesRateHelper : RateHelper
maturityDate_ = iborEndDate;
}
break;
case QLNet.Futures.Type.ASX:
case Futures.Type.ASX:
Utils.QL_REQUIRE(ASX.isASXdate(iborStartDate, false), () =>
iborStartDate + " is not a valid ASX date");
if (iborEndDate == null)
Expand All @@ -143,8 +147,10 @@ public class FuturesRateHelper : RateHelper
maturityDate_ = iborEndDate;
}
break;
case Futures.Type.Custom:
break;
default:
Utils.QL_FAIL("unknown futures type (" + type + ")");
Utils.QL_FAIL("unsupported futures type (" + type + ")");
break;
}
earliestDate_ = iborStartDate;
Expand Down Expand Up @@ -204,8 +210,10 @@ public class FuturesRateHelper : RateHelper
maturityDate_ = iborEndDate;
}
break;
case Futures.Type.Custom:
break;
default:
Utils.QL_FAIL("unknown futures type (" + type + ")");
Utils.QL_FAIL("unsupported futures type (" + type + ")");
break;
}
earliestDate_ = iborStartDate;
Expand All @@ -232,8 +240,10 @@ public class FuturesRateHelper : RateHelper
Utils.QL_REQUIRE(ASX.isASXdate(iborStartDate, false), () =>
iborStartDate + " is not a valid ASX date");
break;
case Futures.Type.Custom:
break;
default:
Utils.QL_FAIL("unknown futures type (" + type + ")");
Utils.QL_FAIL("unsupported futures type (" + type + ")");
break;
}
earliestDate_ = iborStartDate;
Expand Down Expand Up @@ -263,8 +273,10 @@ public class FuturesRateHelper : RateHelper
Utils.QL_REQUIRE(ASX.isASXdate(iborStartDate, false), () =>
iborStartDate + " is not a valid ASX date");
break;
case Futures.Type.Custom:
break;
default:
Utils.QL_FAIL("unknown futures type (" + type + ")");
Utils.QL_FAIL("unsupported futures type (" + type + ")");
break;
}
earliestDate_ = iborStartDate;
Expand All @@ -281,11 +293,10 @@ public override double impliedQuote()

double forwardRate = (termStructure_.discount(earliestDate_) /
termStructure_.discount(maturityDate_) - 1) / yearFraction_;
double convAdj = convAdj_.empty() ? 0 : convAdj_.link.value();
// Convexity, as FRA/futures adjustment, has been used in the
// past to take into account futures margining vs FRA.
// Therefore, there's no requirement for it to be non-negative.
double futureRate = forwardRate + convAdj;
double futureRate = forwardRate + convexityAdjustment();
return 100.0 * (1.0 - futureRate);
}

Expand Down

0 comments on commit 470ffe5

Please sign in to comment.