soma.cell

European option payoffs at expiry, plus a long straddle

max()/min() of two numbers, records for the trade leg, tolerance asserts.

A Soma program from the finance part of the verified corpus: 56 lines, cells OptionPayoff, OptionTests. It passes soma check with soma 3.2.4.

How it is built

The cell OptionPayoff declares 5 signals in its face: call_payoff(spot: Float, strike: Float) -> Float, put_payoff(spot: Float, strike: Float) -> Float, call_pnl(spot: Float, strike: Float, premium: Float) -> Float, straddle_pnl(spot: Float, strike: Float, call_prem: Float, put_prem: Float) -> Float and breakeven_call(strike: Float, premium: Float) -> Float. Handlers: call_payoff (line 14), put_payoff (line 19), call_pnl (line 24), straddle_pnl (line 29) and breakeven_call (line 34).

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

Generated from soma describe on this file.

The source

option_payoff.cell

// European option payoffs at expiry, plus a long straddle.
// max()/min() of two numbers, records for the trade leg, tolerance asserts.

cell OptionPayoff {
    face {
        signal call_payoff(spot: Float, strike: Float) -> Float
        signal put_payoff(spot: Float, strike: Float) -> Float
        signal call_pnl(spot: Float, strike: Float, premium: Float) -> Float
        signal straddle_pnl(spot: Float, strike: Float, call_prem: Float, put_prem: Float) -> Float
        signal breakeven_call(strike: Float, premium: Float) -> Float
    }

    // long call payoff = max(S - K, 0)
    on call_payoff(spot: Float, strike: Float) {
        return max(spot - strike, 0.0)
    }

    // long put payoff = max(K - S, 0)
    on put_payoff(spot: Float, strike: Float) {
        return max(strike - spot, 0.0)
    }

    // P&L = payoff - premium paid
    on call_pnl(spot: Float, strike: Float, premium: Float) {
        return call_payoff(spot, strike) - premium
    }

    // long straddle = call + put, minus both premiums
    on straddle_pnl(spot: Float, strike: Float, call_prem: Float, put_prem: Float) {
        let gross = call_payoff(spot, strike) + put_payoff(spot, strike)
        return gross - call_prem - put_prem
    }

    on breakeven_call(strike: Float, premium: Float) {
        return strike + premium
    }
}

cell test OptionTests {
    rules {
        // in-the-money call
        assert abs(call_payoff(110.0, 100.0) - 10.0) < 0.0001
        // out-of-the-money call pays nothing
        assert abs(call_payoff(90.0, 100.0) - 0.0) < 0.0001
        // put intrinsic
        assert abs(put_payoff(90.0, 100.0) - 10.0) < 0.0001
        // call P&L can be negative (premium lost)
        assert call_pnl(101.0, 100.0, 5.0) < 0.0
        // straddle profits on a big move
        assert straddle_pnl(130.0, 100.0, 5.0, 5.0) > 0.0
        // and loses near the strike
        assert straddle_pnl(100.0, 100.0, 5.0, 5.0) < 0.0
        assert abs(breakeven_call(100.0, 5.0) - 105.0) < 0.0001
    }
}

What the toolchain says

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

$ soma check option_payoff.cell
✓ All checks passed.
$ soma test option_payoff.cell
test OptionTests ...
  ✓ assert abs(call_payoff(110.0, 100.0) - 10.0) < 0.0001
  ✓ assert abs(call_payoff(90.0, 100.0) - 0.0) < 0.0001
  ✓ assert abs(put_payoff(90.0, 100.0) - 10.0) < 0.0001
  ✓ assert call_pnl(101.0, 100.0, 5.0) < 0.0
  ✓ assert straddle_pnl(130.0, 100.0, 5.0, 5.0) > 0.0
  ✓ assert straddle_pnl(100.0, 100.0, 5.0, 5.0) < 0.0
  ✓ assert abs(breakeven_call(100.0, 5.0) - 105.0) < 0.0001

7 tests: 7 passed, 0 failed
$ soma verify option_payoff.cell
Verifying option_payoff.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, max

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