Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
use super::funejson::Value; ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::money_amount::{money, money_from_value, money_to_value, Money}; ← from money.amount ^1.0.0 · built alongside by fune
/// amount x 10000 / price, half-up; both 0 or more, price > 0.
fn basis_points(amount: i64, price: i64) -> i64 {
let n = amount as i128 * 10000;
let d = price as i128;
let mut q = n / d;
if 2 * (n - q * d) >= d {
q += 1;
}
q as i64
}
/// Trailing yield from the dividends paid in the last twelve months, and
/// forward yield from the latest regular dividend annualised, both over the
/// current price.
///
/// # Panics
/// Panics on a price of 0 or less, a negative dividend, paymentsPerYear
/// outside 1 to 52, or mixed currencies.
pub fn dividend_yield(price: &Money, trailing_dividends: &[Money], forward_dividend: &Money, payments_per_year: i64) -> DividendYield {
let currency = price.currency.as_str();
if price.minor <= 0 {
panic!("price must be whole minor units greater than zero; received {}", price.minor);
}
if !(1..=52).contains(&payments_per_year) {
panic!("paymentsPerYear must be a whole number from 1 to 52; received {}", payments_per_year);
}
for dividend in trailing_dividends.iter().chain(std::iter::once(forward_dividend)) {
if dividend.currency != currency {
panic!("currency mismatch: {} and {}", currency, dividend.currency);
}
if dividend.minor < 0 {
panic!("dividends must be whole minor units, 0 or more; received {}", dividend.minor);
}
}
let trailing: i64 = trailing_dividends.iter().map(|d| d.minor).sum();
let forward = forward_dividend.minor * payments_per_year;
DividendYield {
trailing_annual: money(trailing, currency),
forward_annual: money(forward, currency),
trailing_basis_points: basis_points(trailing, price.minor),
forward_basis_points: basis_points(forward, price.minor),
}
}
pub fn dividend_yield_to_value(result: &DividendYield) -> Value {
Value::obj(vec![
("trailingAnnual", money_to_value(&result.trailing_annual)),
("forwardAnnual", money_to_value(&result.forward_annual)),
("trailingBasisPoints", Value::Int(result.trailing_basis_points)),
("forwardBasisPoints", Value::Int(result.forward_basis_points)),
])
}
fn fraction(v: &Value) -> Option<f64> {
match v {
Value::Float(f) if f.fract() != 0.0 => Some(*f),
_ => None,
}
}
pub fn fune_vector(args: &[Value]) -> Value {
if let Some(f) = fraction(args[0].get("minor")) {
panic!("price must be whole minor units greater than zero; received {}", f);
}
for v in args[1].as_arr().iter().chain(std::iter::once(&args[2])) {
if let Some(f) = fraction(v.get("minor")) {
panic!("dividends must be whole minor units, 0 or more; received {}", f);
}
}
if let Some(f) = fraction(&args[3]) {
panic!("paymentsPerYear must be a whole number from 1 to 52; received {}", f);
}
let trailing: Vec<Money> = args[1].as_arr().iter().map(money_from_value).collect();
dividend_yield_to_value(÷nd_yield(
&money_from_value(&args[0]),
&trailing,
&money_from_value(&args[2]),
args[3].as_i64(),
))
}