Thursday, June 4, 2009

Option Profit and Loss in Erlang

Options are a complex game. I was quite surprised at how many of the rules can be expressed in a dozen lines of code. This function calculates the PNL of an options position at the market price of the underlying.

pnl(Px, #position{long = Long, short = Short}) ->
Pnl = [ Px - U#underlying.px || U <- Long#side.underlyings ] ++
[-Px + U#underlying.px || U <- Short#side.underlyings ] ++
[-C#option.px || C <- Long#side.calls, Px =< C#option.strike ] ++
[ C#option.px || C <- Short#side.calls, Px =< C#option.strike ] ++
[-P#option.px || P <- Long#side.puts, Px >= P#option.strike ] ++
[ P#option.px || P <- Short#side.puts, Px >= P#option.strike ] ++
[ Px - C#option.strike - C#option.px || C <- Long#side.calls, Px > C#option.strike ] ++
[-Px + C#option.strike + C#option.px || C <- Short#side.calls, Px > C#option.strike ] ++
[ Px - P#option.strike + P#option.px || P <- Short#side.puts, Px < P#option.strike ] ++
[-Px + P#option.strike - P#option.px || P <- Long#side.puts, Px < P#option.strike ],
lists:sum(Pnl).

Before we dive into the nuts and bolts of this function let's first discuss list comprehensions and how they are written in Erlang. A list comprehension is a way of composing a list from another list. For example, the following line of code creates a list of four integers and doubles every element greater than two.

[ X * 2 || X <- [1,2,3,4], X > 2 ]
% yields [6,8]

This expression can be read as "Double every X taken from [1,2,3,4] where X is greater than 2". Everything to the left of "||" is known as the expression template while everything to the right is known as the generator. The pnl/0 function sums the concatenated results of ten list comprehensions. Each list comprehension is an expression of how the business works. Let's walk through these expressions, one by one. Keep symmetry in your mind along the way ...


Line 1: Long underlyings

[ Px - U#underlying.px || U <- Long#side.underlyings ]
You gain(lose) the market price less the underlying price for every underlying instrument you buy.

Line 2: Short underlyings

[-Px + U#underlying.px || U <- Short#side.underlyings ] 
You gain(lose) the underlying price less the market price for every underlying instrument you sell.

Line 3: Out of the money long calls

[-C#option.px || C <- Long#side.calls,  Px =< C#option.strike ] 
You lose the premium for every call you buy if it expires worthless.

Line 4: Out of the money short calls

[ C#option.px || C <- Short#side.calls, Px =< C#option.strike ] 
You keep the premium for every call you sell if it expires worthless.

Line 5: Out of the money long puts

[-P#option.px || P <- Long#side.puts,   Px >= P#option.strike ] 
You lose the premium for every put you buy if it expires worthless.

Line 6: Out of the money short puts

[ P#option.px || P <- Short#side.puts,  Px >= P#option.strike ] 
You keep the premium for every put you sell that expires worthless.

Line 7: In the money long calls

[ Px - C#option.strike - C#option.px || C <- Long#side.calls,  Px > C#option.strike ] 
You keep the market price less the strike price and premium for every call you buy when the market price exceeds strike price. Bonus points to anyone who has noticed that by this point the function begins a second traversal of the options.

Line 8: In the money short calls

[-Px + C#option.strike + C#option.px || C <- Short#side.calls, Px > C#option.strike ] 
You lose the strike price and the premium less the market price for every call you sell when you are assigned.

Line 9: In the money short puts

[ Px - P#option.strike + P#option.px || P <- Short#side.puts,  Px < P#option.strike ]
You lose market price plus the premium less the strike price for every put you sell when you are assigned.

Line 10: In the money long calls

[-Px + P#option.strike - P#option.px || P <- Long#side.puts,   Px < P#option.strike ]
You keep the strike price less the market price and premium when strike price exceeds market price.

Now let's look at some trends.

Big Risks

pnl(Px, #position{long = Long, short = Short}) ->
Pnl = [ Px - U#underlying.px || U <- Long#side.underlyings ] ++
[-Px + U#underlying.px || U <- Short#side.underlyings ] ++
[-C#option.px || C <- Long#side.calls, Px =< C#option.strike ] ++
[ C#option.px || C <- Short#side.calls, Px =< C#option.strike ] ++
[-P#option.px || P <- Long#side.puts, Px >= P#option.strike ] ++
[ P#option.px || P <- Short#side.puts, Px >= P#option.strike ] ++
[ Px - C#option.strike - C#option.px || C <- Long#side.calls, Px > C#option.strike ] ++
[-Px + C#option.strike + C#option.px || C <- Short#side.calls, Px > C#option.strike ] ++
[ Px - P#option.strike + P#option.px || P <- Short#side.puts, Px < P#option.strike ] ++
[-Px + P#option.strike - P#option.px || P <- Long#side.puts, Px < P#option.strike ],
lists:sum(Pnl).

Big Rewards

pnl(Px, #position{long = Long, short = Short}) ->
Pnl = [ Px - U#underlying.px || U <- Long#side.underlyings ] ++
[-Px + U#underlying.px || U <- Short#side.underlyings ] ++
[-C#option.px || C <- Long#side.calls, Px =< C#option.strike ] ++
[ C#option.px || C <- Short#side.calls, Px =< C#option.strike ] ++
[-P#option.px || P <- Long#side.puts, Px >= P#option.strike ] ++
[ P#option.px || P <- Short#side.puts, Px >= P#option.strike ] ++
[ Px - C#option.strike - C#option.px || C <- Long#side.calls, Px > C#option.strike ] ++
[-Px + C#option.strike + C#option.px || C <- Short#side.calls, Px > C#option.strike ] ++
[ Px - P#option.strike + P#option.px || P <- Short#side.puts, Px < P#option.strike ] ++
[-Px + P#option.strike - P#option.px || P <- Long#side.puts, Px < P#option.strike ],
lists:sum(Pnl).

Out of or at the money

pnl(Px, #position{long = Long, short = Short}) ->
Pnl = [ Px - U#underlying.px || U <- Long#side.underlyings ] ++
[-Px + U#underlying.px || U <- Short#side.underlyings ] ++
[-C#option.px || C <- Long#side.calls, Px =< C#option.strike ] ++
[ C#option.px || C <- Short#side.calls, Px =< C#option.strike ] ++
[-P#option.px || P <- Long#side.puts, Px >= P#option.strike ] ++
[ P#option.px || P <- Short#side.puts, Px >= P#option.strike ] ++
[ Px - C#option.strike - C#option.px || C <- Long#side.calls, Px > C#option.strike ] ++
[-Px + C#option.strike + C#option.px || C <- Short#side.calls, Px > C#option.strike ] ++
[ Px - P#option.strike + P#option.px || P <- Short#side.puts, Px < P#option.strike ] ++
[-Px + P#option.strike - P#option.px || P <- Long#side.puts, Px < P#option.strike ],
lists:sum(Pnl).

In the money options

pnl(Px, #position{long = Long, short = Short}) ->
Pnl = [ Px - U#underlying.px || U <- Long#side.underlyings ] ++
[-Px + U#underlying.px || U <- Short#side.underlyings ] ++
[-C#option.px || C <- Long#side.calls, Px =< C#option.strike ] ++
[ C#option.px || C <- Short#side.calls, Px =< C#option.strike ] ++
[-P#option.px || P <- Long#side.puts, Px >= P#option.strike ] ++
[ P#option.px || P <- Short#side.puts, Px >= P#option.strike ] ++
[ Px - C#option.strike - C#option.px || C <- Long#side.calls, Px > C#option.strike ] ++
[-Px + C#option.strike + C#option.px || C <- Short#side.calls, Px > C#option.strike ] ++
[ Px - P#option.strike + P#option.px || P <- Short#side.puts, Px < P#option.strike ] ++
[-Px + P#option.strike - P#option.px || P <- Long#side.puts, Px < P#option.strike ],
lists:sum(Pnl).

No comments: