Financial functions

ODDLPRICE

Matches all 6 recorded answers

Recorded: 6 workbook cells. How we measure this · See the Rust code

Local names in 40 languages
LanguageName in Excel
ArabicODDLPRICE
BulgarianODDLPRICE
CzechODDLPRICE
DanishULIGE.SIDSTE.KURS
GermanODDLPRICE
GreekODDLPRICE
English (Australia)ODDLPRICE
English (United Kingdom)ODDLPRICE
English (United States)ODDLPRICE
SpanishPRECIO.PER.IRREGULAR.2
EstonianODDLPRICE
FinnishPARITON.VIIM.NIMELLISARVO
FrenchPRIX.DCOUPON.IRREG
HebrewODDLPRICE
CroatianODDLPRICE
HungarianELTÉRŐ.UÁR
IndonesianODDLPRICE
ItalianODDLPRICE
JapaneseODDLPRICE
KoreanODDLPRICE
LithuanianODDLPRICE
LatvianODDLPRICE
NorwegianAVVIKSP.PRIS
DutchAFW.LT.PRIJS
PolishCENA.OST.OKR
Portuguese (Brazil)ODDLPRICE
Portuguese (Portugal)PREÇOÚLTINC
RomanianODDLPRICE
RussianЦЕНАПОСЛНЕРЕГ
SlovakODDLPRICE
SlovenianODDLPRICE
Serbian (Latin)ODDLPRICE
SwedishUDDASPRIS
ThaiODDLPRICE
TurkishTEKSDEĞER işlevi
UkrainianODDLPRICE
VietnameseODDLPRICE
Chinese (Simplified)ODDLPRICE
Chinese (Hong Kong)ODDLPRICE
Chinese (Traditional)ODDLPRICE

Names from Microsoft's support site.

What it does

ODDLPRICE(settlement, maturity, last_interest, rate, yld, redemption, frequency, [basis])

ODDLPRICE computes clean price per 100 face value for a security with an irregular last coupon. Its dates are settlement, maturity and last_interest. They are followed by coupon rate, yield, redemption, frequency and optional basis.

Try it

Input cells (optional)

Example: {"B2": 3, "B3": 4}. A1 holds the formula. Other cells need values before a formula can read them.

Enter a formula, then calculate.

Runs locally in your browser with OneCalc. Its answer may differ from Excel. Use English function names and commas between arguments.

=ODDLPRICE(DATE(2027,8,1),DATE(2027,11,1),DATE(2027,4,1),0.06,0,100,2,0) gives a price near 101.5. The last coupon spans April to November, seven 30/360 months. Its coupon is 3.5 and accrued interest at August settlement is two. At zero yield the clean price is 100+3.5-2=101.5.

Quirks

Basis defaults to zero: 0 US 30/360, 1 actual/actual, 2 actual/360, 3 actual/365, 4 European 30/360. Dates and selectors are truncated under their documented rules. Use DATE values rather than locale-dependent date text. The required date order is last_interest < settlement < maturity. Frequency is one, two or four. Negative coupon rate, invalid selectors and invalid amount/domain cases produce errors. These schedules cannot be reduced to PRICE by changing one date.

How to implement

Generate quasi-coupon periods forward from last_interest through maturity. Sum the normalized full odd-period fraction, accrued fraction and settlement-to-maturity fraction. Form the final coupon and redemption under the simple-discount denominator, then subtract accrued interest. The worked zero-yield example isolates the coupon and accrual arithmetic from discount powers. Calendar seams, long/short-period branches and residual numerical differences remain open where the recorded reports say so. The family combines a credited Apache-licensed ExcelFinancialFunctions translation in its odd-first kernel and calendar helpers with project-owned kernels and changes guided by recorded Excel answers.

Rust code

Show the CalcFunc source of this function

Quoted from the public repository DnaCalc/DnaCalc, crates calc-func and calc-fml, at commit 9e1884369a67. Comments are the source's own. A kernel shared with other functions appears once, on its module page.

