com.opengamma.financial.analytics.model.credit.isdanew.ISDACompliantCDSFunction.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.financial.analytics.model.credit.isdanew.ISDACompliantCDSFunction.java

Source

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

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.lang.ArrayUtils;
import org.threeten.bp.Period;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZonedDateTime;

import com.google.common.collect.Sets;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.analytics.financial.credit.BuySellProtection;
import com.opengamma.analytics.financial.credit.creditdefaultswap.StandardCDSQuotingConvention;
import com.opengamma.analytics.financial.credit.creditdefaultswap.pricing.vanilla.isdanew.AnalyticCDSPricer;
import com.opengamma.analytics.financial.credit.creditdefaultswap.pricing.vanilla.isdanew.CDSAnalytic;
import com.opengamma.analytics.financial.credit.creditdefaultswap.pricing.vanilla.isdanew.CDSQuoteConvention;
import com.opengamma.analytics.financial.credit.creditdefaultswap.pricing.vanilla.isdanew.ISDACompliantCreditCurve;
import com.opengamma.analytics.financial.credit.creditdefaultswap.pricing.vanilla.isdanew.ISDACompliantYieldCurve;
import com.opengamma.analytics.financial.credit.creditdefaultswap.pricing.vanilla.isdanew.ParSpread;
import com.opengamma.analytics.financial.credit.creditdefaultswap.pricing.vanilla.isdanew.PointsUpFront;
import com.opengamma.analytics.financial.credit.creditdefaultswap.pricing.vanilla.isdanew.PointsUpFrontConverter;
import com.opengamma.analytics.financial.credit.creditdefaultswap.pricing.vanilla.isdanew.QuotedSpread;
import com.opengamma.analytics.financial.credit.creditdefaultswap.pricing.vanilla.isdanew.SpreadSensitivityCalculator;
import com.opengamma.analytics.financial.model.BumpType;
import com.opengamma.analytics.math.curve.NodalTenorDoubleCurve;
import com.opengamma.core.AbstractSourceWithExternalBundle;
import com.opengamma.core.change.ChangeManager;
import com.opengamma.core.change.DummyChangeManager;
import com.opengamma.core.holiday.HolidaySource;
import com.opengamma.core.holiday.impl.WeekendHolidaySource;
import com.opengamma.core.region.Region;
import com.opengamma.core.region.RegionSource;
import com.opengamma.core.value.MarketDataRequirementNames;
import com.opengamma.engine.ComputationTarget;
import com.opengamma.engine.function.AbstractFunction.NonCompiledInvoker;
import com.opengamma.engine.function.FunctionCompilationContext;
import com.opengamma.engine.function.FunctionExecutionContext;
import com.opengamma.engine.function.FunctionInputs;
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.TenorLabelledMatrix1D;
import com.opengamma.financial.analytics.model.cds.ISDAFunctionConstants;
import com.opengamma.financial.analytics.model.credit.CreditSecurityToRecoveryRateVisitor;
import com.opengamma.financial.analytics.model.credit.SpreadCurveFunctions;
import com.opengamma.financial.credit.CdsRecoveryRateIdentifier;
import com.opengamma.financial.security.FinancialSecurityTypes;
import com.opengamma.financial.security.cds.CreditDefaultSwapSecurity;
import com.opengamma.financial.security.cds.LegacyVanillaCDSSecurity;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.id.ObjectId;
import com.opengamma.id.UniqueId;
import com.opengamma.id.VersionCorrection;
import com.opengamma.master.region.ManageableRegion;
import com.opengamma.util.async.AsynchronousExecution;
import com.opengamma.util.credit.CreditCurveIdentifier;
import com.opengamma.util.i18n.Country;
import com.opengamma.util.money.Currency;
import com.opengamma.util.time.Tenor;

//TODO Check bucketed cs01 in desired outputs before calcing as expensive

/**
 * Abstract class for cds functions that require ISDA and spread curves.
 */
public class ISDACompliantCDSFunction extends NonCompiledInvoker {

