Skip to content

Commit

Permalink
Add TradedPrice for security-based products
Browse files Browse the repository at this point in the history
Extend use of `TradedPrice`
  • Loading branch information
jodastephen committed Jun 8, 2018
1 parent e0bb97d commit ab9440e
Show file tree
Hide file tree
Showing 22 changed files with 360 additions and 326 deletions.
Expand Up @@ -95,10 +95,10 @@ public PointSensitivities priceSensitivity(ResolvedDsfTrade trade, RatesProvider
*/
private double referencePrice(ResolvedDsfTrade trade, LocalDate valuationDate, double lastSettlementPrice) {
ArgChecker.notNull(valuationDate, "valuationDate");
if (trade.getInfo().getTradeDate().isPresent()) {
return (trade.getInfo().getTradeDate().get().equals(valuationDate) ? trade.getPrice() : lastSettlementPrice);
}
return lastSettlementPrice;
return trade.getTradedPrice()
.filter(tp -> tp.getTradeDate().equals(valuationDate))
.map(tp -> tp.getPrice())
.orElse(lastSettlementPrice);
}

//-------------------------------------------------------------------------
Expand Down
Expand Up @@ -93,7 +93,10 @@ public PointSensitivities priceSensitivity(ResolvedIborFutureTrade trade, RatesP
*/
double referencePrice(ResolvedIborFutureTrade trade, LocalDate valuationDate, double lastSettlementPrice) {
ArgChecker.notNull(valuationDate, "valuationDate");
return (trade.getTradeDate().equals(valuationDate) ? trade.getPrice() : lastSettlementPrice);
return trade.getTradedPrice()
.filter(tp -> tp.getTradeDate().equals(valuationDate))
.map(tp -> tp.getPrice())
.orElse(lastSettlementPrice);
}

//-------------------------------------------------------------------------
Expand Down
Expand Up @@ -109,9 +109,12 @@ public PointSensitivities priceSensitivityRates(
* @param lastSettlementPrice the last settlement price used for margining, in decimal form
* @return the reference price, in decimal form
*/
double referencePrice(ResolvedIborFutureTrade trade, LocalDate valuationDate, double lastSettlementPrice) {
private double referencePrice(ResolvedIborFutureTrade trade, LocalDate valuationDate, double lastSettlementPrice) {
ArgChecker.notNull(valuationDate, "valuationDate");
return (trade.getTradeDate().equals(valuationDate) ? trade.getPrice() : lastSettlementPrice);
return trade.getTradedPrice()
.filter(tp -> tp.getTradeDate().equals(valuationDate))
.map(tp -> tp.getPrice())
.orElse(lastSettlementPrice);
}

//-------------------------------------------------------------------------
Expand Down
Expand Up @@ -249,7 +249,10 @@ public IborFutureOptionSensitivity presentValueSensitivityModelParamsVolatility(
*/
private double referencePrice(ResolvedIborFutureOptionTrade trade, LocalDate valuationDate, double lastSettlementPrice) {
ArgChecker.notNull(valuationDate, "valuationDate");
return (trade.getTradeDate().equals(valuationDate) ? trade.getPrice() : lastSettlementPrice);
return trade.getTradedPrice()
.filter(tp -> tp.getTradeDate().equals(valuationDate))
.map(tp -> tp.getPrice())
.orElse(lastSettlementPrice);
}

}
Expand Up @@ -45,7 +45,7 @@
import com.opengamma.strata.pricer.rate.ImmutableRatesProvider;
import com.opengamma.strata.pricer.sensitivity.RatesFiniteDifferenceSensitivityCalculator;
import com.opengamma.strata.product.SecurityId;
import com.opengamma.strata.product.TradeInfo;
import com.opengamma.strata.product.TradedPrice;
import com.opengamma.strata.product.dsf.Dsf;
import com.opengamma.strata.product.dsf.ResolvedDsf;
import com.opengamma.strata.product.dsf.ResolvedDsfTrade;
Expand Down Expand Up @@ -144,14 +144,12 @@ public class DiscountingDsfTradePricerTest {
.underlyingSwap(SWAP)
.build()
.resolve(REF_DATA);
private static final TradeInfo TRADE_INFO = TradeInfo.builder().tradeDate(VAL_DATE).build();
private static final double TRADE_PRICE = 0.98 + 31.0 / 32.0 / 100.0; // price quoted in 32nd of 1%
private static final long QUANTITY = 1234L;
private static final ResolvedDsfTrade FUTURE_TRADE = ResolvedDsfTrade.builder()
.info(TRADE_INFO)
.product(FUTURE)
.quantity(QUANTITY)
.price(TRADE_PRICE)
.tradedPrice(TradedPrice.of(VAL_DATE, TRADE_PRICE))
.build();
private static final double LASTMARG_PRICE = 0.99 + 8.0 / 32.0 / 100.0;
// calculators
Expand Down
Expand Up @@ -65,19 +65,19 @@ public void test_presentValue() {

//-------------------------------------------------------------------------
public void test_reference_price_after_trade_date() {
LocalDate tradeDate = FUTURE_TRADE.getInfo().getTradeDate().get();
LocalDate tradeDate = FUTURE_TRADE.getTradedPrice().get().getTradeDate();
LocalDate valuationDate = tradeDate.plusDays(1);
double settlementPrice = 0.995;
double referencePrice = PRICER_TRADE.referencePrice(FUTURE_TRADE, valuationDate, settlementPrice);
assertEquals(referencePrice, settlementPrice);
}

public void test_reference_price_on_trade_date() {
LocalDate tradeDate = FUTURE_TRADE.getInfo().getTradeDate().get();
LocalDate tradeDate = FUTURE_TRADE.getTradedPrice().get().getTradeDate();
LocalDate valuationDate = tradeDate;
double settlementPrice = 0.995;
double referencePrice = PRICER_TRADE.referencePrice(FUTURE_TRADE, valuationDate, settlementPrice);
assertEquals(referencePrice, FUTURE_TRADE.getPrice());
assertEquals(referencePrice, FUTURE_TRADE.getTradedPrice().get().getPrice());
}

public void test_reference_price_val_date_not_null() {
Expand All @@ -90,7 +90,7 @@ public void test_parSpread_after_trade_date() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider();
prov.setIborRates(mockIbor);
prov.setValuationDate(FUTURE_TRADE.getInfo().getTradeDate().get().plusDays(1));
prov.setValuationDate(FUTURE_TRADE.getTradedPrice().get().getTradeDate().plusDays(1));
when(mockIbor.rate(FUTURE.getIborRate().getObservation())).thenReturn(RATE);
double lastClosingPrice = 0.99;
double parSpreadExpected = PRICER_TRADE.price(FUTURE_TRADE, prov) - lastClosingPrice;
Expand All @@ -102,11 +102,11 @@ public void test_parSpread_on_trade_date() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider();
prov.setIborRates(mockIbor);
prov.setValuationDate(FUTURE_TRADE.getInfo().getTradeDate().get());
prov.setValuationDate(FUTURE_TRADE.getTradedPrice().get().getTradeDate());
when(mockIbor.rate(FUTURE.getIborRate().getObservation())).thenReturn(RATE);

double lastClosingPrice = 0.99;
double parSpreadExpected = PRICER_TRADE.price(FUTURE_TRADE, prov) - FUTURE_TRADE.getPrice();
double parSpreadExpected = PRICER_TRADE.price(FUTURE_TRADE, prov) - FUTURE_TRADE.getTradedPrice().get().getPrice();
double parSpreadComputed = PRICER_TRADE.parSpread(FUTURE_TRADE, prov, lastClosingPrice);
assertEquals(parSpreadComputed, parSpreadExpected, TOLERANCE_PRICE);
}
Expand All @@ -116,7 +116,7 @@ public void test_presentValue_after_trade_date() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider();
prov.setIborRates(mockIbor);
prov.setValuationDate(FUTURE_TRADE.getInfo().getTradeDate().get().plusDays(1));
prov.setValuationDate(FUTURE_TRADE.getTradedPrice().get().getTradeDate().plusDays(1));
when(mockIbor.rate(FUTURE.getIborRate().getObservation())).thenReturn(RATE);

double lastClosingPrice = 1.025;
Expand All @@ -132,12 +132,12 @@ public void test_presentValue_on_trade_date() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider();
prov.setIborRates(mockIbor);
prov.setValuationDate(FUTURE_TRADE.getInfo().getTradeDate().get());
prov.setValuationDate(FUTURE_TRADE.getTradedPrice().get().getTradeDate());
when(mockIbor.rate(FUTURE.getIborRate().getObservation())).thenReturn(RATE);

double lastClosingPrice = 1.025;
DiscountingIborFutureTradePricer pricerFn = DiscountingIborFutureTradePricer.DEFAULT;
double expected = ((1.0 - RATE) - FUTURE_TRADE.getPrice()) *
double expected = ((1.0 - RATE) - FUTURE_TRADE.getTradedPrice().get().getPrice()) *
FUTURE.getAccrualFactor() * FUTURE.getNotional() * FUTURE_TRADE.getQuantity();
CurrencyAmount computed = pricerFn.presentValue(FUTURE_TRADE, prov, lastClosingPrice);
assertEquals(computed.getAmount(), expected, TOLERANCE_PV);
Expand Down
Expand Up @@ -31,7 +31,7 @@
import com.opengamma.strata.market.surface.interpolator.SurfaceInterpolator;
import com.opengamma.strata.pricer.rate.IborIndexRates;
import com.opengamma.strata.pricer.rate.SimpleRatesProvider;
import com.opengamma.strata.product.TradeInfo;
import com.opengamma.strata.product.TradedPrice;
import com.opengamma.strata.product.index.ResolvedIborFutureOption;
import com.opengamma.strata.product.index.ResolvedIborFutureOptionTrade;

Expand Down Expand Up @@ -69,20 +69,14 @@ public class NormalIborFutureOptionMarginedTradePricerTest {
private static final long OPTION_QUANTITY = 12345;
private static final double TRADE_PRICE = 0.0100;
private static final ResolvedIborFutureOptionTrade FUTURE_OPTION_TRADE_TD = ResolvedIborFutureOptionTrade.builder()
.info(TradeInfo.builder()
.tradeDate(VAL_DATE)
.build())
.product(OPTION)
.quantity(OPTION_QUANTITY)
.price(TRADE_PRICE)
.tradedPrice(TradedPrice.of(VAL_DATE, TRADE_PRICE))
.build();
private static final ResolvedIborFutureOptionTrade FUTURE_OPTION_TRADE = ResolvedIborFutureOptionTrade.builder()
.info(TradeInfo.builder()
.tradeDate(TRADE_DATE)
.build())
.product(OPTION)
.quantity(OPTION_QUANTITY)
.price(TRADE_PRICE)
.tradedPrice(TradedPrice.of(TRADE_DATE, TRADE_PRICE))
.build();

private static final double RATE = 0.015;
Expand Down
Expand Up @@ -37,7 +37,7 @@
import com.opengamma.strata.pricer.index.DiscountingIborFutureTradePricer;
import com.opengamma.strata.pricer.rate.ImmutableRatesProvider;
import com.opengamma.strata.product.SecurityId;
import com.opengamma.strata.product.TradeInfo;
import com.opengamma.strata.product.TradedPrice;
import com.opengamma.strata.product.index.IborFuture;
import com.opengamma.strata.product.index.ResolvedIborFuture;
import com.opengamma.strata.product.index.ResolvedIborFutureTrade;
Expand All @@ -55,8 +55,8 @@ public class IborFuturesJpyEnd2EndTest {
private static final double ONE_BASIS_POINT = 1e-4;
private static final double HUNDRED = 100d;
private static final double TOL = 1e-10;
private static final LocalDate VALUATION = LocalDate.of(2016, 2, 10);
private static final TradeInfo TRADE_INFO = TradeInfo.builder().tradeDate(LocalDate.of(2016, 2, 10)).build();
private static final LocalDate TRADE_DATE = LocalDate.of(2016, 2, 10);
private static final LocalDate VALUATION = TRADE_DATE;
private static final double NOTIONAL = 100_000_000D;
private static final long QUANTITY = 1L;
private static final Rounding ROUNDING = Rounding.ofFractionalDecimalPlaces(2, 2);
Expand Down Expand Up @@ -98,11 +98,11 @@ public class IborFuturesJpyEnd2EndTest {
.build().
resolve(REF_DATA);
private static final double REF_PRICE_MAR = 99.9d;
private static final double REF_PRICE_MAR_DECIMAL = REF_PRICE_MAR * ONE_PERCENT;
private static final ResolvedIborFutureTrade FUTURE_TRADE_MAR = ResolvedIborFutureTrade.builder()
.info(TRADE_INFO)
.product(FUTURE_PRODUCT_MAR)
.price(REF_PRICE_MAR * ONE_PERCENT)
.quantity(QUANTITY)
.tradedPrice(TradedPrice.of(TRADE_DATE, REF_PRICE_MAR_DECIMAL))
.build();
// futures in June 2016
private static final LocalDate REFERENCE_JUN = RollConventions.IMM.adjust(LocalDate.of(2016, 6, 1));
Expand All @@ -118,11 +118,11 @@ public class IborFuturesJpyEnd2EndTest {
.build().
resolve(REF_DATA);
private static final double REF_PRICE_JUN = 100d;
private static final double REF_PRICE_JUN_DECIMAL = REF_PRICE_JUN * ONE_PERCENT;
private static final ResolvedIborFutureTrade FUTURE_TRADE_JUN = ResolvedIborFutureTrade.builder()
.info(TRADE_INFO)
.product(FUTURE_PRODUCT_JUN)
.price(REF_PRICE_JUN * ONE_PERCENT)
.quantity(QUANTITY)
.tradedPrice(TradedPrice.of(TRADE_DATE, REF_PRICE_JUN_DECIMAL))
.build();
// futures in September 2016
private static final LocalDate REFERENCE_SEP = RollConventions.IMM.adjust(LocalDate.of(2016, 9, 1));
Expand All @@ -138,11 +138,11 @@ public class IborFuturesJpyEnd2EndTest {
.build().
resolve(REF_DATA);
private static final double REF_PRICE_SEP = 100.075d;
private static final double REF_PRICE_SEP_DECIMAL = REF_PRICE_SEP * ONE_PERCENT;
private static final ResolvedIborFutureTrade FUTURE_TRADE_SEP = ResolvedIborFutureTrade.builder()
.info(TRADE_INFO)
.product(FUTURE_PRODUCT_SEP)
.price(REF_PRICE_SEP * ONE_PERCENT)
.quantity(QUANTITY)
.tradedPrice(TradedPrice.of(TRADE_DATE, REF_PRICE_SEP_DECIMAL))
.build();
// futures in June 2017
private static final LocalDate REFERENCE_JUN_MID = RollConventions.IMM.adjust(LocalDate.of(2017, 6, 1));
Expand All @@ -159,11 +159,11 @@ public class IborFuturesJpyEnd2EndTest {
.build().
resolve(REF_DATA);
private static final double REF_PRICE_JUN_MID = 100.165d;
private static final double REF_PRICE_JUN_MID_DECIMAL = REF_PRICE_JUN_MID * ONE_PERCENT;
private static final ResolvedIborFutureTrade FUTURE_TRADE_JUN_MID = ResolvedIborFutureTrade.builder()
.info(TRADE_INFO)
.product(FUTURE_PRODUCT_JUN_MID)
.price(REF_PRICE_JUN_MID * ONE_PERCENT)
.quantity(QUANTITY)
.tradedPrice(TradedPrice.of(TRADE_DATE, REF_PRICE_JUN_MID_DECIMAL))
.build();
// futures in March 2020
private static final LocalDate REFERENCE_MAR_LONG = RollConventions.IMM.adjust(LocalDate.of(2020, 3, 1));
Expand All @@ -180,11 +180,11 @@ public class IborFuturesJpyEnd2EndTest {
.build().
resolve(REF_DATA);
private static final double REF_PRICE_MAR_LONG = 99.815d;
private static final double REF_PRICE_MAR_LONG_DECIMAL = REF_PRICE_MAR_LONG * ONE_PERCENT;
private static final ResolvedIborFutureTrade FUTURE_TRADE_MAR_LONG = ResolvedIborFutureTrade.builder()
.info(TRADE_INFO)
.product(FUTURE_PRODUCT_MAR_LONG)
.price(REF_PRICE_MAR_LONG * ONE_PERCENT)
.quantity(QUANTITY)
.tradedPrice(TradedPrice.of(TRADE_DATE, REF_PRICE_MAR_LONG_DECIMAL))
.build();
// pricers
private static final DiscountingIborFutureProductPricer PRODUCT_PRICER = DiscountingIborFutureProductPricer.DEFAULT;
Expand Down Expand Up @@ -265,24 +265,19 @@ public void priceSensitivity() {

public void presentValue() {
// March 2016
CurrencyAmount pvMar = TRADE_PRICER.presentValue(FUTURE_TRADE_MAR, RATES_PROVIDER,
FUTURE_TRADE_MAR.getPrice());
CurrencyAmount pvMar = TRADE_PRICER.presentValue(FUTURE_TRADE_MAR, RATES_PROVIDER, REF_PRICE_MAR_DECIMAL);
assertEquals(pvMar.getAmount(), -9738.418878056109, TOL * NOTIONAL);
// June 2016
CurrencyAmount pvJun = TRADE_PRICER.presentValue(FUTURE_TRADE_JUN, RATES_PROVIDER,
FUTURE_TRADE_JUN.getPrice());
CurrencyAmount pvJun = TRADE_PRICER.presentValue(FUTURE_TRADE_JUN, RATES_PROVIDER, REF_PRICE_JUN_DECIMAL);
assertEquals(pvJun.getAmount(), -3812.1182441189885, TOL * NOTIONAL);
// September 2016
CurrencyAmount pvSep = TRADE_PRICER.presentValue(FUTURE_TRADE_SEP, RATES_PROVIDER,
FUTURE_TRADE_SEP.getPrice());
CurrencyAmount pvSep = TRADE_PRICER.presentValue(FUTURE_TRADE_SEP, RATES_PROVIDER, REF_PRICE_SEP_DECIMAL);
assertEquals(pvSep.getAmount(), -5689.603123847395, TOL * NOTIONAL);
// June 2017
CurrencyAmount pvJunMid =
TRADE_PRICER.presentValue(FUTURE_TRADE_JUN_MID, RATES_PROVIDER, FUTURE_TRADE_JUN_MID.getPrice());
CurrencyAmount pvJunMid = TRADE_PRICER.presentValue(FUTURE_TRADE_JUN_MID, RATES_PROVIDER, REF_PRICE_JUN_MID_DECIMAL);
assertEquals(pvJunMid.getAmount(), 4022.2380772829056, TOL * NOTIONAL);
// March 2020
CurrencyAmount pvMarLong =
TRADE_PRICER.presentValue(FUTURE_TRADE_MAR_LONG, RATES_PROVIDER, FUTURE_TRADE_MAR_LONG.getPrice());
CurrencyAmount pvMarLong = TRADE_PRICER.presentValue(FUTURE_TRADE_MAR_LONG, RATES_PROVIDER, REF_PRICE_MAR_LONG_DECIMAL);
assertEquals(pvMarLong.getAmount(), 35818.328803278506, TOL * NOTIONAL);
}

Expand Down Expand Up @@ -333,21 +328,19 @@ public void presentValueSensitivity() {

public void parSpread() {
// March 2016
double psMar = TRADE_PRICER.parSpread(FUTURE_TRADE_MAR, RATES_PROVIDER, FUTURE_TRADE_MAR.getPrice()) * HUNDRED;
double psMar = TRADE_PRICER.parSpread(FUTURE_TRADE_MAR, RATES_PROVIDER, REF_PRICE_MAR_DECIMAL) * HUNDRED;
assertEquals(psMar, -0.038953675512221064, TOL * HUNDRED);
// June 2016
double psJun = TRADE_PRICER.parSpread(FUTURE_TRADE_JUN, RATES_PROVIDER, FUTURE_TRADE_JUN.getPrice()) * HUNDRED;
double psJun = TRADE_PRICER.parSpread(FUTURE_TRADE_JUN, RATES_PROVIDER, REF_PRICE_JUN_DECIMAL) * HUNDRED;
assertEquals(psJun, -0.01524847297647014, TOL * HUNDRED);
// September 2016
double psSep = TRADE_PRICER.parSpread(FUTURE_TRADE_SEP, RATES_PROVIDER, FUTURE_TRADE_SEP.getPrice()) * HUNDRED;
double psSep = TRADE_PRICER.parSpread(FUTURE_TRADE_SEP, RATES_PROVIDER, REF_PRICE_SEP_DECIMAL) * HUNDRED;
assertEquals(psSep, -0.022758412495393898, TOL * HUNDRED);
// June 2017
double psJunMid =
TRADE_PRICER.parSpread(FUTURE_TRADE_JUN_MID, RATES_PROVIDER, FUTURE_TRADE_JUN_MID.getPrice()) * HUNDRED;
double psJunMid = TRADE_PRICER.parSpread(FUTURE_TRADE_JUN_MID, RATES_PROVIDER, REF_PRICE_JUN_MID_DECIMAL) * HUNDRED;
assertEquals(psJunMid, 0.01608895230913454, TOL * HUNDRED);
// March 2020
double psMarLong =
TRADE_PRICER.parSpread(FUTURE_TRADE_MAR_LONG, RATES_PROVIDER, FUTURE_TRADE_MAR_LONG.getPrice()) * HUNDRED;
double psMarLong = TRADE_PRICER.parSpread(FUTURE_TRADE_MAR_LONG, RATES_PROVIDER, REF_PRICE_MAR_LONG_DECIMAL) * HUNDRED;
assertEquals(psMarLong, 0.14327331521311049, TOL * HUNDRED);
}

Expand Down
Expand Up @@ -74,6 +74,8 @@ public final class ResolvedBondFutureOptionTrade
* The price that was traded, together with the trade date, optional.
* <p>
* This is the price agreed when the trade occurred, in decimal form.
* Strata uses <i>decimal prices</i> for bond futures options in the trade model, pricers and market data.
* This is coherent with the pricing of {@link BondFuture}.
* <p>
* This is optional to allow the class to be used to price both trades and positions.
* When the instance represents a trade, the traded price should be present.
Expand Down Expand Up @@ -180,6 +182,8 @@ public double getQuantity() {
* Gets the price that was traded, together with the trade date, optional.
* <p>
* This is the price agreed when the trade occurred, in decimal form.
* Strata uses <i>decimal prices</i> for bond futures options in the trade model, pricers and market data.
* This is coherent with the pricing of {@link BondFuture}.
* <p>
* This is optional to allow the class to be used to price both trades and positions.
* When the instance represents a trade, the traded price should be present.
Expand Down Expand Up @@ -498,6 +502,8 @@ public Builder quantity(double quantity) {
* Sets the price that was traded, together with the trade date, optional.
* <p>
* This is the price agreed when the trade occurred, in decimal form.
* Strata uses <i>decimal prices</i> for bond futures options in the trade model, pricers and market data.
* This is coherent with the pricing of {@link BondFuture}.
* <p>
* This is optional to allow the class to be used to price both trades and positions.
* When the instance represents a trade, the traded price should be present.
Expand Down

0 comments on commit ab9440e

Please sign in to comment.