class BloombergEQVanillaOptionChain {

  public BloombergEQVanillaOptionChain narrowByStrike(final double referencePrice, int strikeOffset) {
    // Create parser version of chain
    // Collect all unique property values from chain
    List<BloombergTickerParserEQVanillaOption> parsers = new ArrayList<BloombergTickerParserEQVanillaOption>(_identifiers.size());
    NavigableSet<Double> strikes = new TreeSet<Double>();
    for (ExternalId identifier : _identifiers) {
      BloombergTickerParserEQVanillaOption parser = new BloombergTickerParserEQVanillaOption(identifier);
      parsers.add(parser);
      Double strike = parser.getStrike();
      strikes.add(strike);      
    }
    
    // Find the desired strike
    Double targetValue = null;
    
    // Special case:  offset is 0 to begin with, just find the nearest strike
    if (strikeOffset == 0) {
      double floorValue = Objects.firstNonNull(strikes.floor(referencePrice), strikes.first());
      targetValue = floorValue;
      if (floorValue != referencePrice) {
        double ceilingValue = Objects.firstNonNull(strikes.ceiling(referencePrice), strikes.last());
        double diff1 = Math.abs(referencePrice - floorValue);
        double diff2 = Math.abs(referencePrice - ceilingValue);
        if (diff1 < diff2) {
          targetValue = floorValue;
        } else {
          targetValue = ceilingValue;
        } 
      }
    } else {
      // Otherwise, move forward or backward the desired number of offsets and take that value
      targetValue = referencePrice;
      while (strikeOffset != 0) {
        Double next = null;
        if (strikeOffset > 0) {
          next = strikes.higher(targetValue);
          if (next != null) {
            targetValue = next;
            strikeOffset--;
          } else {
            break;
          }
        } else {
          next = strikes.lower(targetValue);
          if (next != null) {
            targetValue = next;
            strikeOffset++;
          } else {
            break;
          }
        }
      }
    }
    
    // Collect all identifiers with this strike
    // (Note: tried pre-hashing and retrieving, was slower than this O(n) approach)
    List<ExternalId> identifiers = new ArrayList<ExternalId>();
    for (BloombergTickerParserEQVanillaOption parser : parsers) {
      if (parser.getStrike() == targetValue) {
        identifiers.add(parser.getIdentifier());
      }
    }
    
    // Done
    return new BloombergEQVanillaOptionChain(identifiers);
  }

  public  BloombergEQVanillaOptionChain(Set<ExternalId> identifiers);
  public  BloombergEQVanillaOptionChain(List<ExternalId> identifiers);
  public  BloombergEQVanillaOptionChain(BloombergEQVanillaOptionChain original);

}