/**
  * Return a good business date computed from a given date and shifted by a certain number of
  * business days. This version uses LocalDate. If the number of shift days is 0, the return date
  * is the next business day. If the number of shift days is non-zero (positive or negative), a 0
  * shift is first applied and then a one business day shift is applied as many time as the
  * absolute value of the shift. If the shift is positive, the one business day is to the future.,
  * if the shift is negative, the one business day is to the past.
  *
  * @param date The initial date.
  * @param shiftDays The number of days of the adjustment. Can be negative or positive.
  * @param calendar The calendar representing the good business days.
  * @return The adjusted dates.
  */
 public static LocalDate getAdjustedDate(
     final LocalDate date, final int shiftDays, final Calendar calendar) {
   ArgumentChecker.notNull(date, "date");
   ArgumentChecker.notNull(calendar, "calendar");
   LocalDate result = date;
   while (!calendar.isWorkingDay(result)) {
     result = result.plusDays(1);
   }
   if (shiftDays > 0) {
     for (int loopday = 0; loopday < shiftDays; loopday++) {
       result = result.plusDays(1);
       while (!calendar.isWorkingDay(result)) {
         result = result.plusDays(1);
       }
     }
   } else {
     for (int loopday = 0; loopday < -shiftDays; loopday++) {
       result = result.minusDays(1);
       while (!calendar.isWorkingDay(result)) {
         result = result.minusDays(1);
       }
     }
   }
   return result;
 }
  /**
   * Computes the risky present value of a premium payment
   *
   * <p>This mimics the ISDA c code function <b>FeePaymentPVWithTimeLine<b>
   *
   * @param today
   * @param valueDate
   * @param stepinDate
   * @param accStartDate
   * @param accEndDate
   * @param payAccOnDefault
   * @return PV
   */
  private double[] calculateSinglePeriodRPV01(
      final LocalDate today,
      final LocalDate accStartDate,
      final LocalDate accEndDate,
      final LocalDate paymentDate,
      final int obsOffset,
      final ISDACompliantDateYieldCurve yieldCurve,
      final ISDACompliantDateCreditCurve hazardRateCurve) {

    final double accTime = _accuralDayCount.getDayCountFraction(accStartDate, accEndDate);
    double t = _curveDayCount.getDayCountFraction(today, paymentDate);
    double tObsOffset = _curveDayCount.getDayCountFraction(today, accEndDate.plusDays(obsOffset));

    // TODO Do we need this?
    // Compensate Java shortcoming
    if (Double.compare(t, -0.0) == 0) {
      t = 0;
    }
    if (Double.compare(tObsOffset, -0.0) == 0) {
      tObsOffset = 0;
    }

    final double survival = hazardRateCurve.getSurvivalProbability(tObsOffset);
    final double discount = yieldCurve.getDiscountFactor(t);
    return new double[] {accTime * discount * survival, accTime};
  }
 public static LocalDate[] getSettlementDateSchedule(
     final LocalDate[] dates,
     final Calendar calendar,
     final BusinessDayConvention businessDayConvention,
     final int settlementDays) {
   ArgumentChecker.notEmpty(dates, "dates");
   ArgumentChecker.notNull(calendar, "calendar");
   final int n = dates.length;
   final LocalDate[] result = new LocalDate[n];
   for (int i = 0; i < n; i++) {
     LocalDate date = businessDayConvention.adjustDate(calendar, dates[i].plusDays(1));
     for (int j = 0; j < settlementDays; j++) {
       date = businessDayConvention.adjustDate(calendar, date.plusDays(1));
     }
     result[i] = date;
   }
   return result;
 }
  public void getHistoricalWithInclusiveExclusiveDates() throws Exception {
    LocalDate end = DateUtils.previousWeekDay();
    LocalDate start = end.minusDays(7);

    HistoricalTimeSeriesInfoSearchRequest request =
        new HistoricalTimeSeriesInfoSearchRequest(IDENTIFIERS);
    request.setValidityDate(LocalDate.now());
    request.setDataSource(BBG_DATA_SOURCE);
    request.setDataProvider(CMPL_DATA_PROVIDER);
    request.setDataField(CLOSE_DATA_FIELD);
    LocalDateDoubleTimeSeries timeSeries = randomTimeSeries();

    HistoricalTimeSeriesInfoSearchResult searchResult = new HistoricalTimeSeriesInfoSearchResult();
    HistoricalTimeSeriesInfoDocument doc = new HistoricalTimeSeriesInfoDocument();
    doc.setUniqueId(UID);
    doc.getInfo().setTimeSeriesObjectId(UID.getObjectId());
    searchResult.getDocuments().add(doc);

    when(_mockResolver.resolve(
            IDENTIFIERS,
            LocalDate.now(),
            BBG_DATA_SOURCE,
            CMPL_DATA_PROVIDER,
            CLOSE_DATA_FIELD,
            null))
        .thenReturn(new HistoricalTimeSeriesResolutionResult(doc.getInfo()));

    for (boolean includeStart : new boolean[] {true, false}) {
      for (boolean includeEnd : new boolean[] {true, false}) {
        // Also test max points limit for various values
        for (Integer maxPoints : new Integer[] {null, -10, -1, 1, 0, -2, 2, 10}) {
          LocalDate startInput = start;
          LocalDate endInput = end;
          if (!includeStart) {
            startInput = start.plusDays(1);
          }
          if (!includeEnd) {
            endInput = end.minusDays(1);
          }

          ManageableHistoricalTimeSeries hts = new ManageableHistoricalTimeSeries();
          LocalDateDoubleTimeSeries lddts =
              (maxPoints == null)
                      || (Math.abs(maxPoints)
                          >= timeSeries.subSeries(start, includeStart, end, includeEnd).size())
                  ? timeSeries.subSeries(start, includeStart, end, includeEnd)
                  : (maxPoints >= 0)
                      ? timeSeries.subSeries(start, includeStart, end, includeEnd).head(maxPoints)
                      : timeSeries.subSeries(start, includeStart, end, includeEnd).tail(-maxPoints);
          hts.setUniqueId(UID);
          hts.setTimeSeries(lddts);
          when(_mockMaster.getTimeSeries(
                  UID.getObjectId(),
                  VersionCorrection.LATEST,
                  HistoricalTimeSeriesGetFilter.ofRange(startInput, endInput, maxPoints)))
              .thenReturn(hts);
          when(_mockMaster.search(request)).thenReturn(searchResult);

          HistoricalTimeSeries test =
              (maxPoints == null)
                  ? _tsSource.getHistoricalTimeSeries(
                      IDENTIFIERS,
                      BBG_DATA_SOURCE,
                      CMPL_DATA_PROVIDER,
                      CLOSE_DATA_FIELD,
                      start,
                      includeStart,
                      end,
                      includeEnd)
                  : _tsSource.getHistoricalTimeSeries(
                      IDENTIFIERS,
                      BBG_DATA_SOURCE,
                      CMPL_DATA_PROVIDER,
                      CLOSE_DATA_FIELD,
                      start,
                      includeStart,
                      end,
                      includeEnd,
                      maxPoints);

          assertEquals(UID, test.getUniqueId());
          assertEquals(hts.getTimeSeries(), test.getTimeSeries());
        }
      }
    }
  }
  /** Test of CDX.NA.IG.20-v1 5Y from Markit website */
  @Test
  public void test() {
    // numbers from https://www.markit.com
    // expected values (user)
    final double mCleanPrice = 100.3;
    final double mCashSettle = -43750455922031.0;
    final int mAccDays = 49;
    final double mAccAmt = 13611111111111.11;
    final double mCreditDV01 = 4647028138242.0;
    // transformed
    final double mCashSettleTransformed = -43757966062423.0;
    final double mCreditDV01Transformed = 4646838148143.0;

    final double tradeLevel = 0.00935;
    final LocalDate tradeDate = LocalDate.of(2013, Month.AUGUST, 7);
    final LocalDate stepinDate = tradeDate.plusDays(1); // AKA stepin date
    final LocalDate cashSettleDate =
        addWorkDays(tradeDate, 3, DEFAULT_CALENDAR); // AKA valuation date
    final LocalDate startDate = getPrevIMMDate(tradeDate);
    final LocalDate maturity = LocalDate.of(2018, Month.JUNE, 20);

    // yield curve
    final LocalDate spotDate = addWorkDays(tradeDate.minusDays(1), 3, DEFAULT_CALENDAR);
    final String[] yieldCurvePoints =
        new String[] {
          "1M", "2M", "3M", "6M", "1Y", "2Y", "3Y", "4Y", "5Y", "6Y", "7Y", "8Y", "9Y", "10Y",
          "12Y", "15Y", "20Y", "25Y", "30Y"
        };
    final String[] yieldCurveInstruments =
        new String[] {
          "M", "M", "M", "M", "M", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S",
          "S"
        };
    final double[] rates =
        new double[] {
          0.00185, 0.00227, 0.002664, 0.003955, 0.006654, 0.004845, 0.00784, 0.011725, 0.0157,
          0.01919, 0.02219, 0.024565, 0.02657, 0.02825, 0.03095, 0.033495, 0.035505, 0.036425,
          0.036915
        };
    final ISDACompliantYieldCurve yieldCurve =
        makeYieldCurve(
            tradeDate,
            spotDate,
            yieldCurvePoints,
            yieldCurveInstruments,
            rates,
            ACT360,
            D30360,
            Period.ofMonths(6));

    final LocalDate nextIMM = getNextIMMDate(tradeDate);
    final LocalDate[] pillarDates = getIMMDateSet(nextIMM, TENORS);
    final int nPillars = pillarDates.length;
    final double[] flatSpreads = new double[nPillars];
    Arrays.fill(flatSpreads, tradeLevel);
    final CDSAnalytic[] calibrationCDS = new CDSAnalytic[nPillars];
    for (int i = 0; i < nPillars; i++) {
      calibrationCDS[i] =
          new CDSAnalytic(
              tradeDate,
              stepinDate,
              cashSettleDate,
              startDate,
              pillarDates[i],
              PAY_ACC_ON_DEFAULT,
              PAYMENT_INTERVAL,
              STUB,
              PROCTECTION_START,
              RECOVERY_RATE);
    }

    final CDSAnalytic pointCDS =
        new CDSAnalytic(
            tradeDate,
            stepinDate,
            cashSettleDate,
            startDate,
            maturity,
            PAY_ACC_ON_DEFAULT,
            PAYMENT_INTERVAL,
            STUB,
            PROCTECTION_START,
            RECOVERY_RATE);
    final QuotedSpread qSpread = new QuotedSpread(COUPON, tradeLevel);
    final double puf = PUF_CONVERTER.convert(pointCDS, qSpread, yieldCurve).getPointsUpFront();
    final double price = (1 - puf) * 100;
    final double accAmt = NOTIONAL * pointCDS.getAccruedPremium(COUPON);
    final double cashSettle = puf * NOTIONAL - accAmt;
    final double cs01 =
        NOTIONAL * ONE_BP * CS01_CAL.parallelCS01(pointCDS, qSpread, yieldCurve, ONE_BP);

    //    System.out.println("price: " + price + "%");
    //    System.out.println("Accured Days: " + pointCDS.getAccuredDays());
    //    System.out.println("Accured Amt: " + accAmt);
    //    System.out.println("Cash Settlement: " + cashSettle);
    //    System.out.println("Credit DV01: " + cs01);

    assertEquals("price", mCleanPrice, price, 1e-1); // only 1dp of percentage given
    assertEquals("Cash Settlement", mCashSettle, cashSettle, 1e-15 * NOTIONAL);
    assertEquals("Accured Days", mAccDays, pointCDS.getAccuredDays());
    assertEquals("Accured Amt", mAccAmt, accAmt, 1e-18 * NOTIONAL);
    assertEquals("Credit DV01", mCreditDV01, cs01, 1e-15 * NOTIONAL);

    // flat spread term structure (transformed)
    final ISDACompliantCreditCurve creditCurve =
        CREDIT_CURVE_BUILDER.calibrateCreditCurve(calibrationCDS, flatSpreads, yieldCurve);
    final double cashSettleTrans =
        NOTIONAL * PRICER.pv(pointCDS, yieldCurve, creditCurve, COUPON, PriceType.DIRTY);
    final double cs01Trans =
        NOTIONAL
            * ONE_BP
            * CS01_CAL.parallelCS01FromParSpreads(
                pointCDS,
                COUPON,
                yieldCurve,
                calibrationCDS,
                flatSpreads,
                ONE_BP,
                BumpType.ADDITIVE);
    //    System.out.println("Cash Settlement (trans): " + cashSettleTrans);
    //    System.out.println("Credit DV01 (trans): " + cs01Trans);
    assertEquals(
        "Cash Settlement (trans)", mCashSettleTransformed, cashSettleTrans, 1e-15 * NOTIONAL);
    assertEquals("Credit DV01 (Trans)", mCreditDV01Transformed, cs01Trans, 1e-15 * NOTIONAL);
  }
  @Test(enabled = false)
  public void rollingTest() {

    final MarketQuoteConverter pufConverter = new MarketQuoteConverter();
    final FastCreditCurveBuilder builder = new FastCreditCurveBuilder();

    final double notional = 1e12;
    final LocalDate today = LocalDate.of(2011, Month.JUNE, 13);
    final Period tenor = Period.ofYears(3);
    final double tradeLevel = 99.785 * ONE_BP;
    // final double tradeLevel = 99.78471 * ONE_BP;

    final LocalDate tradeDate = today;
    final LocalDate stepinDate = tradeDate.plusDays(1); // AKA stepin date
    final LocalDate cashSettleDate =
        addWorkDays(tradeDate, 3, DEFAULT_CALENDAR); // AKA valuation date
    final LocalDate startDate = getPrevIMMDate(tradeDate).plusDays(1);
    final LocalDate nextRolldate = getNextIndexRollDate(today);
    final LocalDate maturity = nextRolldate.plus(tenor).minusMonths(3);

    // yield curve
    final LocalDate spotDate = addWorkDays(today.minusDays(1), 3, DEFAULT_CALENDAR);
    final String[] yieldCurvePoints =
        new String[] {
          "1M", "2M", "3M", "6M", "9M", "1Y", "2Y", "3Y", "4Y", "5Y", "6Y", "7Y", "8Y", "9Y", "10Y",
          "12Y", "15Y", "20Y", "30Y"
        };
    final String[] yieldCurveInstruments =
        new String[] {
          "M", "M", "M", "M", "M", "M", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S",
          "S"
        };
    final double[] rates =
        new double[] {
          0.01262, 0.01344, 0.01469, 0.01739, 0.01947, 0.02145, 0.02114, 0.02308, 0.02511, 0.02695,
          0.02857, 0.02989, 0.03104, 0.03204, 0.03292, 0.0345, 0.03619, 0.03712, 0.03602
        };
    final ISDACompliantYieldCurve yieldCurve =
        makeYieldCurve(
            tradeDate,
            spotDate,
            yieldCurvePoints,
            yieldCurveInstruments,
            rates,
            ACT360,
            D30360,
            Period.ofYears(1));

    final CDSAnalytic pointCDS =
        new CDSAnalytic(
            tradeDate,
            stepinDate,
            cashSettleDate,
            startDate,
            maturity,
            PAY_ACC_ON_DEFAULT,
            PAYMENT_INTERVAL,
            STUB,
            PROCTECTION_START,
            RECOVERY_RATE);
    final QuotedSpread qSpread = new QuotedSpread(COUPON, tradeLevel);
    final double puf = pufConverter.convert(pointCDS, qSpread, yieldCurve).getPointsUpFront();
    final double accAmt = notional * pointCDS.getAccruedPremium(COUPON);
    final double cashAmount = notional * puf - accAmt;
    System.out.println(
        startDate
            + "\t"
            + maturity
            + "\t"
            + puf
            + "\t"
            + (1 - puf) * 100
            + "%\t"
            + cashAmount
            + "\t"
            + pointCDS.getAccuredDays()
            + "\t"
            + accAmt);

    final double impSpread = pufConverter.pufToQuotedSpread(pointCDS, COUPON, yieldCurve, puf);
    System.out.println("imp Spread: " + impSpread);

    // flat spread calculations
    final Period[] standardTenors =
        new Period[] {
          Period.ofMonths(6),
          Period.ofYears(1),
          Period.ofYears(2),
          Period.ofYears(3),
          Period.ofYears(4),
          Period.ofYears(5),
          Period.ofYears(7),
          Period.ofYears(10)
        };
    final int nMat = standardTenors.length;
    final LocalDate[] maturities = new LocalDate[nMat];
    final CDSAnalytic[] pillarCDS = new CDSAnalytic[nMat];
    for (int i = 0; i < nMat; i++) {
      maturities[i] = nextRolldate.plus(standardTenors[i]).minusMonths(3);
      pillarCDS[i] =
          new CDSAnalytic(
              tradeDate,
              stepinDate,
              cashSettleDate,
              startDate,
              maturities[i],
              PAY_ACC_ON_DEFAULT,
              PAYMENT_INTERVAL,
              STUB,
              PROCTECTION_START,
              RECOVERY_RATE);
    }
    final double[] flatSpreads = new double[nMat];
    Arrays.fill(flatSpreads, tradeLevel);
    final ISDACompliantCreditCurve creditCurve =
        builder.calibrateCreditCurve(pillarCDS, flatSpreads, yieldCurve);
    final double pufTrans = PRICER_MARKIT_FIX.pv(pointCDS, yieldCurve, creditCurve, COUPON);
    final double cashAmountTrans = notional * pufTrans - accAmt;
    System.out.println(pufTrans + "\t" + cashAmountTrans);
  }