    private final String[] _valueRequirements = new String[] { ValueRequirementNames.ACCRUED_DAYS,
            ValueRequirementNames.ACCRUED_PREMIUM, ValueRequirementNames.POINTS_UPFRONT,
            ValueRequirementNames.CLEAN_PRESENT_VALUE, ValueRequirementNames.DIRTY_PRESENT_VALUE,
            ValueRequirementNames.CLEAN_PRICE, ValueRequirementNames.QUOTED_SPREAD,
            ValueRequirementNames.UPFRONT_AMOUNT, ValueRequirementNames.BUCKETED_CS01,
            ValueRequirementNames.PARALLEL_CS01, ValueRequirementNames.PRINCIPAL };
    public static double ONE_BPS = 1e-4; // fractional 1 BPS
    private HolidaySource _holidaySource; //OpenGammaCompilationContext.getHolidaySource(context);
    private RegionSource _regionSource;
    private static final PointsUpFrontConverter POINTS_UP_FRONT_CONVERTER = new PointsUpFrontConverter();
    protected static final AnalyticCDSPricer PRICER = new AnalyticCDSPricer();
    public static final SpreadSensitivityCalculator CALCULATOR = new SpreadSensitivityCalculator();

    @Override
    public void init(final FunctionCompilationContext context) {
        // using hardcoded region and calendar for now
        _holidaySource = new WeekendHolidaySource(); //OpenGammaCompilationContext.getHolidaySource(context);
        _regionSource = new TestRegionSource(getTestRegion()); //OpenGammaCompilationContext.getRegionSource(context);
        //_converter = new CreditDefaultSwapSecurityConverterDeprecated(holidaySource, regionSource);
    }

