Package com.opengamma.financial.analytics.model.pnl

Source Code of com.opengamma.financial.analytics.model.pnl.MarkToMarketPnLFunction

/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.model.pnl;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.LocalDate;
import org.threeten.bp.ZonedDateTime;

import com.google.common.collect.Sets;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.core.position.Trade;
import com.opengamma.core.security.Security;
import com.opengamma.core.value.MarketDataRequirementNames;
import com.opengamma.engine.ComputationTarget;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.cache.MissingInput;
import com.opengamma.engine.function.AbstractFunction;
import com.opengamma.engine.function.FunctionCompilationContext;
import com.opengamma.engine.function.FunctionExecutionContext;
import com.opengamma.engine.function.FunctionInputs;
import com.opengamma.engine.target.ComputationTargetReference;
import com.opengamma.engine.target.ComputationTargetType;
import com.opengamma.engine.value.ComputedValue;
import com.opengamma.engine.value.ValueProperties;
import com.opengamma.engine.value.ValuePropertyNames;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.engine.value.ValueRequirementNames;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.financial.analytics.model.forex.FXUtils;
import com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils;
import com.opengamma.financial.security.FinancialSecurityUtils;
import com.opengamma.financial.security.bond.BondSecurity;
import com.opengamma.financial.security.future.FutureSecurity;
import com.opengamma.financial.security.future.InterestRateFutureSecurity;
import com.opengamma.financial.security.option.EquityIndexFutureOptionSecurity;
import com.opengamma.financial.security.option.EquityIndexOptionSecurity;
import com.opengamma.financial.security.option.EquityOptionSecurity;
import com.opengamma.financial.security.option.IRFutureOptionSecurity;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.async.AsynchronousExecution;
import com.opengamma.util.money.Currency;

/**
* Function that computes the profit or loss since previous close,
* as defined by {@link ValueRequirementNames#HISTORICAL_TIME_SERIES_LATEST}. This will get most recent closing price before today.
* By intention, this will not be today's close even if it's available. Note that this may be stale, if time series aren't updated nightly, as we take latest value.
* Illiquid securities do not trade each day..
* As the name MarkToMarket implies, this simple Function applies to Trades on Exchange-Traded Securities.
*/
public class MarkToMarketPnLFunction extends AbstractFunction.NonCompiledInvoker {

  /** The logger */
  private static final Logger s_logger = LoggerFactory.getLogger(MarkToMarketPnLFunction.class);

  private final String _costOfCarryField;
  private final String _closingPriceField;

  public MarkToMarketPnLFunction(String closingPriceField, String costOfCarryField) {
    ArgumentChecker.notNull(costOfCarryField, "costOfCarryField");
    ArgumentChecker.notNull(closingPriceField, "closingPriceField");
    _closingPriceField = closingPriceField;
    _costOfCarryField = costOfCarryField;
  }

  protected String getValueRequirementName() {
    return ValueRequirementNames.MTM_PNL;
  }

  @Override
  public ComputationTargetType getTargetType() {
    return ComputationTargetType.TRADE;
  }

  @Override
  public boolean canApplyTo(FunctionCompilationContext context, ComputationTarget target) {

    final Security security = target.getPositionOrTrade().getSecurity();
    if (FXUtils.isFXSecurity(security)) {
      return false;
    }
    return FinancialSecurityUtils.isExchangeTraded(security) || (security instanceof BondSecurity); // See SecurityMarketValueFunction
  }