public class AnalyticCDV01Test {

  // private static final ISDACompliantCreditCurveBuild BUILDER = new
  // ISDACompliantCreditCurveBuild();
  private static final ISDACompliantCreditCurveBuilder BUILDER = new FastCreditCurveBuilder();
  private static final AnalyticCDSPricer PRICER = new AnalyticCDSPricer();
  private static final Calendar DEFAULT_CALENDAR = new MondayToFridayCalendar("Weekend_Only");

  // common data
  private static final LocalDate TODAY = LocalDate.of(2013, 4, 21);
  private static final LocalDate EFFECTIVE_DATE = TODAY.plusDays(1); // AKA stepin date
  private static final LocalDate CASH_SETTLE_DATE =
      addWorkDays(TODAY, 3, DEFAULT_CALENDAR); // AKA valuation date
  private static final double RECOVERY_RATE = 0.4;
  // valuation CDS
  private static final LocalDate PROTECTION_STATE_DATE = LocalDate.of(2013, 2, 3); // Seasoned CDS
  private static final LocalDate PROTECTION_END_DATE = LocalDate.of(2018, 3, 20);
  private static final double DEAL_SPREAD = 101;
  private static final CDSAnalytic CDS;

  // market CDSs
  private static final LocalDate[] PAR_SPD_DATES =
      new LocalDate[] {
        LocalDate.of(2013, 6, 20),
        LocalDate.of(2013, 9, 20),
        LocalDate.of(2014, 3, 20),
        LocalDate.of(2015, 3, 20),
        LocalDate.of(2016, 3, 20),
        LocalDate.of(2018, 3, 20),
        LocalDate.of(2023, 3, 20)
      };
  private static final double[] PAR_SPREADS = new double[] {50, 70, 80, 95, 100, 95, 80};
  private static final int NUM_MARKET_CDS = PAR_SPD_DATES.length;
  private static final CDSAnalytic[] MARKET_CDS = new CDSAnalytic[NUM_MARKET_CDS];