    @Override
    public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs,
            final ComputationTarget target, final Set<ValueRequirement> desiredValues)
            throws AsynchronousExecution {
        final ZonedDateTime now = ZonedDateTime.now(executionContext.getValuationClock());
        final ValueRequirement requirement = desiredValues.iterator().next();
        final ValueProperties properties = requirement.getConstraints().copy().get();

        final LegacyVanillaCDSSecurity security = (LegacyVanillaCDSSecurity) target.getSecurity();
        //LegacyVanillaCreditDefaultSwapDefinition cds = _converter.visitLegacyVanillaCDSSecurity(security);
        final ValueRequirement desiredValue = desiredValues.iterator().next(); // all same constraints

        final String quoteConventionString = desiredValue.getConstraint(ISDAFunctionConstants.CDS_QUOTE_CONVENTION);
        final StandardCDSQuotingConvention quoteConvention = StandardCDSQuotingConvention
                .parse(quoteConventionString);

        final CdsRecoveryRateIdentifier recoveryRateIdentifier = security
                .accept(new CreditSecurityToRecoveryRateVisitor(executionContext.getSecuritySource()));
        Object recoveryRateObject = inputs.getValue(new ValueRequirement("PX_LAST", ComputationTargetType.PRIMITIVE,
                recoveryRateIdentifier.getExternalId()));
        if (recoveryRateObject == null) {
            throw new OpenGammaRuntimeException("Could not get recovery rate");
            //s_logger.warn("Could not get recovery rate, defaulting to 0.4: " + recoveryRateIdentifier);
            //recoveryRateObject = 0.4;
        }
        final double recoveryRate = (Double) recoveryRateObject;

        // get the isda curve
        final Object isdaObject = inputs.getValue(ValueRequirementNames.YIELD_CURVE);
        if (isdaObject == null) {
            throw new OpenGammaRuntimeException("Couldn't get isda curve");
        }
        final ISDACompliantYieldCurve yieldCurve = (ISDACompliantYieldCurve) isdaObject;

        // spreads
        NodalTenorDoubleCurve spreadObject = (NodalTenorDoubleCurve) inputs
                .getValue(ValueRequirementNames.BUCKETED_SPREADS);
        if (spreadObject == null) {
            throw new OpenGammaRuntimeException("Unable to get spreads");
        }
        final double[] spreads = ArrayUtils.toPrimitive(spreadObject.getYData());
        //final String pillarString = IMMDateGenerator.isIMMDate(security.getMaturityDate()) ? requirement.getConstraint(ISDAFunctionConstants.ISDA_BUCKET_TENORS) : ISDACompliantCreditCurveFunction.NON_IMM_PILLAR_TENORS;
        final ZonedDateTime[] bucketDates = SpreadCurveFunctions.getPillarDates(now, spreadObject.getXData());
        final CDSQuoteConvention[] quotes = SpreadCurveFunctions.getQuotes(security.getMaturityDate(), spreads,
                security.getParSpread(), quoteConvention, false);

        // spreads
        NodalTenorDoubleCurve pillarObject = (NodalTenorDoubleCurve) inputs
                .getValue(ValueRequirementNames.PILLAR_SPREADS);
        if (pillarObject == null) {
            throw new OpenGammaRuntimeException("Unable to get pillars");
        }

        // CDS analytics for credit curve (possible performance improvement if earlier result obtained)
        //final LegacyVanillaCreditDefaultSwapDefinition curveCDS = cds.withStartDate(now);
        //security.setStartDate(now); // needed for curve instruments
        final CDSAnalytic[] bucketCDSs = new CDSAnalytic[bucketDates.length];
        for (int i = 0; i < bucketCDSs.length; i++) {
            //security.setMaturityDate(bucketDates[i]);
            final CDSAnalyticVisitor visitor = new CDSAnalyticVisitor(now.toLocalDate(), _holidaySource,
                    _regionSource, security.getStartDate().toLocalDate(), bucketDates[i].toLocalDate(),
                    recoveryRate);
            bucketCDSs[i] = security.accept(visitor);
        }

        final ZonedDateTime[] pillarDates = SpreadCurveFunctions.getPillarDates(now, pillarObject.getXData());
        final CDSAnalytic[] pillarCDSs = new CDSAnalytic[pillarDates.length];
        for (int i = 0; i < pillarCDSs.length; i++) {
            //security.setMaturityDate(bucketDates[i]);
            final CDSAnalyticVisitor visitor = new CDSAnalyticVisitor(now.toLocalDate(), _holidaySource,
                    _regionSource, security.getStartDate().toLocalDate(), pillarDates[i].toLocalDate(),
                    recoveryRate);
            pillarCDSs[i] = security.accept(visitor);
        }

        final ISDACompliantCreditCurve creditCurve = (ISDACompliantCreditCurve) inputs
                .getValue(ValueRequirementNames.HAZARD_RATE_CURVE);
        if (creditCurve == null) {
            throw new OpenGammaRuntimeException("Couldnt get credit curve");
        }

        //final CDSAnalytic analytic = CDSAnalyticConverter.create(cds, now.toLocalDate());
        final CDSAnalyticVisitor visitor = new CDSAnalyticVisitor(now.toLocalDate(), _holidaySource, _regionSource,
                recoveryRate);
        final CDSAnalytic analytic = security.accept(visitor);
        final BuySellProtection buySellProtection = security.isBuy() ? BuySellProtection.BUY
                : BuySellProtection.SELL;
        final Double cdsQuoteDouble = (Double) inputs.getValue(MarketDataRequirementNames.MARKET_VALUE);
        if (cdsQuoteDouble == null) {
            throw new OpenGammaRuntimeException("Couldn't get spread for " + security);
        }
        final CDSQuoteConvention quote = SpreadCurveFunctions.getQuotes(security.getMaturityDate(),
                new double[] { cdsQuoteDouble }, security.getParSpread(), quoteConvention, true)[0];

        final double notional = security.getNotional().getAmount();
        final double coupon = security.getParSpread() * ONE_BPS;
        final PointsUpFront puf = getPointsUpfront(quote, buySellProtection, yieldCurve, analytic, creditCurve);
        final double accruedPremium = analytic.getAccruedPremium(coupon) * notional;
        final int accruedDays = analytic.getAccuredDays();
        final double quotedSpread = getQuotedSpread(quote, puf, buySellProtection, yieldCurve, analytic)
                .getQuotedSpread();
        final double upfrontAmount = getUpfrontAmount(analytic, puf, notional, buySellProtection);
        final double cleanPV = puf.getPointsUpFront() * notional;
        final double cleanPrice = getCleanPrice(puf);
        final TenorLabelledMatrix1D bucketedCS01 = getBucketedCS01(analytic, bucketCDSs, spreadObject.getXData(),
                quote, notional, yieldCurve, creditCurve);
        final double parallelCS01 = getParallelCS01(quote, analytic, yieldCurve, notional, pillarCDSs,
                ArrayUtils.toPrimitive(pillarObject.getYData()));

        final Set<ComputedValue> results = Sets.newHashSetWithExpectedSize(_valueRequirements.length);
        results.add(new ComputedValue(
                new ValueSpecification(ValueRequirementNames.ACCRUED_PREMIUM, target.toSpecification(), properties),
                accruedPremium));
        results.add(new ComputedValue(
                new ValueSpecification(ValueRequirementNames.ACCRUED_DAYS, target.toSpecification(), properties),
                accruedDays));
        results.add(new ComputedValue(
                new ValueSpecification(ValueRequirementNames.QUOTED_SPREAD, target.toSpecification(), properties),
                quotedSpread / ONE_BPS));
        results.add(new ComputedValue(
                new ValueSpecification(ValueRequirementNames.UPFRONT_AMOUNT, target.toSpecification(), properties),
                upfrontAmount));
        results.add(new ComputedValue(new ValueSpecification(ValueRequirementNames.DIRTY_PRESENT_VALUE,
                target.toSpecification(), properties), upfrontAmount));
        results.add(new ComputedValue(new ValueSpecification(ValueRequirementNames.CLEAN_PRESENT_VALUE,
                target.toSpecification(), properties), cleanPV));
        results.add(new ComputedValue(
                new ValueSpecification(ValueRequirementNames.PRINCIPAL, target.toSpecification(), properties),
                cleanPV));
        results.add(new ComputedValue(
                new ValueSpecification(ValueRequirementNames.CLEAN_PRICE, target.toSpecification(), properties),
                cleanPrice));
        results.add(new ComputedValue(
                new ValueSpecification(ValueRequirementNames.BUCKETED_CS01, target.toSpecification(), properties),
                bucketedCS01));
        results.add(new ComputedValue(
                new ValueSpecification(ValueRequirementNames.PARALLEL_CS01, target.toSpecification(), properties),
                parallelCS01));
        results.add(new ComputedValue(
                new ValueSpecification(ValueRequirementNames.POINTS_UPFRONT, target.toSpecification(), properties),
                puf.getPointsUpFront()));
        return results;
    }

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

    @Override
    public Set<ValueSpecification> getResults(final FunctionCompilationContext context,
            final ComputationTarget target) {
        final Set<ValueSpecification> specs = new HashSet<>();
        final ValueProperties properties = createValueProperties().withAny(ISDAFunctionConstants.ISDA_CURVE_OFFSET)
                .withAny(ISDAFunctionConstants.ISDA_CURVE_DATE)
                .with(ISDAFunctionConstants.ISDA_IMPLEMENTATION, ISDAFunctionConstants.ISDA_IMPLEMENTATION_NEW)
                .withAny(ISDAFunctionConstants.CDS_QUOTE_CONVENTION)
                .withAny(ISDAFunctionConstants.ISDA_BUCKET_TENORS)
                .with(ValuePropertyNames.CURVE_CALCULATION_METHOD, ISDAFunctionConstants.ISDA_METHOD_NAME).get();
        for (final String value : _valueRequirements) {
            specs.add(new ValueSpecification(value, target.toSpecification(), properties));
        }
        return specs;
    }

    @Override
    public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context,
            final ComputationTarget target, final ValueRequirement desiredValue) {
        final LegacyVanillaCDSSecurity cds = (LegacyVanillaCDSSecurity) target.getSecurity();
        final Currency ccy = cds.getNotional().getCurrency();
        final CreditCurveIdentifier isdaIdentifier = getISDACurveIdentifier(cds);
        final CreditCurveIdentifier spreadIdentifier = getSpreadCurveIdentifier(cds);

        final String isdaOffset = desiredValue.getConstraint(ISDAFunctionConstants.ISDA_CURVE_OFFSET);
        if (isdaOffset == null) {
            return null;
        }

        final String isdaCurveDate = desiredValue.getConstraint(ISDAFunctionConstants.ISDA_CURVE_DATE);
        if (isdaCurveDate == null) {
            return null;
        }

        final String isdaCurveMethod = desiredValue.getConstraint(ISDAFunctionConstants.ISDA_IMPLEMENTATION);
        if (isdaCurveMethod == null) {
            return null;
        }

        // isda curve
        final ValueProperties isdaProperties = ValueProperties.builder()
                .with(ValuePropertyNames.CURVE, isdaIdentifier.toString())
                .with(ValuePropertyNames.CURVE_CALCULATION_METHOD, ISDAFunctionConstants.ISDA_METHOD_NAME)
                .with(ISDAFunctionConstants.ISDA_CURVE_OFFSET, isdaOffset)
                .with(ISDAFunctionConstants.ISDA_CURVE_DATE, isdaCurveDate)
                .with(ISDAFunctionConstants.ISDA_IMPLEMENTATION, isdaCurveMethod).get();
        final ValueRequirement isdaRequirment = new ValueRequirement(ValueRequirementNames.YIELD_CURVE,
                ComputationTargetType.CURRENCY, ccy.getUniqueId(), isdaProperties);

        final String quoteConvention = desiredValue.getConstraint(ISDAFunctionConstants.CDS_QUOTE_CONVENTION);
        if (quoteConvention == null) {
            return null;
        }

        final String bucketTenors = desiredValue.getConstraint(ISDAFunctionConstants.ISDA_BUCKET_TENORS);
        if (bucketTenors == null) {
            return null;
        }

        //market  spreads
        final ValueProperties spreadProperties = ValueProperties.builder()
                .with(ISDAFunctionConstants.CDS_QUOTE_CONVENTION, quoteConvention)
                .with(ValuePropertyNames.CURVE_CALCULATION_METHOD, ISDAFunctionConstants.ISDA_METHOD_NAME)
                .with(ISDAFunctionConstants.ISDA_CURVE_OFFSET, isdaOffset)
                .with(ISDAFunctionConstants.ISDA_CURVE_DATE, isdaCurveDate)
                .with(ISDAFunctionConstants.ISDA_IMPLEMENTATION, isdaCurveMethod)
                .with(ISDAFunctionConstants.ISDA_BUCKET_TENORS, bucketTenors).get();
        final ValueRequirement spreadRequirment = new ValueRequirement(ValueRequirementNames.BUCKETED_SPREADS,
                target.toSpecification(), spreadProperties);
        final ValueRequirement pillarRequirment = new ValueRequirement(ValueRequirementNames.PILLAR_SPREADS,
                target.toSpecification(), spreadProperties);
        final ValueRequirement creditCurveRequirement = new ValueRequirement(
                ValueRequirementNames.HAZARD_RATE_CURVE, target.toSpecification(), spreadProperties);

        // get individual spread for this cds (ignore business day adjustment on either)
        final Period period = Period.between(cds.getStartDate().toLocalDate().withDayOfMonth(20),
                cds.getMaturityDate().toLocalDate().withDayOfMonth(20));
        final ValueRequirement cdsSpreadRequirement = new ValueRequirement(MarketDataRequirementNames.MARKET_VALUE,
                ComputationTargetType.PRIMITIVE, ExternalId.of("Tenor", period.toString()));

        final CdsRecoveryRateIdentifier recoveryRateIdentifier = cds
                .accept(new CreditSecurityToRecoveryRateVisitor(context.getSecuritySource()));
        final ValueRequirement recoveryRateRequirement = new ValueRequirement("PX_LAST",
                ComputationTargetType.PRIMITIVE, recoveryRateIdentifier.getExternalId());

        return Sets.newHashSet(isdaRequirment, spreadRequirment, cdsSpreadRequirement, creditCurveRequirement,
                pillarRequirment, recoveryRateRequirement);
    }

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

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

    public static CreditCurveIdentifier getSpreadCurveIdentifier(final CreditDefaultSwapSecurity cds) {
        return getCreditCurveIdentifier(cds, "");
    }

    public static CreditCurveIdentifier getISDACurveIdentifier(final CreditDefaultSwapSecurity cds) {
        return getCreditCurveIdentifier(cds, "ISDA_");
    }

    /**
     * Get the CreditCurveIdentifier with name appended
     *
     * @param security
     */
    private static CreditCurveIdentifier getCreditCurveIdentifier(final CreditDefaultSwapSecurity security,
            final String name) {
        final CreditCurveIdentifier curveIdentifier = CreditCurveIdentifier.of(
                name + security.getReferenceEntity().getValue(), security.getNotional().getCurrency(),
                security.getDebtSeniority().toString(), security.getRestructuringClause().toString());
        return curveIdentifier;
    }

    public PointsUpFront getPointsUpfront(CDSQuoteConvention quote, BuySellProtection buySellProtection,
            ISDACompliantYieldCurve yieldCurve, CDSAnalytic analytic, ISDACompliantCreditCurve creditCurve) {
        double puf = 0.0;
        if (quote instanceof PointsUpFront) {
            return (PointsUpFront) quote;
        } else if (quote instanceof QuotedSpread) {
            puf = POINTS_UP_FRONT_CONVERTER.quotedSpreadToPUF(analytic, quote.getCoupon(), yieldCurve,
                    ((QuotedSpread) quote).getQuotedSpread());
        } else if (quote instanceof ParSpread) {
            puf = PRICER.pv(analytic, yieldCurve, creditCurve, ((ParSpread) quote).getCoupon());
        } else {
            throw new OpenGammaRuntimeException("Unknown quote type " + quote);
        }
        // SELL protection reverses directions of legs
        puf = (buySellProtection == BuySellProtection.SELL) ? -puf : puf;
        return new PointsUpFront(quote.getCoupon(), puf);
    }

    public static QuotedSpread getQuotedSpread(CDSQuoteConvention quote, PointsUpFront puf,
            BuySellProtection buySellProtection, ISDACompliantYieldCurve yieldCurve, CDSAnalytic analytic) {
        double quotedSpread;
        if (quote instanceof QuotedSpread) {
            return (QuotedSpread) quote;
        } else {
            quotedSpread = POINTS_UP_FRONT_CONVERTER.pufToQuotedSpread(analytic, puf.getCoupon(), yieldCurve,
                    puf.getPointsUpFront());
        }
        // SELL protection reverses directions of legs
        quotedSpread = (buySellProtection == BuySellProtection.SELL) ? -quotedSpread : quotedSpread;
        return new QuotedSpread(quote.getCoupon(), quotedSpread);
    }

    public double getUpfrontAmount(final CDSAnalytic analytic, final PointsUpFront puf, final double notional,
            final BuySellProtection buySellProtection) {
        // upfront amount is defined as dirty PV
        double cash = (puf.getPointsUpFront() - analytic.getAccruedPremium(puf.getCoupon())) * notional;
        // SELL protection reverses directions of legs
        return (buySellProtection == BuySellProtection.SELL) ? -cash : cash;
    }

    public double getCleanPrice(final PointsUpFront puf) {
        return 100.0 * (1 - puf.getPointsUpFront());
    }

    public TenorLabelledMatrix1D getBucketedCS01(CDSAnalytic analytic, CDSAnalytic[] buckets, Tenor[] tenors,
            CDSQuoteConvention quote, double notional, ISDACompliantYieldCurve yieldCurve,
            ISDACompliantCreditCurve creditCurve) {
        //TODO: Check quote.getCoupon() is spread value for IMM & 0.01 (or 0.05) for non IMM
        double[] cs01Values;
        if (quote instanceof ParSpread) {
            cs01Values = CALCULATOR.bucketedCS01FromCreditCurve(analytic, quote.getCoupon(), buckets, yieldCurve,
                    creditCurve, ONE_BPS);
        } else {
            cs01Values = CALCULATOR.bucketedCS01FromCreditCurve(analytic, quote.getCoupon()/*coupon * ONE_BPS*/,
                    buckets, yieldCurve, creditCurve, ONE_BPS);
        }
        for (int i = 0; i < cs01Values.length; i++) {
            cs01Values[i] *= notional * ONE_BPS;
        }
        return new TenorLabelledMatrix1D(tenors, cs01Values);
    }

    public double getParallelCS01(CDSQuoteConvention quote, CDSAnalytic analytic,
            ISDACompliantYieldCurve yieldCurve, double notional, CDSAnalytic[] pillars, double[] pillarSpreads) {
        double cs01;
        if (quote instanceof ParSpread) {
            cs01 = CALCULATOR.parallelCS01FromParSpreads(analytic, quote.getCoupon(), // ParSpread
                    yieldCurve, pillars, pillarSpreads, ONE_BPS, BumpType.ADDITIVE);
        } else {
            cs01 = CALCULATOR.parallelCS01(analytic, quote, yieldCurve, ONE_BPS);
        }
        return Double.valueOf(cs01 * notional * ONE_BPS);
    }

    public static ManageableRegion getTestRegion() {
        final ManageableRegion region = new ManageableRegion();
        region.setUniqueId(UniqueId.parse("Dummy~region"));
        region.setName("United States");
        region.setCurrency(Currency.USD);
        region.setCountry(Country.US);
        region.setTimeZone(ZoneId.of("America/New_York"));
        region.setExternalIdBundle(ExternalIdBundle.of(ExternalId.parse("dummy~region")));
        return region;
    }

    /** test region */
    public final class TestRegionSource extends AbstractSourceWithExternalBundle<Region> implements RegionSource {

        private final AtomicLong _count = new AtomicLong(0);
        private final Region _testRegion;

        private TestRegionSource(final Region testRegion) {
            _testRegion = testRegion;
        }

        private TestRegionSource() {
            _testRegion = getTestRegion();
        }

        @Override
        public Collection<Region> get(final ExternalIdBundle bundle, final VersionCorrection versionCorrection) {
            _count.getAndIncrement();
            Collection<Region> result = Collections.emptyList();
            if (_testRegion.getExternalIdBundle().equals(bundle)
                    && versionCorrection.equals(VersionCorrection.LATEST)) {
                result = Collections.singleton((Region) getTestRegion());
            }
            return result;
        }

        @Override
        public Region get(final ObjectId objectId, final VersionCorrection versionCorrection) {
            _count.getAndIncrement();
            Region result = null;
            if (_testRegion.getUniqueId().getObjectId().equals(objectId)
                    && versionCorrection.equals(VersionCorrection.LATEST)) {
                result = _testRegion;
            }
            return result;
        }

        @Override
        public Region get(final UniqueId uniqueId) {
            _count.getAndIncrement();
            Region result = null;
            if (_testRegion.getUniqueId().equals(uniqueId)) {
                result = _testRegion;
            }
            return result;
        }

        @Override
        public Region getHighestLevelRegion(final ExternalIdBundle bundle) {
            _count.getAndIncrement();
            Region result = null;
            if (_testRegion.getExternalIdBundle().equals(bundle)) {
                result = _testRegion;
            }
            return result;
        }

        @Override
        public Region getHighestLevelRegion(final ExternalId externalId) {
            _count.getAndIncrement();
            Region result = null;
            if (_testRegion.getExternalIdBundle().contains(externalId)) {
                result = _testRegion;
            }
            return result;
        }

        /**
         * Gets the count.
         *
         * @return the count
         */
        public AtomicLong getCount() {
            return _count;
        }

        @Override
        public ChangeManager changeManager() {
            return DummyChangeManager.INSTANCE;
        }

    }
}