  @Override
  public Set<ComputedValue> execute(FunctionExecutionContext executionContext,
                                    FunctionInputs inputs,
                                    ComputationTarget target,
                                    Set<ValueRequirement> desiredValues) throws AsynchronousExecution {
    // 1. Unpack
    final Trade trade = target.getTrade();
    final Security security = trade.getSecurity();
    final LocalDate tradeDate = trade.getTradeDate();
    LocalDate valuationDate = ZonedDateTime.now(executionContext.getValuationClock()).toLocalDate();
    final boolean isNewTrade = tradeDate.equals(valuationDate);

    // Get desired TradeType: Open (traded before today), New (traded today) or All
    final ValueRequirement desiredValue = desiredValues.iterator().next();
    final String tradeType = desiredValue.getConstraint(PnLFunctionUtils.PNL_TRADE_TYPE_CONSTRAINT);
    if (tradeType == null) {
      s_logger.error("TradeType not set for: " + security.getName() +
          ". Choose one of {" + PnLFunctionUtils.PNL_TRADE_TYPE_OPEN + "," + PnLFunctionUtils.PNL_TRADE_TYPE_OPEN + "," + PnLFunctionUtils.PNL_TRADE_TYPE_ALL + "}");
    }

    // Create output specification. Check for trivial cases
    final ValueSpecification valueSpecification = new ValueSpecification(getValueRequirementName(), target.toSpecification(), desiredValue.getConstraints());
    if (isNewTrade && tradeType.equalsIgnoreCase(PnLFunctionUtils.PNL_TRADE_TYPE_OPEN) ||
        (!isNewTrade) && tradeType.equalsIgnoreCase(PnLFunctionUtils.PNL_TRADE_TYPE_NEW)) {
      return Sets.newHashSet(new ComputedValue(valueSpecification, 0.0));
    }

    // 2. Get inputs
    // For all TradeTypes, we'll require the live Price
    Double livePrice = calculateLivePrice(inputs, target);

    // For PNL, we need a reference price. We have two cases:
    // Open: will need the closing price and any carry
    // New: will need the trade price
    Double referencePrice;
    Double costOfCarry = 0.0;

    if (isNewTrade) {
      referencePrice = trade.getPremium();
      if (referencePrice == null) {
        throw new NullPointerException("New Trades require a premium to compute PNL on trade date. Premium was null for " + trade.getUniqueId());
      }
      if ((security instanceof InterestRateFutureSecurity || security instanceof IRFutureOptionSecurity) && (trade.getPremium() > 1.0)) {
        referencePrice /= 100.0;
      }
    } else {
      referencePrice = calculateReferencePrice(inputs, target);
      if (referencePrice == null) {
        final ComputedValue result = new ComputedValue(valueSpecification, MissingInput.MISSING_MARKET_DATA);
        return Sets.newHashSet(result);
      }
      Object carryValue = inputs.getValue(_costOfCarryField);
      if (carryValue != null) {
        costOfCarry = (Double) carryValue;
      }
    }
    // 3. Compute the PNL
    // Move in the marked prices: Live - Previous Close
    final Double dailyPriceMove = livePrice - referencePrice;
    // Total move := Value
    Double dailyValueMove = dailyPriceMove - costOfCarry;

    // 4. Scale by Trade Notionals and Quantity
    // Some SecurityType's have Notional values built-in. Scale by these if required.
    if (security instanceof FutureSecurity) {
      final FutureSecurity futureSecurity = (FutureSecurity) security;
      dailyValueMove *= futureSecurity.getUnitAmount();
    } else if (security instanceof EquityOptionSecurity) {
      final EquityOptionSecurity optionSecurity = (EquityOptionSecurity) security;
      dailyValueMove *= optionSecurity.getPointValue();
    } else if (security instanceof EquityIndexOptionSecurity) {
      final EquityIndexOptionSecurity optionSecurity = (EquityIndexOptionSecurity) security;
      dailyValueMove *= optionSecurity.getPointValue();
    } else if (security instanceof EquityIndexFutureOptionSecurity) {
      final EquityIndexFutureOptionSecurity optionSecurity = (EquityIndexFutureOptionSecurity) security;
      dailyValueMove *= optionSecurity.getPointValue();
    } else if (security instanceof IRFutureOptionSecurity) {
      final IRFutureOptionSecurity optionSecurity = (IRFutureOptionSecurity) security;
      dailyValueMove *= optionSecurity.getPointValue();
    }
    // Multiply by the Trade's Quantity
    final Double dailyPnL = target.getTrade().getQuantity().doubleValue() * dailyValueMove;

    // 5. Return
    final ComputedValue result = new ComputedValue(valueSpecification, dailyPnL);
    return Sets.newHashSet(result);
  }


