OpenSourceRisk / Engine

Open Source Risk Engine
http://www.opensourcerisk.org
Other
494 stars 222 forks source link

Incorrect FX dates convention handling with USD pairs #270

Open xwzhu opened 2 weeks ago

xwzhu commented 2 weeks ago

It seems that currently ORE is using a too simplified method to handle FX spot date, option expiry and delivery dates, which doesn't work for pairs involving USD, e.g. EUR/USD. Please refer to this wiki page for more infomation.

The Quantlib library has this partially implemented, see this PR, however such functionality is not being used. So for EUR-USD-FX convention, I think the correctly way would be to configure it like below, and pass the <TradingCalendar> field to FXSwapRateHelper when building implied yield curves.

<FX>
    <Id>EUR-USD-FX</Id>
    <SpotDays>2</SpotDays>
    <SourceCurrency>EUR</SourceCurrency>
    <TargetCurrency>USD</TargetCurrency>
    <PointsFactor>10000</PointsFactor>
    <AdvanceCalendar>TARGET</AdvanceCalendar>
    <TradingCalendar>US</AdvanceCalendar>
    <SpotRelative>true</SpotRelative>
</FX>

Further more, the TN/ON quotes need to be marked optional. As during days around US holiday, one of them may not be available. The code also need to allow deriving ON rate directly when TN is not available.

For FX volatility quotes, the expiry date calculation follows a reverse spot date rule from delivery date, which is also treated incorrectly in the exisint code.

gbfredrik commented 1 week ago

Hi, I also want to chime in that we see these issues a lot and are very interested in improvements to the FX handling. We have a fix for the TradingCalendar tag (just as you illustrated it) that we are looking to contribute shortly. This should help spot date and expiry date calculations for FX swap rate helpers.

Moreover, the FX spot logic needs similar adjustments, relying on the trading calendar property as well. We have yet to get there, but I'm interested in whether anyone from Acadia has any thoughts on that already.

Kind regards, Fredrik

xwzhu commented 1 week ago

HI @gbfredrik,

Having thinked about this issue again yesterday, I am now actually using three calendars in my local fork.

  1. advance calendar
  2. spot date calendar (default to advance calendar)
  3. trading calendar (default to NullCalendar)

Taking EUR/USD (T+2) for example, the three calendars are configured as:

  1. TARGET + US
  2. TARGET
  3. US

For GBP/EUR (T+2), they are:

  1. UK + TARGET
  2. UK + TARGET
  3. US

The reason to separate out an additional calendar just for spot date, is that I think when advancing tenors the joint calendar is still the expected one, and it will make a difference when tenors are businessday based (1D, 5D, etc.).

Then the spot date (T+2 case) is calculated in the following way:

horizon date (T) ---> advance 2 days with spot date calendar
                 ---> adjust with joint calendar of spot date calendar and trading calendar

And forward date is calculated as:

spot date ---> advance tenor with advance calendar
          ---> adjust with joint calendar of advance  calendar and trading calendar