soma.cell

Equity income metrics: dividend yield, payout ratio, dividend-discount

(Gordon growth) fair value, and yield-on-cost. Straightforward ratios with guards against division by zero.

A Soma program from the finance part of the verified corpus: 49 lines, cells DividendMetrics, DividendTests. It passes soma check with soma 3.2.4.

How it is built

The cell DividendMetrics declares 4 signals in its face: yield_pct(annual_div: Float, price: Float) -> Float, payout_ratio(annual_div: Float, eps: Float) -> Float, gordon_value(next_div: Float, discount: Float, growth: Float) -> Float and yield_on_cost(annual_div: Float, cost_basis: Float) -> Float. Handlers: yield_pct (line 13), payout_ratio (line 18), gordon_value (line 24) and yield_on_cost (line 29).

The file also holds 1 test cell (DividendTests) with 5 assertions, run by soma test.

Generated from soma describe on this file.

The source

dividend_yield.cell

// Equity income metrics: dividend yield, payout ratio, dividend-discount
// (Gordon growth) fair value, and yield-on-cost. Straightforward ratios
// with guards against division by zero.

cell DividendMetrics {
    face {
        signal yield_pct(annual_div: Float, price: Float) -> Float
        signal payout_ratio(annual_div: Float, eps: Float) -> Float
        signal gordon_value(next_div: Float, discount: Float, growth: Float) -> Float
        signal yield_on_cost(annual_div: Float, cost_basis: Float) -> Float
    }

    on yield_pct(annual_div: Float, price: Float) {
        if price == 0.0 { return 0.0 }
        return annual_div / price * 100.0
    }

    on payout_ratio(annual_div: Float, eps: Float) {
        if eps == 0.0 { return 0.0 }
        return annual_div / eps
    }

    // Gordon growth: V = D1 / (k - g), valid only when k > g
    on gordon_value(next_div: Float, discount: Float, growth: Float) {
        if discount <= growth { return 0.0 }
        return next_div / (discount - growth)
    }

    on yield_on_cost(annual_div: Float, cost_basis: Float) {
        if cost_basis == 0.0 { return 0.0 }
        return annual_div / cost_basis * 100.0
    }
}

cell test DividendTests {
    rules {
        // $2 div on a $50 stock = 4%
        assert abs(yield_pct(2.0, 50.0) - 4.0) < 0.0001
        // $2 div on $5 EPS = 40% payout
        assert abs(payout_ratio(2.0, 5.0) - 0.40) < 0.0001
        // Gordon: D1=2, k=8%, g=3% → 2/0.05 = 40
        assert abs(gordon_value(2.0, 0.08, 0.03) - 40.0) < 0.0001
        // degenerate Gordon (k <= g) guarded to 0
        assert abs(gordon_value(2.0, 0.03, 0.08)) < 0.0001
        // yield on cost beats current yield when bought cheaper
        assert yield_on_cost(2.0, 25.0) > yield_pct(2.0, 50.0)
    }
}

What the toolchain says

Run on a fresh copy of the program at build time; the outputs are pasted unedited.

$ soma check dividend_yield.cell
✓ All checks passed.
$ soma test dividend_yield.cell
test DividendTests ...
  ✓ assert abs(yield_pct(2.0, 50.0) - 4.0) < 0.0001
  ✓ assert abs(payout_ratio(2.0, 5.0) - 0.40) < 0.0001
  ✓ assert abs(gordon_value(2.0, 0.08, 0.03) - 40.0) < 0.0001
  ✓ assert abs(gordon_value(2.0, 0.03, 0.08)) < 0.0001
  ✓ assert yield_on_cost(2.0, 25.0) > yield_pct(2.0, 50.0)

5 tests: 5 passed, 0 failed
$ soma verify dividend_yield.cell
Verifying dividend_yield.cell...
No state machine in this program: nothing to prove beyond `soma check` (invariants and lifecycles are what verify proves).
VERIFY OK (vacuous — no state machine)

Builtins used

abs

Source file: /corpus/finance/dividend_yield.cell · examples/corpus/finance/dividend_yield.cell