diff --git a/examples/src/main/java/com/opengamma/strata/examples/SwapPricingExample.java b/examples/src/main/java/com/opengamma/strata/examples/SwapPricingExample.java index f8193e3062..c28004cd86 100644 --- a/examples/src/main/java/com/opengamma/strata/examples/SwapPricingExample.java +++ b/examples/src/main/java/com/opengamma/strata/examples/SwapPricingExample.java @@ -62,7 +62,12 @@ /** * Example to illustrate using the calculation API to price a swap. *

- * This makes use of the example market data environment. + * This makes use of the example market data environment. The example uses a + * multi-curve setup: the USD discount curve is used for discounting and the + * USD-LIBOR-3M curve is used for floating-rate projection. The resulting NPV + * is therefore not directly comparable with a single flat risk-free-rate curve + * used by another pricing library unless the market data and conventions are + * aligned first. */ public class SwapPricingExample { @@ -95,7 +100,9 @@ private static void calculate(CalculationRunner runner) { Column.of(Measures.PV01_CALIBRATED_BUCKETED), Column.of(AdvancedMeasures.PV01_SEMI_PARALLEL_GAMMA_BUCKETED)); - // use the built-in example market data + // Use the built-in multi-curve example market data. USD-Disc is used for + // discounting and USD-3ML for USD-LIBOR-3M projection. This is not a flat + // 1% risk-free-rate setup. LocalDate valuationDate = LocalDate.of(2014, 1, 22); ExampleMarketDataBuilder marketDataBuilder = ExampleMarketData.builder(); MarketData marketData = marketDataBuilder.buildSnapshot(valuationDate); diff --git a/modules/loader/src/main/java/com/opengamma/strata/loader/csv/SwapTradeCsvPlugin.java b/modules/loader/src/main/java/com/opengamma/strata/loader/csv/SwapTradeCsvPlugin.java index 4aa599f505..0524e5e240 100644 --- a/modules/loader/src/main/java/com/opengamma/strata/loader/csv/SwapTradeCsvPlugin.java +++ b/modules/loader/src/main/java/com/opengamma/strata/loader/csv/SwapTradeCsvPlugin.java @@ -68,6 +68,7 @@ import com.opengamma.strata.product.swap.SwapTrade; import com.opengamma.strata.product.swap.type.SingleCurrencySwapConvention; import com.opengamma.strata.product.swap.type.XCcyIborIborSwapConvention; +import com.opengamma.strata.product.swap.type.XCcyOvernightOvernightSwapConvention; /** * Loads Swap trades from CSV files. @@ -357,10 +358,9 @@ static SwapTrade parseWithConvention(CsvRow row, TradeInfo info, ReferenceData r Period periodToStart = periodToStartOpt.get(); Tenor tenor = tenorOpt.get(); if (fxRateOpt.isPresent()) { - XCcyIborIborSwapConvention convention = XCcyIborIborSwapConvention.of(conventionStr); - double notionalFlat = notional * fxRateOpt.get(); - SwapTrade trade = convention.createTrade( - tradeDate, periodToStart, tenor, buySell, notional, notionalFlat, fixedRate, refData); + SwapTrade trade = createCrossCurrencySwap( + conventionStr, tradeDate, periodToStart, tenor, buySell, notional, + notional * fxRateOpt.get(), fixedRate, refData); trade = trade.toBuilder().info(info).build(); return adjustTrade(trade, rollCnvOpt, stubCnvOpt, firstRegStartDateOpt, lastRegEndDateOpt, dateCnv, dateCalOpt); } else { @@ -396,15 +396,52 @@ private static SwapTrade createSwap( Optional fxRateOpt) { if (fxRateOpt.isPresent()) { - XCcyIborIborSwapConvention convention = XCcyIborIborSwapConvention.of(conventionStr); - double notionalFlat = notional * fxRateOpt.get(); - return convention.toTrade(info, startDate, endDate, buySell, notional, notionalFlat, fixedRate); + return createCrossCurrencySwap( + conventionStr, info, startDate, endDate, buySell, notional, + notional * fxRateOpt.get(), fixedRate); } else { SingleCurrencySwapConvention convention = SingleCurrencySwapConvention.of(conventionStr); return convention.toTrade(info, startDate, endDate, buySell, notional, fixedRate); } } + private static SwapTrade createCrossCurrencySwap( + String conventionStr, + LocalDate tradeDate, + Period periodToStart, + Tenor tenor, + BuySell buySell, + double notionalSpreadLeg, + double notionalFlatLeg, + double spread, + ReferenceData refData) { + + if (XCcyIborIborSwapConvention.extendedEnum().lookupAll().containsKey(conventionStr)) { + return XCcyIborIborSwapConvention.of(conventionStr).createTrade( + tradeDate, periodToStart, tenor, buySell, notionalSpreadLeg, notionalFlatLeg, spread, refData); + } + return XCcyOvernightOvernightSwapConvention.of(conventionStr).createTrade( + tradeDate, periodToStart, tenor, buySell, notionalSpreadLeg, notionalFlatLeg, spread, refData); + } + + private static SwapTrade createCrossCurrencySwap( + String conventionStr, + TradeInfo info, + LocalDate startDate, + LocalDate endDate, + BuySell buySell, + double notionalSpreadLeg, + double notionalFlatLeg, + double spread) { + + if (XCcyIborIborSwapConvention.extendedEnum().lookupAll().containsKey(conventionStr)) { + return XCcyIborIborSwapConvention.of(conventionStr).toTrade( + info, startDate, endDate, buySell, notionalSpreadLeg, notionalFlatLeg, spread); + } + return XCcyOvernightOvernightSwapConvention.of(conventionStr).toTrade( + info, startDate, endDate, buySell, notionalSpreadLeg, notionalFlatLeg, spread); + } + // adjust trade based on additional fields specified private static SwapTrade adjustTrade( SwapTrade trade, diff --git a/modules/loader/src/test/java/com/opengamma/strata/loader/csv/TradeCsvLoaderTest.java b/modules/loader/src/test/java/com/opengamma/strata/loader/csv/TradeCsvLoaderTest.java index 41df48bc69..c3aa46a982 100644 --- a/modules/loader/src/test/java/com/opengamma/strata/loader/csv/TradeCsvLoaderTest.java +++ b/modules/loader/src/test/java/com/opengamma/strata/loader/csv/TradeCsvLoaderTest.java @@ -168,7 +168,7 @@ public class TradeCsvLoaderTest { private static final ReferenceData REF_DATA = ReferenceData.standard(); - private static final int NUMBER_SWAPS = 11; + private static final int NUMBER_SWAPS = 12; private static final ResourceLocator FILE = ResourceLocator.of("classpath:com/opengamma/strata/loader/csv/trades.csv"); @@ -745,6 +745,13 @@ public void test_load_swap() { assertBeanEquals(expected8, filtered.get(8)); assertBeanEquals(expected9, filtered.get(9)); assertBeanEquals(expected10, filtered.get(10)); + SwapTrade overnightSwap = filtered.get(11); + assertThat(overnightSwap.getInfo().getId().get().getValue()).isEqualTo("123422"); + assertThat(overnightSwap.getProduct().getLegs()).hasSize(2); + assertThat(overnightSwap.getProduct().getLegs().get(0).getCurrency()).isEqualTo(EUR); + assertThat(overnightSwap.getProduct().getLegs().get(1).getCurrency()).isEqualTo(USD); + assertThat(overnightSwap.getProduct().getLegs().get(0).getPayReceive()).isEqualTo(PAY); + assertThat(overnightSwap.getProduct().getLegs().get(1).getPayReceive()).isEqualTo(RECEIVE); checkRoundtrip( SwapTrade.class, @@ -759,7 +766,8 @@ public void test_load_swap() { expected7, expected8, expected9, - expected10); + expected10, + overnightSwap); } private SwapTrade expectedSwap0() { @@ -2315,7 +2323,7 @@ public void test_load_filtered() { ImmutableList.of(FILE.getCharSource()), ImmutableList.of(FraTrade.class, TermDepositTrade.class)); assertThat(trades.getValue()).hasSize(6); - assertThat(trades.getFailures()).hasSize(29); + assertThat(trades.getFailures()).hasSize(30); assertThat(trades.getFailures().get(0).getMessage()).isEqualTo( "Trade type not allowed " + SwapTrade.class.getName() + ", only these types are supported: FraTrade, TermDepositTrade"); } diff --git a/modules/loader/src/test/resources/com/opengamma/strata/loader/csv/trades.csv b/modules/loader/src/test/resources/com/opengamma/strata/loader/csv/trades.csv index 07687db0b1..e640046462 100644 --- a/modules/loader/src/test/resources/com/opengamma/strata/loader/csv/trades.csv +++ b/modules/loader/src/test/resources/com/opengamma/strata/loader/csv/trades.csv @@ -19,6 +19,7 @@ Variable,,,,,,,,,,,,,,,,,,01/06/2018,,,,,,,,,,,,,,2500000,,,,,,,,,,,,,,,,,,,,,,, Swap,OG,123419,01/06/2017,,,,,,,,,,,,,,,,,,,,Pay,01/07/2017,01/07/2018,,,1T,BRL,1000000,1.3,,BUS/252,,,Receive,01/07/2017,01/07/2018,1T,BRL,1000000,BRL-CDI,OvernightCompoundedAnnualRate,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, Swap,OG,123420,01/06/2017,,,,,,,,,,,,,,,,,,,,Pay,01/07/2017,01/07/2018,,,1T,BRL,2000000,1.5,,BUS/252,,,Receive,01/07/2017,01/07/2018,1T,BRL,2000000,BRL-CDI,OvernightCompoundedAnnualRate,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, Swap,OG,123421,01/06/2017,,,,,,,,,,,,,,,,,,,,Pay,01/07/2017,01/07/2018,,,1T,BRL,3000000,1.7,,BUS/252,,,Receive,01/07/2017,01/07/2018,1T,BRL,3000000,BRL-CDI,Compounded,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Swap,OG,123422,01/06/2017,,,,EUR-ESTR-3M-USD-SOFR-3M,Buy,,P3Y,,,0.6,1.25,,,2000000,05/07/2017,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, Swaption,OG,123411,01/06/2017,,,,GBP-FIXED-1Y-LIBOR-3M,Buy,P1M,P5Y,,,0.4,,,,2000000,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Long,ParYield,03/07/2017,30/06/2017,11:00,Europe/London,Pay,GBP,1000,03/06/2017,,,,,,,,,,,,,,,,,,,,, Swaption,OG,123412,01/06/2017,,,,GBP-FIXED-6M-LIBOR-6M,BUY,,,,,-0.01,,,,3100000,01/08/2017,01/08/2022,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Short,Physical,,30/06/2017,11:00,Europe/London,Receive,GBP,1000,03/06/2017,,,,,,,,,,,,,,,,,,,,,