  // yield curve
  private static ISDACompliantYieldCurve YIELD_CURVE;

  static {
    final double flatrate = 0.05;
    final double t = 20.0;
    YIELD_CURVE = new ISDACompliantYieldCurve(new double[] {t}, new double[] {flatrate});

    final boolean payAccOndefault = true;
    final Period tenor = Period.ofMonths(3);
    final StubType stubType = StubType.FRONTSHORT;
    final boolean protectionStart = true;

    CDS =
        new CDSAnalytic(
            TODAY,
            EFFECTIVE_DATE,
            CASH_SETTLE_DATE,
            PROTECTION_STATE_DATE,
            PROTECTION_END_DATE,
            payAccOndefault,
            tenor,
            stubType,
            protectionStart,
            RECOVERY_RATE);

    for (int i = 0; i < NUM_MARKET_CDS; i++) {
      MARKET_CDS[i] =
          new CDSAnalytic(
              TODAY,
              EFFECTIVE_DATE,
              CASH_SETTLE_DATE,
              TODAY,
              PAR_SPD_DATES[i],
              payAccOndefault,
              tenor,
              stubType,
              protectionStart,
              RECOVERY_RATE);
    }
  }

  @Test
  public void Test() {
    final boolean print = false;
    if (print) {
      System.out.println("AnalyticCDV01Test set print =false before push");
    }

    final double dealSpread = DEAL_SPREAD / 10000;
    final double[] mrkSpreads = new double[NUM_MARKET_CDS];
    for (int i = 0; i < NUM_MARKET_CDS; i++) {
      mrkSpreads[i] = PAR_SPREADS[i] / 10000;
    }
    final ISDACompliantCreditCurve creditCurve =
        BUILDER.calibrateCreditCurve(MARKET_CDS, mrkSpreads, YIELD_CURVE);
    final int n = creditCurve.getNumberOfKnots();
    final double[][] jacA = new double[n][n];
    for (int j = 0; j < n; j++) {
      final CDSAnalytic cds = MARKET_CDS[j];
      for (int i = 0; i < n; i++) {
        final double dDdH = PRICER.parSpreadCreditSensitivity(cds, YIELD_CURVE, creditCurve, i);
        jacA[i][j] = dDdH;
      }
    }
    final DoubleMatrix2D jac = new DoubleMatrix2D(jacA);
    if (print) {
      System.out.println(jac);
      System.out.println();
    }

    final double[] temp = new double[n];
    for (int i = 0; i < n; i++) {
      temp[i] = PRICER.pvCreditSensitivity(CDS, YIELD_CURVE, creditCurve, dealSpread, i);
    }
    final DoubleMatrix1D dVdH = new DoubleMatrix1D(temp);
    if (print) {
      System.out.println(dVdH);
      System.out.println();
    }

    final LUDecompositionCommons decomp = new LUDecompositionCommons();
    final LUDecompositionResult res = decomp.evaluate(jac);
    final DoubleMatrix1D dVdS = res.solve(dVdH);

    // compare with bump and reprice
    final SpreadSensitivityCalculator bumpCal = new SpreadSensitivityCalculator();
    final double[] fd =
        bumpCal.bucketedCS01FromParSpreads(
            CDS, dealSpread, YIELD_CURVE, MARKET_CDS, mrkSpreads, 1e-7, BumpType.ADDITIVE);
    final DoubleMatrix1D fd_dVdS = new DoubleMatrix1D(fd);
    if (print) {
      System.out.println(dVdS);
      System.out.println(fd_dVdS);
    }
    for (int i = 0; i < n; i++) {
      assertEquals(
          fd_dVdS.getEntry(i),
          dVdS.getEntry(i),
          1e-6); // the fd is only forward difference - so accuracy is not great
    }
  }
}
Exemple #8
0
  public static void scheduleAll(Context context) {
    String[] projection = {
      DBContract.Medicines._ID,
      DBContract.Medicines.COLUMN_NAME_ALARM,
      DBContract.Medicines.COLUMN_NAME_STARTDATE,
      DBContract.Medicines.COLUMN_NAME_ENDDATE,
      DBContract.Medicines.COLUMN_NAME_RECURRENCE,
      DBContract.Medicines.COLUMN_NAME_SCHEDULE
    };

    String selection = DBContract.Medicines.COLUMN_NAME_ENDDATE + " != ?";
    String[] selectionArgs = {"0"};

    // obtener medicamentos en vigor: fecha fin distinta de cero
    Cursor cursor =
        context
            .getContentResolver()
            .query(
                LembramoContentProvider.CONTENT_URI_MEDICINES,
                projection,
                selection,
                selectionArgs,
                null);

    boolean active, started;
    long idMedicine, endMillis;
    long rangeStartMillis = 0, rangeEndMillis = 0;
    LocalDate startDate, endDate;
    LocalDate now = LocalDate.now();

    while (cursor.moveToNext()) {
      idMedicine = cursor.getLong(cursor.getColumnIndex(DBContract.Medicines._ID));
      startDate =
          TimeUtils.parseDate(
              cursor.getString(cursor.getColumnIndex(DBContract.Medicines.COLUMN_NAME_STARTDATE)));
      endMillis = cursor.getLong(cursor.getColumnIndex(DBContract.Medicines.COLUMN_NAME_ENDDATE));
      endDate = TimeUtils.getDateFromMillis(endMillis);

      // hemos comenzado el tratamiento?
      started = true;
      if (now.isBefore(startDate)) {
        // aun no se ha llegado a la fecha de inicio del tratamiento
        // si queda más de un día no planificamos todavía
        if (Period.between(now, startDate).getDays() > 1) started = false;
      }

      // endMillis != 0 porque lo hemos pedido así en la consulta
      // si endMillis == -1 es tratamiento para siempre
      active = true;
      if (endMillis != -1) {
        // fecha concreta de finalización
        if (now.isAfter(endDate)) {
          active = false;
          setInactive(context, idMedicine);
        }
      }

      if (started && active) {
        String recurrenceRule =
            cursor.getString(cursor.getColumnIndex(DBContract.Medicines.COLUMN_NAME_RECURRENCE));
        String intakeRule =
            cursor.getString(cursor.getColumnIndex(DBContract.Medicines.COLUMN_NAME_SCHEDULE));
        Time dtStart =
            TimeUtils.getTimeDateFromString(
                cursor.getString(
                    cursor.getColumnIndex(DBContract.Medicines.COLUMN_NAME_STARTDATE)));

        // buscar en tabla intakes última planificación
        long last = getLastPlannedIntakeDate(context, idMedicine);
        boolean plan = true;
        if (last == 0) {
          // no hay ninguna planificacion previa, partimos de cero
          rangeStartMillis = TimeUtils.getMillis(startDate);

          if (now.isAfter(startDate))
            // el móvil estuvo apagado, estamos en medio de la planificación
            // pero aún no hubo ninguna. se perdieron intakes
            rangeEndMillis = TimeUtils.getMillis(now.plusDays(1));
          else rangeEndMillis = TimeUtils.getMillis(startDate.plusDays(1));

        } else {
          // hubo planificaciones anteriores
          LocalDate d = TimeUtils.getDateFromMillis(last).plusDays(1);
          if (Period.between(now, d).getDays() > 1) {
            plan = false;
          } else {
            rangeStartMillis = TimeUtils.getMillis(d);
            rangeEndMillis = TimeUtils.getMillis(d.plusDays(1));
          }
        }

        if (plan) {
          long[] days = expand(dtStart, recurrenceRule, rangeStartMillis, rangeEndMillis);
          if (days.length > 0) {
            List<IntakeHelper> dailyIntakes = IntakeUtils.parseDailyIntakes(intakeRule);

            for (long day : days) {
              LocalDate date = TimeUtils.getDateFromMillis(day);
              int max;
              // controlar las que son COUNT
              if ((getDurationType(dtStart, recurrenceRule) == END_BY_COUNT)
                  && (date.isEqual(endDate)))
                max = getNumberOfLastIntakesByCount(dtStart, recurrenceRule, dailyIntakes.size());
              else max = dailyIntakes.size();

              IntakeHelper intake;
              long intakeInstant;
              int i = 0;
              while (i < max) {
                // añadir las tomas de ese día
                intake = dailyIntakes.get(i);
                intakeInstant = TimeUtils.getMillis(date, intake.getTime());
                saveIntake(context, intakeInstant, intake.getDose(), idMedicine);
                i++;
              }
            }
          }
        }
      }
    }
    cursor.close();
  }
  /**
   * This is the present value of the premium leg per unit of fractional spread - hence it is equal
   * to 10,000 times the RPV01 (Risky PV01). The actual PV of the leg is this multiplied by the
   * notional and the fractional spread (i.e. spread in basis points divided by 10,000)
   *
   * <p>This mimics the ISDA c function <b>JpmcdsCdsFeeLegPV</b>
   *
   * @param today The 'current' date
   * @param stepinDate Date when party assumes ownership. This is normally today + 1 (T+1). Aka
   *     assignment date or effective date.
   * @param valueDate The valuation date. The date that values are PVed to. Is is normally today + 3
   *     business days. Aka cash-settle date.
   * @param startDate The protection start date. If protectStart = true, then protections starts at
   *     the beginning of the day, otherwise it is at the end.
   * @param endDate The protection end date (the protection ends at end of day)
   * @param payAccOnDefault Is the accrued premium paid in the event of a default
   * @param tenor The nominal step between premium payments (e.g. 3 months, 6 months).
   * @param stubType stubType Options are FRONTSHORT, FRONTLONG, BACKSHORT, BACKLONG or NONE -
   *     <b>Note</b> in this code NONE is not allowed
   * @param yieldCurve Curve from which payments are discounted
   * @param hazardRateCurve Curve giving survival probability
   * @param protectStart Does protection start at the beginning of the day
   * @param priceType Clean or Dirty price. The clean price removes the accrued premium if the trade
   *     is between payment times.
   * @return 10,000 times the RPV01 (on a notional of 1)
   */
  public double pvPremiumLegPerUnitSpread(
      final LocalDate today,
      final LocalDate stepinDate,
      final LocalDate valueDate,
      final LocalDate startDate,
      final LocalDate endDate,
      final boolean payAccOnDefault,
      final Period tenor,
      final StubType stubType,
      final ISDACompliantDateYieldCurve yieldCurve,
      final ISDACompliantDateCreditCurve hazardRateCurve,
      final boolean protectStart,
      final PriceType priceType) {
    ArgumentChecker.notNull(today, "null today");
    ArgumentChecker.notNull(stepinDate, "null stepinDate");
    ArgumentChecker.notNull(valueDate, "null valueDate");
    ArgumentChecker.notNull(startDate, "null startDate");
    ArgumentChecker.notNull(endDate, "null endDate");
    ArgumentChecker.notNull(tenor, "null tenor");
    ArgumentChecker.notNull(stubType, "null stubType");
    ArgumentChecker.notNull(yieldCurve, "null yieldCurve");
    ArgumentChecker.notNull(hazardRateCurve, "null hazardRateCurve");
    ArgumentChecker.notNull(priceType, "null priceType");
    ArgumentChecker.isFalse(valueDate.isBefore(today), "Require valueDate >= today");
    ArgumentChecker.isFalse(stepinDate.isBefore(today), "Require stepin >= today");

    final ISDAPremiumLegSchedule paymentSchedule =
        new ISDAPremiumLegSchedule(
            startDate,
            endDate,
            tenor,
            stubType,
            _businessdayAdjustmentConvention,
            _calandar,
            protectStart);
    final int nPayments = paymentSchedule.getNumPayments();

    // these are potentially different from startDate and endDate
    final LocalDate globalAccStart = paymentSchedule.getAccStartDate(0);
    final LocalDate golobalAccEnd = paymentSchedule.getAccEndDate(nPayments - 1);

    // TODO this logic could be part of ISDAPremiumLegSchdule
    final LocalDate matDate = protectStart ? golobalAccEnd.minusDays(1) : golobalAccEnd;

    if (today.isAfter(matDate) || stepinDate.isAfter(matDate)) {
      return 0.0; // trade has expired
    }

    final LocalDate[] yieldCurveDates = yieldCurve.getCurveDates();
    final LocalDate[] creditCurveDates = hazardRateCurve.getCurveDates();
    // This is common to the protection leg
    final LocalDate[] integrationSchedule =
        payAccOnDefault
            ? getIntegrationNodesAsDates(
                globalAccStart, golobalAccEnd, yieldCurveDates, creditCurveDates)
            : null;
    final int obsOffset = protectStart ? -1 : 0; // protection start at the beginning or end day

    double rpv01 = 0.0;
    for (int i = 0; i < nPayments; i++) {

      final LocalDate accStart = paymentSchedule.getAccStartDate(i);
      final LocalDate accEnd = paymentSchedule.getAccEndDate(i);
      final LocalDate pay = paymentSchedule.getPaymentDate(i);

      if (!accEnd.isAfter(stepinDate)) {
        continue; // this cashflow has already been realised
      }

      final double[] temp =
          calculateSinglePeriodRPV01(
              today, accStart, accEnd, pay, obsOffset, yieldCurve, hazardRateCurve);
      rpv01 += temp[0];

      if (payAccOnDefault) {
        final LocalDate offsetStepinDate = stepinDate.plusDays(obsOffset);
        final LocalDate offsetAccStartDate = accStart.plusDays(obsOffset);
        final LocalDate offsetAccEndDate = accEnd.plusDays(obsOffset);
        rpv01 +=
            calculateSinglePeriodAccrualOnDefault(
                today,
                offsetStepinDate,
                offsetAccStartDate,
                offsetAccEndDate,
                temp[1],
                yieldCurve,
                hazardRateCurve,
                integrationSchedule);
      }
    }

    // Compute the discount factor discounting the upfront payment made on the cash settlement date
    // back to the valuation date
    final double t = _curveDayCount.getDayCountFraction(today, valueDate);
    final double df = yieldCurve.getDiscountFactor(t);
    rpv01 /= df;

    // Do we want to calculate the clean price (includes the previously accrued portion of the
    // premium)
    if (priceType == PriceType.CLEAN) {
      rpv01 -= calculateAccruedInterest(paymentSchedule, stepinDate);
    }

    return rpv01;
  }