  protected ValueProperties.Builder createValueProperties(final ComputationTarget target) {
    final ValueProperties.Builder properties = createValueProperties();
    properties.withAny(PnLFunctionUtils.PNL_TRADE_TYPE_CONSTRAINT);
    final Currency ccy = FinancialSecurityUtils.getCurrency(target.getPositionOrTrade().getSecurity());
    if (ccy != null) {
      properties.with(ValuePropertyNames.CURRENCY, ccy.getCode());
    }
    return properties;
  }

  @Override
  public Set<ValueSpecification> getResults(FunctionCompilationContext context, ComputationTarget target) {
    return Collections.singleton(new ValueSpecification(getValueRequirementName(),
                                                        target.toSpecification(),
                                                        createValueProperties(target).get()));
  }

  @Override
  public Set<ValueRequirement> getRequirements(FunctionCompilationContext context, ComputationTarget target, ValueRequirement desiredValue) {
    final Set<ValueRequirement> requirements = new HashSet<>();
    final Security security = target.getPositionOrTrade().getSecurity();
    requirements.addAll(createLivePriceRequirement(security));
    requirements.addAll(createReferencePriceRequirement(security));
    if (_costOfCarryField.length() > 0) {     // Cost of Carry, if provided
      requirements.add(HistoricalTimeSeriesFunctionUtils.createHTSLatestRequirement(security, _costOfCarryField, null));
    }
    return requirements;
  }

  /**
   * @param security the target's security
   * @return Engine Function requirements for the current / live price
   */
  protected Set<ValueRequirement> createLivePriceRequirement(Security security) {
    final ComputationTargetReference securityTarget = new ComputationTargetSpecification(ComputationTargetType.SECURITY, security.getUniqueId());
    final ValueRequirement securityValueReq = new ValueRequirement(MarketDataRequirementNames.MARKET_VALUE, securityTarget);
    return Collections.singleton(securityValueReq);
  }
 
  /**
   * @param security the target's security
   * @return Engine Function requirements for the closing / reference price
   */
  protected Set<ValueRequirement> createReferencePriceRequirement(Security security) {
    ValueRequirement htsReq =
        HistoricalTimeSeriesFunctionUtils.createHTSLatestRequirement(security, getClosingPriceField(), null);
    return Collections.singleton(htsReq);
  }
 
  // Provides the current / live price
  protected Double calculateLivePrice(FunctionInputs inputs, ComputationTarget target) { 
    final ComputedValue valLivePrice = inputs.getComputedValue(MarketDataRequirementNames.MARKET_VALUE);
    if (valLivePrice == null) {
      throw new OpenGammaRuntimeException(MarketDataRequirementNames.MARKET_VALUE + " not available," + target);
    }
    return (Double) valLivePrice.getValue();
  }
 
  // Provides the closing / reference price
  protected Double calculateReferencePrice(FunctionInputs inputs, ComputationTarget target) {
    for (ComputedValue input : inputs.getAllValues()) {
      if (input.getSpecification().getValueName().equals(ValueRequirementNames.HISTORICAL_TIME_SERIES_LATEST)) {
        String field = input.getSpecification().getProperty(HistoricalTimeSeriesFunctionUtils.DATA_FIELD_PROPERTY);
        if (field.equals(getClosingPriceField())) {
          Object value = input.getValue();
          if (value == null) {
            return null;
          }
          return (Double) value;
        }
      }
    }
    return null;
  }

  @Override
  public boolean canHandleMissingRequirements() {
    return true;
  }

  protected String getClosingPriceField() {
    return _closingPriceField;
  }
}
TOP

Related Classes of com.opengamma.financial.analytics.model.pnl.MarkToMarketPnLFunction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.