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.
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
$ 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)