/** * Exactly divides this frequency by another. * * <p>This calculates the integer division of this frequency by the specified frequency. If the * result is not an integer, an exception is thrown. * * <p>Month-based and year-based periodic frequencies are calculated by dividing the total number * of months. For example, P6M divided by P3M results in 2, and P2Y divided by P6M returns 4. * * <p>Day-based and week-based periodic frequencies are calculated by dividing the total number of * days. For example, P26W divided by P13W results in 2, and P2W divided by P1D returns 14. * * <p>The 'Term' frequency throws an exception. * * @param other the other frequency to divide into this one * @return this frequency divided by the other frequency * @throws IllegalArgumentException if the frequency does not exactly divide into this one */ public int exactDivide(Frequency other) { ArgChecker.notNull(other, "other"); if (isMonthBased() && other.isMonthBased()) { long paymentMonths = getPeriod().toTotalMonths(); long accrualMonths = other.getPeriod().toTotalMonths(); if ((paymentMonths % accrualMonths) == 0) { return Math.toIntExact(paymentMonths / accrualMonths); } } else if (period.toTotalMonths() == 0 && other.period.toTotalMonths() == 0) { long paymentDays = getPeriod().getDays(); long accrualDays = other.getPeriod().getDays(); if ((paymentDays % accrualDays) == 0) { return Math.toIntExact(paymentDays / accrualDays); } } throw new IllegalArgumentException( Messages.format("Frequency '{}' is not a multiple of '{}'", this, other)); }
/** * Make a set of standard CDS represented as a MultiCdsAnalytic instance. The first CDS with have * a tenor of firstTenor, while the last CDS will have a tenor of lastTenor; the remaining CDS * will consist of all the (multiple of 3 month) tenors between the first and last tenor, e.g. if * firstTenor = 6M and lastTenor = 5Y, there will be a total of 22 CDS with tenors of 6M, 9M, * 1Y,....4Y9M, 5Y. * * @param tradeDate the trade date * @param firstTenor the first tenor * @param lastTenor the last tenor * @return a set of CDS represented as a MultiCdsAnalytic */ public MultiCdsAnalytic makeMultiImmCds( LocalDate tradeDate, Period firstTenor, Period lastTenor) { ArgChecker.notNull(firstTenor, "firstTenor"); ArgChecker.notNull(lastTenor, "lastTenor"); int immNMonths = (int) DEFAULT_COUPON_INT.toTotalMonths(); int m1 = (int) firstTenor.toTotalMonths(); int m2 = (int) lastTenor.toTotalMonths(); if (m1 % immNMonths != 0 || m2 % immNMonths != 0) { throw new IllegalArgumentException( "tenors is not a multiple of " + DEFAULT_COUPON_INT.toString()); } int firstIndex = m1 / immNMonths; int lastIndex = m2 / immNMonths; return makeMultiImmCds(tradeDate, firstIndex, lastIndex); }
/** * Subtracts the period of this frequency from the specified date. * * <p>This method implements {@link TemporalAmount}. It is not intended to be called directly. Use * {@link LocalDate#minus(TemporalAmount)} instead. * * @param temporal the temporal object to subtract from * @return the result with this frequency subtracted * @throws DateTimeException if unable to subtract * @throws ArithmeticException if numeric overflow occurs */ @Override public Temporal subtractFrom(Temporal temporal) { // special case for performance if (temporal instanceof LocalDate) { LocalDate date = (LocalDate) temporal; return date.minusMonths(period.toTotalMonths()).minusDays(period.getDays()); } return period.subtractFrom(temporal); }
/** * Adds the period of this frequency to the specified date. * * <p>This method implements {@link TemporalAmount}. It is not intended to be called directly. Use * {@link LocalDate#plus(TemporalAmount)} instead. * * @param temporal the temporal object to add to * @return the result with this frequency added * @throws DateTimeException if unable to add * @throws ArithmeticException if numeric overflow occurs */ @Override public Temporal addTo(Temporal temporal) { // special case for performance if (temporal instanceof LocalDate) { LocalDate date = (LocalDate) temporal; return date.plusMonths(period.toTotalMonths()).plusDays(period.getDays()); } return period.addTo(temporal); }
/** * Obtains a periodic frequency from a {@code Period}. * * <p>The period normally consists of either days and weeks, or months and years. It must also be * positive and non-zero. * * <p>If the number of days is an exact multiple of 7 it will be converted to weeks. Months are * not normalized into years. * * <p>The maximum tenor length is 1,000 years. * * @param period the period to convert to a periodic frequency * @return the periodic frequency * @throws IllegalArgumentException if the period is negative, zero or too large */ public static Frequency of(Period period) { ArgChecker.notNull(period, "period"); int days = period.getDays(); long months = period.toTotalMonths(); if (months == 0 && days != 0) { return ofDays(days); } if (months > MAX_MONTHS) { throw new IllegalArgumentException("Period must not exceed 1000 years"); } return new Frequency(period); }
private String readablePeriod(Period period) { if (period.isZero()) return "Hoy"; String startsWith = period.isNegative() ? "Hace " : "En "; long months = Math.abs(period.toTotalMonths()); int days = Math.abs(period.getDays()); if (Math.abs(months) > 0) { String endsWith = (months > 1) ? "es" : ""; return startsWith + months + " mes" + endsWith; } else { String endsWith = (days > 1) ? "s" : ""; return startsWith + days + " dia" + endsWith; } }
/** * Calculates the number of events that occur in a year. * * <p>The number of events per year is the number of times that the period occurs per year. Not * all periodic frequency instances can be converted to an integer events per year. All constants * declared on this class will return a result. * * <p>Month-based and year-based periodic frequencies are converted by dividing 12 by the number * of months. Only the following periodic frequencies return a value - P1M, P2M, P3M, P4M, P6M, * P1Y. * * <p>Day-based and week-based periodic frequencies are converted by dividing 364 by the number of * days. Only the following periodic frequencies return a value - P1D, P2D, P4D, P1W, P2W, P4W, * P13W, P26W, P52W. * * <p>The 'Term' periodic frequency returns zero. * * @return the number of events per year * @throws IllegalArgumentException if unable to calculate the number of events per year */ public int eventsPerYear() { if (isTerm()) { return 0; } long months = period.toTotalMonths(); int days = period.getDays(); if (isMonthBased()) { if (12 % months == 0) { return (int) (12 / months); } } else if (months == 0 && 364 % days == 0) { return (int) (364 / days); } throw new IllegalArgumentException("Unable to calculate events per year: " + this); }
/** * Make a set of standard CDS represented as a MultiCdsAnalytic instance. * * @param tradeDate the trade date * @param accStartDate the accrual start date * @param tenors the tenors (length) of the CDS * @return a set of CDS represented as a MultiCdsAnalytic */ public MultiCdsAnalytic makeMultiImmCds( LocalDate tradeDate, LocalDate accStartDate, Period[] tenors) { ArgChecker.noNulls(tenors, "tenors"); int n = tenors.length; int immNMonths = (int) DEFAULT_COUPON_INT.toTotalMonths(); int[] matIndices = new int[n]; for (int i = 0; i < n; i++) { int months = (int) tenors[i].toTotalMonths(); if (months % immNMonths != 0) { throw new IllegalArgumentException( "tenors index " + i + " is not a multiple of " + DEFAULT_COUPON_INT.toString()); } matIndices[i] = months / immNMonths; } return makeMultiImmCds(tradeDate, accStartDate, matIndices); }
private LocalDate getMaxMonthsThresholdDate(ExcelRow item) { LocalDate result = null; if (item.getDate() != null) { if (firstDate == null || firstDate.isAfter(item.getDate())) { firstDate = item.getDate(); } final LocalDate startDate = firstDate; final LocalDate endDate = LocalDate.now(); final Period period = Period.between(startDate, endDate); /** If the period between the first date and today is greater or equal to maxNumberOfMonth */ if (period.toTotalMonths() >= maxNumberOfMonth) { result = endDate; } } return result; }
/** * Checks if the periodic frequency is month-based. * * <p>A month-based frequency consists of an integral number of months. Any year-based frequency * is also counted as month-based. There must be no day or week element. * * @return true if this is month-based */ public boolean isMonthBased() { return period.toTotalMonths() > 0 && period.getDays() == 0 && isTerm() == false; }
/** * Checks if the periodic frequency is week-based. * * <p>A week-based frequency consists of an integral number of weeks. There must be no day, month * or year element. * * @return true if this is week-based */ public boolean isWeekBased() { return period.toTotalMonths() == 0 && period.getDays() % 7 == 0; }