ODDLPRICE · 4 lines · calc-func/src/catalogue/bonds.rs on GitHub
25 oddlprice_fn "ODDLPRICE" (7, 8) [V "settlement", V "maturity", V "last_interest", V "rate", V "yld", V "redemption", V "frequency", V "basis"] |s, a, sv| {
    let dates = [date_1900(s, a, 0, sv)?, date_1900(s, a, 1, sv)?, date_1900(s, a, 2, sv)?];
    odd_out(s, odd::oddlprice_kernel(dates[0], dates[1], dates[2], num(s, a, 3)?, num(s, a, 4)?, num(s, a, 5)?, num(s, a, 6)?, basis(s, a, 7)?))
}
oddlprice_kernel · 87 lines · calc-func/src/ported/odd_bond_family.rs on GitHub
pub fn oddlprice_kernel(
    settlement: f64,
    maturity: f64,
    last_interest: f64,
    rate: f64,
    yld: f64,
    redemption: f64,
    frequency: f64,
    basis: Option<f64>,
) -> Result<f64, OddBondEvalError> {
    validate_positive_inputs(&[
        settlement,
        maturity,
        last_interest,
        rate,
        yld,
        redemption,
        frequency,
    ])?;
    if rate < 0.0 || yld < 0.0 || redemption <= 0.0 {
        return Err(OddBondEvalError::Domain(WorksheetErrorCode::Num));
    }
    let settlement = parse_date_serial(settlement)?;
    let maturity = parse_date_serial(maturity)?;
    let last_interest = parse_date_serial(last_interest)?;
    let frequency = parse_frequency(frequency)?;
    let basis = parse_basis(basis.unwrap_or(0.0))?;
    if !(last_interest < settlement && settlement < maturity) {
        return Err(OddBondEvalError::Domain(WorksheetErrorCode::Num));
    }

    let months_per_coupon = 12 / frequency;
    let mut nc = 0i64;
    let mut cursor = last_interest;
    while cursor < maturity {
        cursor = add_months_clamped(cursor, months_per_coupon)
            .ok_or(OddBondEvalError::Domain(WorksheetErrorCode::Num))?;
        nc += 1;
        if nc > 64 {
            return Err(OddBondEvalError::Domain(WorksheetErrorCode::Num));
        }
    }
    let mut early_coupon = last_interest;
    let mut dcnl = 0.0;
    let mut anl = 0.0;
    let mut dscnl = 0.0;
    for index in 1..=nc {
        let late_coupon = add_months_clamped(early_coupon, months_per_coupon)
            .ok_or(OddBondEvalError::Domain(WorksheetErrorCode::Num))?;
        let nl = day_count_non_negative_with_us_hack(early_coupon, late_coupon, basis)?;
        if nl <= 0.0 {
            return Err(OddBondEvalError::Domain(WorksheetErrorCode::Num));
        }
        let dci = if index < nc {
            nl
        } else {
            day_count_non_negative_with_us_hack(early_coupon, maturity, basis)?
        };
        let a = if late_coupon < settlement {
            dci
        } else if early_coupon < settlement {
            day_count_non_negative(early_coupon, settlement, basis)?
        } else {
            0.0
        };
        let start_date = settlement.max(early_coupon);
        let end_date = maturity.min(late_coupon);
        let dsc = day_count_non_negative(start_date, end_date, basis)?;
        early_coupon = late_coupon;
        dcnl += dci / nl;
        anl += a / nl;
        dscnl += dsc / nl;
    }
    if dscnl <= 0.0 {
        return Err(OddBondEvalError::Domain(WorksheetErrorCode::Num));
    }
    let x = 100.0 * rate / frequency as f64;
    let term1 = dcnl * x + redemption;
    let term2 = dscnl * yld / frequency as f64 + 1.0;
    let term3 = anl * x;
    let price = term1 / term2 - term3;
    if price.is_finite() {
        Ok(price)
    } else {
        Err(OddBondEvalError::Domain(WorksheetErrorCode::Num))
    }
}

Kernels shared with other functions

Argument and result plumbing

  • fail catalogue/kit
  • num catalogue/kit

No implementation has been published with a Handbook test suite for this function.

Version differences

No same-input comparison between named Excel builds is recorded for this function here. The documented behaviour below is not a measurement of every Excel release.

Alternatives

ODDLYIELD solves yield from the same last-coupon schedule. ODDFPRICE handles an irregular first coupon; PRICE handles regular coupons.

Named variants

No named variants are recorded yet.

Suggest a correction or contribute an implementation · For agents