protected FXForwardSecurity createFXForwardSecurity(final Bundle bundle) { final double putAmount = bundle._firstCurrency.equals(Currency.JPY) ? NOTIONAL * 100 : NOTIONAL; final ZonedDateTime forwardDate = nextWorkingDay( bundle._tradeDate.plusDays(bundle._daysOffset), bundle._firstCurrency, bundle._secondCurrency); final Double fxRate = getApproxFXRate( forwardDate.toLocalDate(), Pair.of(bundle._firstCurrency, bundle._secondCurrency)); if (fxRate == null) { return null; } final double callAmount = NOTIONAL * fxRate; final Currency payCurrency = bundle._long ? bundle._secondCurrency : bundle._firstCurrency; final Currency receiveCurrency = bundle._long ? bundle._firstCurrency : bundle._secondCurrency; final String dateString = forwardDate.toString(DATE_FORMATTER); final FXForwardSecurity fxForwardSecurity = new FXForwardSecurity( payCurrency, callAmount, receiveCurrency, putAmount, forwardDate, REGION); final String callAmountString = NOTIONAL_FORMATTER.format(callAmount); final String putAmountString = NOTIONAL_FORMATTER.format(putAmount); fxForwardSecurity.setName( "Pay " + payCurrency + " " + callAmountString + ", receive " + receiveCurrency + " " + putAmountString + " on " + dateString); return fxForwardSecurity; }
protected FXBarrierOptionSecurity createFXBarrierOptionSecurity(final Bundle bundle) { final Currency putCurrency = bundle._firstCurrency; final Currency callCurrency = bundle._secondCurrency; final double putAmount = putCurrency.equals(Currency.JPY) ? NOTIONAL * 100 : NOTIONAL; final ZonedDateTime settlementDate = nextWorkingDay( bundle._tradeDate.plusDays(bundle._daysOffset), bundle._firstCurrency, bundle._secondCurrency); final Expiry expiry = new Expiry(settlementDate, ExpiryAccuracy.DAY_MONTH_YEAR); final Double fxRate = getApproxFXRate( settlementDate.toLocalDate(), Pair.of(bundle._firstCurrency, bundle._secondCurrency)); if (fxRate == null) { return null; } final double callAmount = NOTIONAL * fxRate; final String dateString = settlementDate.toString(DATE_FORMATTER); final BarrierType barrierType = bundle._up ? BarrierType.UP : BarrierType.DOWN; final BarrierDirection barrierDirection = BarrierDirection.KNOCK_IN; final MonitoringType monitoringType = MonitoringType.CONTINUOUS; final SamplingFrequency samplingFrequency = SamplingFrequency.DAILY_CLOSE; final double barrierLevel = bundle._up ? fxRate * 1.5 : fxRate / 1.5; final FXBarrierOptionSecurity fxBarrierOptionSecurity = new FXBarrierOptionSecurity( putCurrency, callCurrency, putAmount, callAmount, expiry, settlementDate, barrierType, barrierDirection, monitoringType, samplingFrequency, barrierLevel, bundle._long); final String callAmountString = NOTIONAL_FORMATTER.format(callAmount); final String putAmountString = NOTIONAL_FORMATTER.format(putAmount); final String barrierLevelString = RATE_FORMATTER.format(barrierLevel); final String barrierUnitString = callCurrency + "/" + putCurrency; fxBarrierOptionSecurity.setName( (bundle._long ? "Long " : "Short ") + (bundle._up ? "up" : "down") + " knock-in at " + barrierLevelString + " " + barrierUnitString + ", put " + putCurrency + " " + putAmountString + ", call " + callCurrency + " " + callAmountString + " on " + dateString); return fxBarrierOptionSecurity; }
protected FXDigitalOptionSecurity createFXDigitalOptionSecurity(final Bundle bundle) { final Currency putCurrency = bundle._firstCurrency; final Currency callCurrency = bundle._secondCurrency; final Currency paymentCurrency = bundle._paymentCurrency; final double putAmount = putCurrency.equals(Currency.JPY) ? NOTIONAL * 100 : NOTIONAL; final ZonedDateTime expiry = nextWorkingDay(bundle._tradeDate.plusDays(bundle._daysOffset), putCurrency, callCurrency); final Double rate = getApproxFXRate(expiry.toLocalDate(), Pair.of(putCurrency, callCurrency)); if (rate == null) { return null; } final double callAmount = rate * NOTIONAL; final ZonedDateTime settlementDate = nextWorkingDay(expiry.plusDays(2), putCurrency, callCurrency); final FXDigitalOptionSecurity security = new FXDigitalOptionSecurity( putCurrency, callCurrency, putAmount, callAmount, paymentCurrency, new Expiry(expiry), settlementDate, bundle._long); final StringBuilder sb = new StringBuilder("Digital "); sb.append(bundle._long ? "Long" : "Short"); sb.append(" put ").append(putCurrency).append(' ').append(NOTIONAL_FORMATTER.format(putAmount)); sb.append(", call ") .append(callCurrency) .append(' ') .append(NOTIONAL_FORMATTER.format(callAmount)); sb.append(" on ").append(expiry.toString(DATE_FORMATTER)); security.setName(sb.toString()); return security; }
/** * Creates the output root data. * * @return the output root data, not null */ protected FlexiBean createRootData() { FlexiBean out = super.createRootData(); HolidayDocument latestDoc = data().getHoliday(); HolidayDocument versionedHoliday = data().getVersioned(); out.put("latestHolidayDoc", latestDoc); out.put("latestHoliday", latestDoc.getHoliday()); out.put("holidayDoc", versionedHoliday); out.put("holiday", versionedHoliday.getHoliday()); out.put("deleted", !latestDoc.isLatest()); List<Pair<Year, List<LocalDate>>> map = new ArrayList<Pair<Year, List<LocalDate>>>(); List<LocalDate> dates = versionedHoliday.getHoliday().getHolidayDates(); if (dates.size() > 0) { int year = dates.get(0).getYear(); int start = 0; int pos = 0; for (; pos < dates.size(); pos++) { if (dates.get(pos).getYear() == year) { continue; } map.add(Pair.of(Year.of(year), dates.subList(start, pos))); year = dates.get(pos).getYear(); start = pos; } map.add(Pair.of(Year.of(year), dates.subList(start, pos))); } out.put("holidayDatesByYear", map); return out; }
private static void populateVolatilitySurfaceDefinitions( final ConfigMaster configMaster, final UniqueIdentifiable target) { final Tenor[] expiryTenors = new Tenor[] { Tenor.ofDays(7), Tenor.ofDays(14), Tenor.ofDays(21), Tenor.ofMonths(1), Tenor.ofMonths(3), Tenor.ofMonths(6), Tenor.ofMonths(9), Tenor.ofYears(1), Tenor.ofYears(5), Tenor.ofYears(10) }; @SuppressWarnings("unchecked") final Pair<Number, FXVolQuoteType>[] deltaAndTypes = new Pair[] { Pair.of(25, FXVolQuoteType.BUTTERFLY), Pair.of(25, FXVolQuoteType.RISK_REVERSAL), Pair.of(15, FXVolQuoteType.BUTTERFLY), Pair.of(15, FXVolQuoteType.RISK_REVERSAL), Pair.of(0, FXVolQuoteType.ATM) }; final VolatilitySurfaceDefinition<Tenor, Pair<Number, FXVolQuoteType>> volSurfaceDefinition = new VolatilitySurfaceDefinition<Tenor, Pair<Number, FXVolQuoteType>>( "SECONDARY_EURUSD_" + InstrumentTypeProperties.FOREX, target, expiryTenors, deltaAndTypes); ConfigMasterUtils.storeByName(configMaster, makeConfigDocument(volSurfaceDefinition)); }
@SuppressWarnings("unchecked") @Test public void expandedRagged() { Tenor[] xs = new Tenor[] {Tenor.DAY, Tenor.ONE_WEEK, Tenor.TWO_WEEKS, Tenor.TWO_WEEKS, Tenor.ONE_MONTH}; Tenor[] ys = new Tenor[] { Tenor.ONE_YEAR, Tenor.ONE_YEAR, Tenor.ONE_YEAR, Tenor.TWO_YEARS, Tenor.TWO_YEARS }; double[] vols = new double[] {10, 11, 12, 13, 14}; Map<Pair<Tenor, Tenor>, Double> values = Maps.newHashMap(); for (int i = 0; i < xs.length; i++) { values.put(Pair.of(xs[i], ys[i]), vols[i]); } String name = "test"; UniqueIdentifiable target = Currency.USD; VolatilitySurfaceData<Tenor, Tenor> data = new VolatilitySurfaceData<>(name, name, target, xs, ys, values); Map<String, Object> map = (Map<String, Object>) new VolatilitySurfaceDataFormatter() .format(data, null, TypeFormatter.Format.EXPANDED, null); assertEquals( Lists.newArrayList("1D", "7D", "14D", "1M"), map.get(SurfaceFormatterUtils.X_LABELS)); assertEquals(Lists.newArrayList("1Y", "2Y"), map.get(SurfaceFormatterUtils.Y_LABELS)); assertEquals( Lists.newArrayList(10d, 11d, 12d, null, null, null, 13d, 14d), map.get(SurfaceFormatterUtils.VOL)); }
@Override public synchronized YieldCurveDefinitionDocument update(YieldCurveDefinitionDocument document) { ArgumentChecker.notNull(document, "document"); ArgumentChecker.notNull(document.getYieldCurveDefinition(), "document.yieldCurveDefinition"); final Currency currency = document.getYieldCurveDefinition().getCurrency(); final String name = document.getYieldCurveDefinition().getName(); final UniqueId uid = UniqueId.of(getUniqueIdScheme(), name + "_" + currency.getCode()); if (!uid.equals(document.getUniqueId())) { throw new IllegalArgumentException("Invalid unique identifier"); } final Pair<Currency, String> key = Pair.of(currency, name); final TreeMap<Instant, YieldCurveDefinition> value = _definitions.get(key); if (value == null) { throw new DataNotFoundException("UID '" + uid + "' not found"); } if (_sourceVersionCorrection.getVersionAsOf() != null) { // Don't need to keep the old values before the one needed by "versionAsOfInstant" final Instant oldestNeeded = value.floorKey(_sourceVersionCorrection.getVersionAsOf()); value.headMap(oldestNeeded).clear(); } else { // Don't need any old values value.clear(); } Instant now = Instant.now(); value.put(now, document.getYieldCurveDefinition()); document.setUniqueId(uid); changeManager().entityChanged(ChangeType.CHANGED, uid.getObjectId(), null, null, now); return document; }
// ------------------------------------------------------------------------- @Override public synchronized YieldCurveDefinitionDocument add(YieldCurveDefinitionDocument document) { ArgumentChecker.notNull(document, "document"); ArgumentChecker.notNull(document.getYieldCurveDefinition(), "document.yieldCurveDefinition"); final Currency currency = document.getYieldCurveDefinition().getCurrency(); final String name = document.getYieldCurveDefinition().getName(); final Pair<Currency, String> key = Pair.of(currency, name); if (_definitions.containsKey(key)) { throw new IllegalArgumentException("Duplicate definition"); } final TreeMap<Instant, YieldCurveDefinition> value = new TreeMap<Instant, YieldCurveDefinition>(); Instant now = Instant.now(); value.put(now, document.getYieldCurveDefinition()); _definitions.put(key, value); final UniqueId uid = UniqueId.of(getUniqueIdScheme(), name + "_" + currency.getCode()); document.setUniqueId(uid); changeManager() .entityChanged( ChangeType.ADDED, document.getObjectId(), document.getVersionFromInstant(), document.getVersionToInstant(), now); return document; }
@Override public CurveBuildingBlockBundle buildObject( final FudgeDeserializer deserializer, final FudgeMsg message) { final List<FudgeField> curveNames = message.getAllByName(CURVE_NAME_FIELD); final List<FudgeField> blocks = message.getAllByName(BLOCK_FIELD); final List<FudgeField> matrices = message.getAllByName(MATRIX_FIELD); final int n = curveNames.size(); if (blocks.size() != n) { throw new IllegalStateException( "Should have one block for each curve name; have " + curveNames + " and " + blocks); } if (matrices.size() != n) { throw new IllegalStateException( "Should have one matrix for each curve name; have " + curveNames + " and " + matrices); } final LinkedHashMap<String, Pair<CurveBuildingBlock, DoubleMatrix2D>> data = new LinkedHashMap<>(); for (int i = 0; i < n; i++) { final String curveName = (String) curveNames.get(i).getValue(); final CurveBuildingBlock block = deserializer.fieldValueToObject(CurveBuildingBlock.class, blocks.get(i)); final DoubleMatrix2D m = new DoubleMatrix2D(deserializer.fieldValueToObject(double[][].class, matrices.get(i))); data.put(curveName, Pair.of(block, m)); } return new CurveBuildingBlockBundle(data); }
@Override public CurveBuildingBlock buildObject( final FudgeDeserializer deserializer, final FudgeMsg message) { final List<FudgeField> curveNames = message.getAllByName(CURVE_NAME_FIELD); final List<FudgeField> startIndices = message.getAllByName(START_INDEX_FIELD); final int n = curveNames.size(); if (startIndices.size() != n) { throw new IllegalStateException( "Should have one start index for each curve name; have " + curveNames + " and " + startIndices); } final List<FudgeField> numbers = message.getAllByName(NUMBER_FIELD); if (numbers.size() != n) { throw new IllegalStateException( "Should have one parameter number for each curve name; have " + curveNames + " and " + numbers); } final LinkedHashMap<String, Pair<Integer, Integer>> data = new LinkedHashMap<>(); for (int i = 0; i < n; i++) { final String curveName = (String) curveNames.get(i).getValue(); final Integer startIndex = ((Number) startIndices.get(i).getValue()).intValue(); final Integer number = ((Number) numbers.get(i).getValue()).intValue(); data.put(curveName, Pair.of(startIndex, number)); } return new CurveBuildingBlock(data); }
@SuppressWarnings("unchecked") public Pair<ResolveTask[], ResolvedValueProducer[]> getTasksProducing( final ValueSpecification valueSpecification) { do { final MapEx<ResolveTask, ResolvedValueProducer> tasks = getBuilder().getTasks(valueSpecification); if (tasks != null) { final ResolveTask[] resultTasks; final ResolvedValueProducer[] resultProducers; synchronized (tasks) { if (tasks.containsKey(null)) { continue; } if (tasks.isEmpty()) { return null; } resultTasks = new ResolveTask[tasks.size()]; resultProducers = new ResolvedValueProducer[tasks.size()]; int i = 0; for (final Map.Entry<ResolveTask, ResolvedValueProducer> task : (Set<Map.Entry<ResolveTask, ResolvedValueProducer>>) tasks.entrySet()) { // Don't ref-count the tasks; they're just used for parent comparisons resultTasks[i] = task.getKey(); resultProducers[i++] = task.getValue(); task.getValue().addRef(); // We're holding the task lock } } return Pair.of(resultTasks, resultProducers); } else { return null; } } while (true); }
@Override public synchronized YieldCurveDefinitionDocument get( ObjectIdentifiable objectIdable, VersionCorrection versionCorrection) { ArgumentChecker.notNull(objectIdable, "objectIdable"); ObjectId objectId = objectIdable.getObjectId(); if (!getUniqueIdScheme().equals(objectId.getScheme())) { throw new DataNotFoundException( "Scheme '" + objectId.getScheme() + "' not valid for '" + getUniqueIdScheme() + "'"); } final int i = objectId.getValue().indexOf('_'); if (i <= 0) { throw new DataNotFoundException( "Identifier '" + objectId.getValue() + "' not valid for '" + getUniqueIdScheme() + "'"); } final String name = objectId.getValue().substring(0, i); final String iso = objectId.getValue().substring(i + 1); final Currency currency; try { currency = Currency.of(iso); } catch (IllegalArgumentException e) { throw new DataNotFoundException( "Identifier '" + objectId.getValue() + "' not valid for '" + getUniqueIdScheme() + "'", e); } final TreeMap<Instant, YieldCurveDefinition> definitions = _definitions.get(Pair.of(currency, name)); if (definitions == null) { throw new DataNotFoundException("Curve definition not found"); } final YieldCurveDefinition definition = definitions.lastEntry().getValue(); if (definition == null) { throw new DataNotFoundException("Curve definition not found"); } return new YieldCurveDefinitionDocument(objectId.atLatestVersion(), definition); }
@SuppressWarnings("unchecked") @Test public void expandedRectangular() { Tenor[] xVals = new Tenor[] {Tenor.DAY, Tenor.ONE_WEEK, Tenor.TWO_WEEKS}; Tenor[] yVals = new Tenor[] {Tenor.ONE_YEAR, Tenor.TWO_YEARS}; double[] vols = new double[] {10, 11, 12, 13, 14, 15}; Map<Pair<Tenor, Tenor>, Double> vol = Maps.newHashMap(); for (int y = 0; y < yVals.length; y++) { for (int x = 0; x < xVals.length; x++) { vol.put(Pair.of(xVals[x], yVals[y]), vols[x + (y * xVals.length)]); } } String name = "test"; UniqueIdentifiable target = Currency.USD; VolatilitySurfaceData<Tenor, Tenor> data = new VolatilitySurfaceData<>(name, name, target, xVals, yVals, vol); Map<String, Object> map = (Map<String, Object>) new VolatilitySurfaceDataFormatter() .format(data, null, TypeFormatter.Format.EXPANDED, null); assertEquals(Lists.newArrayList("1D", "7D", "14D"), map.get(SurfaceFormatterUtils.X_LABELS)); assertEquals(Lists.newArrayList("1Y", "2Y"), map.get(SurfaceFormatterUtils.Y_LABELS)); assertEquals( Lists.newArrayList(10d, 11d, 12d, 13d, 14d, 15d), map.get(SurfaceFormatterUtils.VOL)); }
public static Collection<Pair<ValueSpecification, Object>> getValues( final ViewComputationCache cache, final Collection<ValueSpecification> specifications) { final Collection<Pair<ValueSpecification, Object>> values = new ArrayList<Pair<ValueSpecification, Object>>(specifications.size()); for (ValueSpecification specification : specifications) { values.add(Pair.of(specification, cache.getValue(specification))); } return values; }
@Override public synchronized void remove(ObjectIdentifiable objectIdentifiable) { ArgumentChecker.notNull(objectIdentifiable, "objectIdentifiable"); if (!getUniqueIdScheme().equals(objectIdentifiable.getObjectId().getScheme())) { throw new DataNotFoundException( "Scheme '" + objectIdentifiable.getObjectId().getScheme() + "' not valid for '" + getUniqueIdScheme() + "'"); } final int i = objectIdentifiable.getObjectId().getValue().indexOf('_'); if (i <= 0) { throw new DataNotFoundException( "Identifier '" + objectIdentifiable.getObjectId().getValue() + "' not valid for '" + getUniqueIdScheme() + "'"); } final String name = objectIdentifiable.getObjectId().getValue().substring(0, i); final String iso = objectIdentifiable.getObjectId().getValue().substring(i + 1); final Currency currency; try { currency = Currency.of(iso); } catch (IllegalArgumentException e) { throw new DataNotFoundException( "Identifier '" + objectIdentifiable.getObjectId().getValue() + "' not valid for '" + getUniqueIdScheme() + "'", e); } final Pair<Currency, String> key = Pair.of(currency, name); if (_sourceVersionCorrection.getVersionAsOf() != null) { final TreeMap<Instant, YieldCurveDefinition> value = _definitions.get(key); if (value == null) { throw new DataNotFoundException("Curve definition not found"); } // Don't need to keep the old values before the one needed by "versionAsOfInstant" final Instant oldestNeeded = value.floorKey(_sourceVersionCorrection.getVersionAsOf()); if (oldestNeeded != null) { value.headMap(oldestNeeded).clear(); } // Store a null to indicate the delete value.put(Instant.now(), null); } else { if (_definitions.remove(key) == null) { throw new DataNotFoundException("Curve definition not found"); } } changeManager() .entityChanged( ChangeType.REMOVED, objectIdentifiable.getObjectId(), null, null, Instant.now()); }
/** * @param priority The priority of the functions * @param interpolatorName The volatility surface interpolator name * @param leftExtrapolatorName The volatility surface left extrapolator name * @param rightExtrapolatorName The volatility surface right extrapolator name * @param propertyValuesByCurrencies Values for the properties per currency: an array of strings * where the <i>i<sup>th</sup></i> currency has properties: * <ul> * <li><i>i</i> = first currency name, * <li><i>i + 1</i> = first currency curve configuration name * <li><i>i + 2</i> = first currency discounting curve name * <li><i>i + 3</i> = second currency name, * <li><i>i + 4</i> = second currency curve configuration name * <li><i>i + 5</i> = second currency discounting curve name * <li><i>i + 6</i> = surface name * </ul> */ public FXOptionBlackDefaults( final String priority, final String interpolatorName, final String leftExtrapolatorName, final String rightExtrapolatorName, final String... propertyValuesByCurrencies) { super(ComputationTargetType.SECURITY, true); ArgumentChecker.notNull(priority, "priority"); ArgumentChecker.notNull(interpolatorName, "interpolator name"); ArgumentChecker.notNull(leftExtrapolatorName, "left extrapolator name"); ArgumentChecker.notNull(rightExtrapolatorName, "right extrapolator name"); ArgumentChecker.notNull(propertyValuesByCurrencies, "property values by currency"); ArgumentChecker.isTrue( propertyValuesByCurrencies.length % 7 == 0, "Must have two currencies, one curve config and discounting curve name per currency pair and one surface name"); _priority = PriorityClass.valueOf(priority); _interpolatorName = interpolatorName; _leftExtrapolatorName = leftExtrapolatorName; _rightExtrapolatorName = rightExtrapolatorName; _propertyValuesByFirstCurrency = new HashMap<String, Pair<String, String>>(); _propertyValuesBySecondCurrency = new HashMap<String, Pair<String, String>>(); _surfaceNameByCurrencyPair = new HashMap<Pair<String, String>, String>(); for (int i = 0; i < propertyValuesByCurrencies.length; i += 7) { final String firstCurrency = propertyValuesByCurrencies[i]; final Pair<String, String> firstCurrencyValues = Pair.of(propertyValuesByCurrencies[i + 1], propertyValuesByCurrencies[i + 2]); final String secondCurrency = propertyValuesByCurrencies[i + 3]; ArgumentChecker.isFalse( firstCurrency.equals(secondCurrency), "The two currencies must not be equal; have {} and {}", firstCurrency, secondCurrency); final Pair<String, String> secondCurrencyValues = Pair.of(propertyValuesByCurrencies[i + 4], propertyValuesByCurrencies[i + 5]); final String surfaceName = propertyValuesByCurrencies[i + 6]; _propertyValuesByFirstCurrency.put(firstCurrency, firstCurrencyValues); _propertyValuesBySecondCurrency.put(secondCurrency, secondCurrencyValues); _surfaceNameByCurrencyPair.put(Pair.of(firstCurrency, secondCurrency), surfaceName); } }
@Override public List<UniqueId> replaceAllVersions( ObjectIdentifiable objectIdentifiable, List<YieldCurveDefinitionDocument> replacementDocuments) { ArgumentChecker.notNull(replacementDocuments, "replacementDocuments"); ArgumentChecker.notNull(objectIdentifiable, "objectIdentifiable"); final Instant now = Instant.now(); for (YieldCurveDefinitionDocument replacementDocument : replacementDocuments) { ArgumentChecker.notNull(replacementDocument, "document"); ArgumentChecker.notNull( replacementDocument.getYieldCurveDefinition(), "document.yieldCurveDefinition"); final Currency currency = replacementDocument.getYieldCurveDefinition().getCurrency(); final String name = replacementDocument.getYieldCurveDefinition().getName(); final UniqueId id = UniqueId.of(getUniqueIdScheme(), name + "_" + currency.getCode()); ArgumentChecker.isTrue(id.equals(objectIdentifiable), "Invalid object identifier"); } YieldCurveDefinitionDocument storedDocument = get(objectIdentifiable, null); if (storedDocument == null) { throw new DataNotFoundException("Document not found: " + objectIdentifiable); } final Currency currency = storedDocument.getYieldCurveDefinition().getCurrency(); final String name = storedDocument.getYieldCurveDefinition().getName(); Pair<Currency, String> key = Pair.of(currency, name); final TreeMap<Instant, YieldCurveDefinition> value = _definitions.get(key); if (value == null) { throw new DataNotFoundException("OID '" + objectIdentifiable + "' not found"); } value.clear(); List<YieldCurveDefinitionDocument> orderedReplacementDocuments = MasterUtils.adjustVersionInstants(now, null, null, replacementDocuments); final Instant lowestVersionFrom = orderedReplacementDocuments.get(0).getVersionFromInstant(); ArgumentChecker.notNull( lowestVersionFrom, "You must define version from of the first document"); for (YieldCurveDefinitionDocument replacementDocument : orderedReplacementDocuments) { value.put( replacementDocument.getVersionFromInstant(), replacementDocument.getYieldCurveDefinition()); changeManager() .entityChanged(ChangeType.CHANGED, replacementDocument.getObjectId(), null, null, now); } return MasterUtils.mapToUniqueIDs(orderedReplacementDocuments); }
@Override public ObjectsPair<Collection<LiveDataSpecification>, Collection<LiveDataSpecification>> splitShouldFake( FakeSubscriptionBloombergLiveDataServer server, Collection<LiveDataSpecification> specs) { if (specs.isEmpty()) { return Pair.of( (Collection<LiveDataSpecification>) new ArrayList<LiveDataSpecification>(), (Collection<LiveDataSpecification>) new ArrayList<LiveDataSpecification>()); } Set<LiveDataSpecification> fakes = new HashSet<LiveDataSpecification>(); Set<LiveDataSpecification> underlyings = new HashSet<LiveDataSpecification>(); for (LiveDataSpecification liveDataSpecification : specs) { if (shouldFake(liveDataSpecification)) { fakes.add(liveDataSpecification); } else { underlyings.add(liveDataSpecification); } } return Pair.of( (Collection<LiveDataSpecification>) underlyings, (Collection<LiveDataSpecification>) fakes); }
@Override public ComputedValue getComputedValue(final ValueRequirement requirement) { final Pair<String, Object> key = Pair.of( requirement.getValueName(), targetSpecKey(_resolver.getTargetSpecification(requirement.getTargetReference()))); final ComputedValue[] values = _valuesByRequirement.get(key); if (values != null) { for (final ComputedValue value : values) { // Shortcut to check the properties as we already know the name and target match if (requirement.getConstraints().isSatisfiedBy(value.getSpecification().getProperties())) { return value; } } } return null; }
@Override public YieldCurveDefinition getDefinition( final Currency currency, final String name, final VersionCorrection versionCorrection) { ArgumentChecker.notNull(currency, "currency"); ArgumentChecker.notNull(name, "name"); final TreeMap<Instant, YieldCurveDefinition> definitions = _definitions.get(Pair.of(currency, name)); if (definitions == null) { return null; } final Map.Entry<Instant, YieldCurveDefinition> entry = definitions.floorEntry(versionCorrection.getVersionAsOf()); if (entry == null) { return null; } return entry.getValue(); }
@Override public ViewCalculationResultModel buildObject(FudgeDeserializer deserializer, FudgeMsg message) { final Map<ComputationTargetSpecification, Map<Pair<String, ValueProperties>, ComputedValue>> mapNames = new HashMap< ComputationTargetSpecification, Map<Pair<String, ValueProperties>, ComputedValue>>(); for (FudgeField field : message) { final ComputedValue value = deserializer.fieldValueToObject(ComputedValue.class, field); final ComputationTargetSpecification target = value.getSpecification().getTargetSpecification(); if (!mapNames.containsKey(target)) { mapNames.put(target, new HashMap<Pair<String, ValueProperties>, ComputedValue>()); } mapNames .get(target) .put( Pair.of( value.getSpecification().getValueName(), value.getSpecification().getProperties()), value); } return new ViewCalculationResultModel() { @Override public Collection<ComputationTargetSpecification> getAllTargets() { return mapNames.keySet(); } @Override public Map<Pair<String, ValueProperties>, ComputedValue> getValues( ComputationTargetSpecification target) { return mapNames.get(target); } @Override public Collection<ComputedValue> getAllValues(ComputationTargetSpecification target) { Map<Pair<String, ValueProperties>, ComputedValue> targetValuesMap = mapNames.get(target); return targetValuesMap != null ? Collections.unmodifiableCollection(targetValuesMap.values()) : null; } }; }
// ------------------------------------------------------------------------- @Override public synchronized YieldCurveDefinition getDefinition(Currency currency, String name) { ArgumentChecker.notNull(currency, "currency"); ArgumentChecker.notNull(name, "name"); final TreeMap<Instant, YieldCurveDefinition> definitions = _definitions.get(Pair.of(currency, name)); if (definitions == null) { return null; } final Map.Entry<Instant, YieldCurveDefinition> entry; if (_sourceVersionCorrection.getVersionAsOf() == null) { entry = definitions.lastEntry(); } else { entry = definitions.floorEntry(_sourceVersionCorrection.getVersionAsOf()); } if (entry == null) { return null; } return entry.getValue(); }
@Override public CompiledFunctionRepository compile( final FunctionRepository repository, final FunctionCompilationContext context, final ExecutorService executor, final InstantProvider atInstantProvider) { clearInvalidCache(context.getFunctionInitId()); final Instant atInstant = Instant.of(atInstantProvider); final Pair<FunctionRepository, Instant> key = Pair.of(repository, atInstant); // Try a previous compilation final InMemoryCompiledFunctionRepository previous = getPreviousCompilation(key); if (previous != null) { if (previous.getLatestInvocationTime() == null) { return previous; } else { if (!atInstant.isAfter(previous.getLatestInvocationTime())) { return previous; } } } // Try a future compilation final InMemoryCompiledFunctionRepository next = getNextCompilation(key); if (next != null) { if (next.getEarliestInvocationTime() == null) { return next; } else { if (!atInstant.isBefore(next.getEarliestInvocationTime())) { return next; } } } // Try the exact timestamp InMemoryCompiledFunctionRepository compiled = getCachedCompilation(key); if (compiled != null) { return compiled; } // Create a compilation, salvaging results from previous and next if possible compiled = compile(context, repository, atInstant, previous, next, executor); cacheCompilation(key, compiled); return compiled; }
private void addValue(final ComputedValue value) { ArgumentChecker.notNull(value, "Computed Value"); if (value.getValue() instanceof ComputedValue) { throw new IllegalArgumentException("Double-nested value"); } _values.add(value); _valuesByRequirementName.put(value.getSpecification().getValueName(), value); final Pair<String, Object> key = Pair.of( value.getSpecification().getValueName(), targetSpecKey(value.getSpecification().getTargetSpecification())); final ComputedValue[] prev = _valuesByRequirement.get(key); if (prev == null) { _valuesByRequirement.put(key, new ComputedValue[] {value}); } else { final ComputedValue[] values = new ComputedValue[prev.length + 1]; System.arraycopy(prev, 0, values, 0, prev.length); values[prev.length] = value; _valuesByRequirement.put(key, values); } }
protected FXOptionSecurity createFXOptionSecurity(final Bundle bundle) { final Currency putCurrency = bundle._firstCurrency; final Currency callCurrency = bundle._secondCurrency; final double putAmount = bundle._firstCurrency.equals(Currency.JPY) ? NOTIONAL * 100 : NOTIONAL; final ZonedDateTime settlementDate = bundle._tradeDate.plusDays(bundle._daysOffset); final Double fxRate = getApproxFXRate( settlementDate.toLocalDate(), Pair.of(bundle._firstCurrency, bundle._secondCurrency)); if (fxRate == null) { return null; } final double callAmount = NOTIONAL * fxRate; final Expiry expiry = new Expiry(settlementDate, ExpiryAccuracy.DAY_MONTH_YEAR); final String dateString = settlementDate.toString(DATE_FORMATTER); final FXOptionSecurity fxOptionSecurity = new FXOptionSecurity( putCurrency, callCurrency, putAmount, callAmount, expiry, settlementDate, bundle._long, new EuropeanExerciseType()); final String callAmountString = NOTIONAL_FORMATTER.format(callAmount); final String putAmountString = NOTIONAL_FORMATTER.format(putAmount); fxOptionSecurity.setName( (bundle._long ? "Long " : "Short ") + "put " + putCurrency + " " + putAmountString + ", call " + callCurrency + " " + callAmountString + " on " + dateString); return fxOptionSecurity; }
@Override public synchronized YieldCurveDefinitionDocument addOrUpdate( YieldCurveDefinitionDocument document) { ArgumentChecker.notNull(document, "document"); ArgumentChecker.notNull(document.getYieldCurveDefinition(), "document.yieldCurveDefinition"); final Currency currency = document.getYieldCurveDefinition().getCurrency(); final String name = document.getYieldCurveDefinition().getName(); final Pair<Currency, String> key = Pair.of(currency, name); TreeMap<Instant, YieldCurveDefinition> value = _definitions.get(key); final UniqueId uid = UniqueId.of(getUniqueIdScheme(), name + "_" + currency.getCode()); Instant now = Instant.now(); if (value != null) { if (_sourceVersionCorrection.getVersionAsOf() != null) { // Don't need to keep the old values before the one needed by "versionAsOfInstant" final Instant oldestNeeded = value.floorKey(_sourceVersionCorrection.getVersionAsOf()); if (oldestNeeded != null) { value.headMap(oldestNeeded).clear(); } } else { // Don't need any old values value.clear(); } value.put(now, document.getYieldCurveDefinition()); changeManager().entityChanged(ChangeType.CHANGED, uid.getObjectId(), null, null, now); } else { value = new TreeMap<Instant, YieldCurveDefinition>(); value.put(now, document.getYieldCurveDefinition()); _definitions.put(key, value); changeManager() .entityChanged( ChangeType.ADDED, uid.getObjectId(), document.getVersionFromInstant(), document.getVersionToInstant(), now); } document.setUniqueId(uid); return document; }
@Override public synchronized YieldCurveDefinitionDocument get(UniqueId uid) { ArgumentChecker.notNull(uid, "objectIdentifiable"); if (!uid.isLatest()) { throw new IllegalArgumentException( "Only latest version supported by '" + getUniqueIdScheme() + "'"); } if (!getUniqueIdScheme().equals(uid.getScheme())) { throw new DataNotFoundException( "Scheme '" + uid.getScheme() + "' not valid for '" + getUniqueIdScheme() + "'"); } final int i = uid.getValue().indexOf('_'); if (i <= 0) { throw new DataNotFoundException( "Identifier '" + uid.getValue() + "' not valid for '" + getUniqueIdScheme() + "'"); } final String name = uid.getValue().substring(0, i); final String iso = uid.getValue().substring(i + 1); final Currency currency; try { currency = Currency.of(iso); } catch (IllegalArgumentException e) { throw new DataNotFoundException( "Identifier '" + uid.getValue() + "' not valid for '" + getUniqueIdScheme() + "'", e); } final TreeMap<Instant, YieldCurveDefinition> definitions = _definitions.get(Pair.of(currency, name)); if (definitions == null) { throw new DataNotFoundException("Curve definition not found"); } final YieldCurveDefinition definition = definitions.lastEntry().getValue(); if (definition == null) { throw new DataNotFoundException("Curve definition not found"); } return new YieldCurveDefinitionDocument(uid, definition); }
@Override protected Set<String> getDefaultValue( final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredValue, final String propertyName) { final FinancialSecurity security = (FinancialSecurity) target.getSecurity(); final String putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor()).getCode(); final String callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor()).getCode(); if (!(_propertyValuesByFirstCurrency.containsKey(putCurrency) || _propertyValuesBySecondCurrency.containsKey(putCurrency))) { s_logger.error( "Could not get config for put currency " + putCurrency + "; should never happen"); return null; } if (!(_propertyValuesByFirstCurrency.containsKey(callCurrency) || _propertyValuesBySecondCurrency.containsKey(callCurrency))) { s_logger.error( "Could not get config for call currency " + callCurrency + "; should never happen"); return null; } final String putCurveConfig, callCurveConfig, putCurve, callCurve; if (_propertyValuesByFirstCurrency.containsKey(putCurrency)) { final Pair<String, String> firstCurrencyValues = _propertyValuesByFirstCurrency.get(putCurrency); putCurveConfig = firstCurrencyValues.getFirst(); putCurve = firstCurrencyValues.getSecond(); final Pair<String, String> secondCurrencyValues = _propertyValuesBySecondCurrency.get(callCurrency); callCurveConfig = secondCurrencyValues.getFirst(); callCurve = secondCurrencyValues.getSecond(); } else { final Pair<String, String> firstCurrencyValues = _propertyValuesByFirstCurrency.get(callCurrency); callCurveConfig = firstCurrencyValues.getFirst(); callCurve = firstCurrencyValues.getSecond(); final Pair<String, String> secondCurrencyValues = _propertyValuesBySecondCurrency.get(putCurrency); putCurveConfig = secondCurrencyValues.getFirst(); putCurve = secondCurrencyValues.getSecond(); } if (FXOptionBlackFunction.PUT_CURVE_CALC_CONFIG.equals(propertyName)) { return Collections.singleton(putCurveConfig); } if (FXOptionBlackFunction.PUT_CURVE.equals(propertyName)) { return Collections.singleton(putCurve); } if (FXOptionBlackFunction.CALL_CURVE_CALC_CONFIG.equals(propertyName)) { return Collections.singleton(callCurveConfig); } if (FXOptionBlackFunction.CALL_CURVE.equals(propertyName)) { return Collections.singleton(callCurve); } if (InterpolatedDataProperties.X_INTERPOLATOR_NAME.equals(propertyName)) { return Collections.singleton(_interpolatorName); } if (InterpolatedDataProperties.LEFT_X_EXTRAPOLATOR_NAME.equals(propertyName)) { return Collections.singleton(_leftExtrapolatorName); } if (InterpolatedDataProperties.RIGHT_X_EXTRAPOLATOR_NAME.equals(propertyName)) { return Collections.singleton(_rightExtrapolatorName); } if (ValuePropertyNames.SURFACE.equals(propertyName)) { Pair<String, String> pair = Pair.of(putCurrency, callCurrency); if (_surfaceNameByCurrencyPair.containsKey(pair)) { return Collections.singleton(_surfaceNameByCurrencyPair.get(pair)); } pair = Pair.of(callCurrency, putCurrency); if (_surfaceNameByCurrencyPair.containsKey(pair)) { return Collections.singleton(_surfaceNameByCurrencyPair.get(pair)); } } return null; }
@Override public Set<ComputedValue> execute( final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target, final Set<ValueRequirement> desiredValues) { final Clock snapshotClock = executionContext.getValuationClock(); final ZonedDateTime now = snapshotClock.zonedDateTime(); final FinancialSecurity security = (FinancialSecurity) target.getSecurity(); final InstrumentDefinition<InstrumentDerivative> definition = (InstrumentDefinition<InstrumentDerivative>) security.accept(VISITOR); final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor()); final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor()); final ValueRequirement desiredValue = desiredValues.iterator().next(); final String putCurveName = desiredValue.getConstraint(PROPERTY_PUT_CURVE); final String callCurveName = desiredValue.getConstraint(PROPERTY_CALL_CURVE); final String surfaceName = desiredValue.getConstraint(ValuePropertyNames.SURFACE); final String putForwardCurveName = desiredValue.getConstraint(PROPERTY_PUT_FORWARD_CURVE); final String callForwardCurveName = desiredValue.getConstraint(PROPERTY_CALL_FORWARD_CURVE); final String putCurveCalculationMethod = desiredValue.getConstraint(PROPERTY_PUT_CURVE_CALCULATION_METHOD); final String callCurveCalculationMethod = desiredValue.getConstraint(PROPERTY_CALL_CURVE_CALCULATION_METHOD); final String interpolatorName = desiredValue.getConstraint(InterpolatedDataProperties.X_INTERPOLATOR_NAME); final String leftExtrapolatorName = desiredValue.getConstraint(InterpolatedDataProperties.LEFT_X_EXTRAPOLATOR_NAME); final String rightExtrapolatorName = desiredValue.getConstraint(InterpolatedDataProperties.RIGHT_X_EXTRAPOLATOR_NAME); final String spread = desiredValue.getConstraint(PROPERTY_CALL_SPREAD_VALUE); final double spreadValue = Double.parseDouble(spread); final String fullPutCurveName = putCurveName + "_" + putCurrency.getCode(); final String fullCallCurveName = callCurveName + "_" + callCurrency.getCode(); final String[] curveNames; if (FXUtils.isInBaseQuoteOrder( putCurrency, callCurrency)) { // To get Base/quote in market standard order. curveNames = new String[] {fullPutCurveName, fullCallCurveName}; } else { curveNames = new String[] {fullCallCurveName, fullPutCurveName}; } final YieldAndDiscountCurve putFundingCurve = getCurve(inputs, putCurrency, putCurveName); final YieldAndDiscountCurve callFundingCurve = getCurve(inputs, callCurrency, callCurveName); final YieldAndDiscountCurve[] curves; final Map<String, Currency> curveCurrency = new HashMap<String, Currency>(); curveCurrency.put(fullPutCurveName, putCurrency); curveCurrency.put(fullCallCurveName, callCurrency); final String[] allCurveNames; final Currency ccy1; final Currency ccy2; if (FXUtils.isInBaseQuoteOrder( putCurrency, callCurrency)) { // To get Base/quote in market standard order. ccy1 = putCurrency; ccy2 = callCurrency; curves = new YieldAndDiscountCurve[] {putFundingCurve, callFundingCurve}; allCurveNames = new String[] {fullPutCurveName, fullCallCurveName}; } else { curves = new YieldAndDiscountCurve[] {callFundingCurve, putFundingCurve}; allCurveNames = new String[] {fullCallCurveName, fullPutCurveName}; ccy1 = callCurrency; ccy2 = putCurrency; } final InstrumentDerivative fxOption = definition.toDerivative(now, curveNames); final YieldCurveBundle yieldCurves = new YieldCurveBundle(allCurveNames, curves); final Object spotObject = inputs.getValue(ValueRequirementNames.SPOT_RATE); if (spotObject == null) { throw new OpenGammaRuntimeException("Could not get spot rate"); } final double spot = (Double) spotObject; final ValueRequirement fxVolatilitySurfaceRequirement = getSurfaceRequirement( surfaceName, putCurrency, callCurrency, interpolatorName, leftExtrapolatorName, rightExtrapolatorName); final Object volatilitySurfaceObject = inputs.getValue(fxVolatilitySurfaceRequirement); if (volatilitySurfaceObject == null) { throw new OpenGammaRuntimeException("Could not get " + fxVolatilitySurfaceRequirement); } final SmileDeltaTermStructureParametersStrikeInterpolation smiles = (SmileDeltaTermStructureParametersStrikeInterpolation) volatilitySurfaceObject; final FXMatrix fxMatrix = new FXMatrix(ccy1, ccy2, spot); final ValueProperties.Builder properties = getResultProperties( putCurveName, putForwardCurveName, putCurveCalculationMethod, callCurveName, callForwardCurveName, callCurveCalculationMethod, surfaceName, spread, interpolatorName, leftExtrapolatorName, rightExtrapolatorName, target); final ValueSpecification spec = new ValueSpecification(_valueRequirementName, target.toSpecification(), properties.get()); final YieldCurveBundle curvesWithFX = new YieldCurveBundle(fxMatrix, curveCurrency, yieldCurves.getCurvesMap()); final SmileDeltaTermStructureDataBundle smileBundle = new SmileDeltaTermStructureDataBundle(curvesWithFX, smiles, Pair.of(ccy1, ccy2)); return getResult(fxOption, spreadValue, smileBundle, spec); }
private void addNodes( final ManageablePortfolioNode rootNode, final String underlying, final boolean includeUnderlying, final Period[] expiries) { final ExternalId ticker = ExternalSchemes.bloombergTickerSecurityId(underlying); ManageableSecurity underlyingSecurity = null; if (includeUnderlying) { underlyingSecurity = getOrLoadEquity(ticker); } final ExternalIdBundle bundle = underlyingSecurity == null ? ExternalIdBundle.of(ticker) : underlyingSecurity.getExternalIdBundle(); final HistoricalTimeSeriesInfoDocument timeSeriesInfo = getOrLoadTimeSeries(ticker, bundle); final double estimatedCurrentStrike = getOrLoadMostRecentPoint(timeSeriesInfo); final Set<ExternalId> optionChain = getOptionChain(ticker); // TODO: reuse positions/nodes? final String longName = underlyingSecurity == null ? "" : underlyingSecurity.getName(); final String formattedName = MessageFormatter.format("[{}] {}", underlying, longName).getMessage(); final ManageablePortfolioNode equityNode = new ManageablePortfolioNode(formattedName); final BigDecimal underlyingAmount = VALUE_OF_UNDERLYING.divide( BigDecimal.valueOf(estimatedCurrentStrike), BigDecimal.ROUND_HALF_EVEN); if (includeUnderlying) { addPosition(equityNode, underlyingAmount, ticker); } final TreeMap<LocalDate, Set<BloombergTickerParserEQOption>> optionsByExpiry = new TreeMap<LocalDate, Set<BloombergTickerParserEQOption>>(); for (final ExternalId optionTicker : optionChain) { s_logger.debug("Got option {}", optionTicker); final BloombergTickerParserEQOption optionInfo = BloombergTickerParserEQOption.getOptionParser(optionTicker); s_logger.debug("Got option info {}", optionInfo); final LocalDate key = optionInfo.getExpiry(); Set<BloombergTickerParserEQOption> set = optionsByExpiry.get(key); if (set == null) { set = new HashSet<BloombergTickerParserEQOption>(); optionsByExpiry.put(key, set); } set.add(optionInfo); } final Set<ExternalId> tickersToLoad = new HashSet<ExternalId>(); final BigDecimal expiryCount = BigDecimal.valueOf(expiries.length); final BigDecimal defaultAmountAtExpiry = underlyingAmount.divide(expiryCount, BigDecimal.ROUND_DOWN); final BigDecimal spareAmountAtExpiry = defaultAmountAtExpiry.add(BigDecimal.ONE); int spareCount = underlyingAmount.subtract(defaultAmountAtExpiry.multiply(expiryCount)).intValue(); for (final Period bucketPeriod : expiries) { final ManageablePortfolioNode bucketNode = new ManageablePortfolioNode(bucketPeriod.toString().substring(1)); final LocalDate nowish = LocalDate.now() .withDayOfMonth( 20); // This avoids us picking different options every time this script is run final LocalDate targetExpiry = nowish.plus(bucketPeriod); final LocalDate chosenExpiry = optionsByExpiry.floorKey(targetExpiry); if (chosenExpiry == null) { s_logger.info("No options for {} on {}", targetExpiry, underlying); continue; } s_logger.info( "Using time {} for bucket {} ({})", new Object[] {chosenExpiry, bucketPeriod, targetExpiry}); final Set<BloombergTickerParserEQOption> optionsAtExpiry = optionsByExpiry.get(chosenExpiry); final TreeMap<Double, Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption>> optionsByStrike = new TreeMap<>(); for (final BloombergTickerParserEQOption option : optionsAtExpiry) { // s_logger.info("option {}", option); final double key = option.getStrike(); Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption> pair = optionsByStrike.get(key); if (pair == null) { pair = Pair.of(null, null); } if (option.getOptionType() == OptionType.CALL) { pair = Pair.of(option, pair.getSecond()); } else { pair = Pair.of(pair.getFirst(), option); } optionsByStrike.put(key, pair); } // cascading collar? final BigDecimal amountAtExpiry = spareCount-- > 0 ? spareAmountAtExpiry : defaultAmountAtExpiry; s_logger.info(" est strike {}", estimatedCurrentStrike); final Double[] strikes = optionsByStrike.keySet().toArray(new Double[0]); int strikeIndex = Arrays.binarySearch(strikes, estimatedCurrentStrike); if (strikeIndex < 0) { strikeIndex = -(1 + strikeIndex); } s_logger.info( "strikes length {} index {} strike of index {}", new Object[] { Integer.valueOf(strikes.length), Integer.valueOf(strikeIndex), Double.valueOf(strikes[strikeIndex]) }); int minIndex = strikeIndex - _numOptions; minIndex = Math.max(0, minIndex); int maxIndex = strikeIndex + _numOptions; maxIndex = Math.min(strikes.length - 1, maxIndex); s_logger.info("min {} max {}", Integer.valueOf(minIndex), Integer.valueOf(maxIndex)); final StringBuffer sb = new StringBuffer("strikes: ["); for (int j = minIndex; j <= maxIndex; j++) { sb.append(" "); sb.append(strikes[j]); } sb.append(" ]"); s_logger.info(sb.toString()); // Short Calls final ArrayList<Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption>> calls = new ArrayList<Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption>>(); for (int j = minIndex; j < strikeIndex; j++) { final Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption> pair = optionsByStrike.get(strikes[j]); if (pair == null) { throw new OpenGammaRuntimeException("no pair for strike" + strikes[j]); } calls.add(pair); } spreadOptions( bucketNode, calls, OptionType.CALL, -1, tickersToLoad, amountAtExpiry, includeUnderlying, calls.size()); // Long Puts final ArrayList<Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption>> puts = new ArrayList<Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption>>(); for (int j = strikeIndex + 1; j <= maxIndex; j++) { final Pair<BloombergTickerParserEQOption, BloombergTickerParserEQOption> pair = optionsByStrike.get(strikes[j]); if (pair == null) { throw new OpenGammaRuntimeException("no pair for strike" + strikes[j]); } puts.add(pair); } spreadOptions( bucketNode, puts, OptionType.PUT, 1, tickersToLoad, amountAtExpiry, includeUnderlying, puts.size()); if (bucketNode.getChildNodes().size() + bucketNode.getPositionIds().size() > 0) { equityNode.addChildNode(bucketNode); // Avoid generating empty nodes } } for (final ExternalId optionTicker : tickersToLoad) { final ManageableSecurity loaded = getOrLoadSecurity(optionTicker); if (loaded == null) { throw new OpenGammaRuntimeException("Unexpected option type " + loaded); } // TODO [LAPANA-29] Should be able to do this for index options too if (includeUnderlying) { try { final HistoricalTimeSeriesInfoDocument loadedTs = getOrLoadTimeSeries(optionTicker, loaded.getExternalIdBundle()); if (loadedTs == null) { throw new OpenGammaRuntimeException("Failed to get time series for " + loaded); } } catch (final Exception ex) { s_logger.info("Failed to get time series for " + loaded, ex); } } } if (equityNode.getPositionIds().size() + equityNode.getChildNodes().size() > 0) { rootNode.addChildNode(equityNode); } }