Option Strategies

Butterfly Spread


A Butterfly Spread strategy involves trading four option contracts with the same expiration but three different strike prices. There are four kinds of Butterfly Spread:

Name Strategy
Long butterfly spread with calls Buy 1 ITM call, sell 2 ATM call, buy 1 OTM call
Long butterfly spread with puts Buy 1 ITM put, sell 2 ATM put, buy 1 OTM put
Short butterfly spread with calls Sell 1 ITM call, buy 2 ATM call, sell 1 OTM call
Short butterfly spread with puts Buy 1 ITM put, sell 2 ATM put, buy 1 OTM put

A Butterfly Spread consists of three legs with a total of four options. In this tutorial, we use the Long Butterfly Spread as an example: long one ITM call, short two ATM calls and long one OTM call. All the calls have the same expiration. On the other hand, the middle strike is halfway between the lower and the higher strikes.

The aim of a Butterfly Spread strategy is for a trader to profit from marginal price changes in the underlying stock in either direction.

butterfly spread strategy payoff


Follow these steps to implement a bull butterfly spread with calls strategy.

  1. In the Initialize method, set the start date, end date, cash, and Option universe.
  2. private Symbol _symbol;
    public override void Initialize()
        SetStartDate(2017, 4, 1);
        SetEndDate(2017, 5, 30);
        var option = AddOption("GOOG", Resolution.Minute);
        _symbol = option.Symbol;
        option.SetFilter(-9, 9, TimeSpan.FromDays(30), TimeSpan.FromDays(60));
    def Initialize(self) -> None:
        self.SetStartDate(2017, 4, 1)
        self.SetEndDate(2017, 5, 30)
        option = self.AddOption("GOOG", Resolution.Minute)
        self.symbol = option.Symbol
        option.SetFilter(-9, 9, timedelta(30), timedelta(60))
  3. In the OnData method, select the Option contracts.
  4. public override void OnData(Slice slice)
        // avoid extra orders
        if (Portfolio.Invested) return;
        // Get the OptionChain of the symbol
        var chain = slice.OptionChains.get(_symbol, null);
        if (chain == null || chain.Count() == 0) return;
        // sorted the optionchain by expiration date and choose the furthest date
        var expiry = chain.OrderBy(x => x.Expiry).Last().Expiry;
        // filter the call options from the contracts expires on that date
        var calls = chain.Where(x => x.Expiry == expiry && x.Right == OptionRight.Call);
        // sorted the contracts according to their strike prices
        var callContracts = calls.OrderBy(x => x.Strike);
        if (callContracts.Count() == 0) return;
        // choose OTM call
        var otmCall = callContracts.Last();
        // choose ITM call
        var itmCall = callContracts.First();
        // choose ATM call
        var atmCall = callContracts.OrderBy(x => Math.Abs(chain.Underlying.Price - x.Strike)).First();
    def OnData(self, slice: Slice) -> None:
        # avoid extra orders
        if self.Portfolio.Invested: return
        # Get the OptionChain of the self.symbol
        chain = slice.OptionChains.get(self.symbol, None)
        if not chain: return
        # sorted the optionchain by expiration date and choose the furthest date
        expiry = sorted(chain, key = lambda x: x.Expiry, reverse=True)[0].Expiry
        # filter the call options from the contracts expires on that date
        calls = [i for i in chain if i.Expiry == expiry and i.Right == 0]
        # sorted the contracts according to their strike prices
        call_contracts = sorted(calls, key = lambda x: x.Strike)
        if len(call_contracts) == 0: return
        # choose OTM call
        self.otm_call = call_contracts[-1]
        # choose ITM call
        self.itm_call = call_contracts[0]
        # choose ATM call
        self.atm_call = sorted(call_contracts, key = lambda x: abs(chain.Underlying.Price - x.Strike))[0]
  5. In the OnData method, buy the ITM and OTM calls.
  6.     Sell(atmCall.Symbol, 2);
        Buy(itmCall.Symbol, 1);
        Buy(otmCall.Symbol, 1);
    self.Sell(self.atm_call.Symbol, 2)
    self.Buy(self.itm_call.Symbol, 1)
    self.Buy(self.otm_call.Symbol, 1)


From the following algorithm, at time 0, the GOOG share price is $832.8. We purchase 1 OTM call option with strike price $855, 1 ITM call option with strike price $810 and sell 2 ATM options with strike prices at 835. At the expiry 05/19/2017, the share price is $930 and so the long positions of the ITM option and the OTM option are exercised: we buy 100 GOOG shares at $810 and buy another 100 shares at $855. At the same time, the 2 short positions of the ATM option are also exercised: we sell 200 GOOG shares to the option holder at $835. After the expiration date, we don't hold any shares of the underlying. Since the stock price had a sharp increase during the life of options, we fail to profit from a Long Call Butterfly Spread.


Backtest using SetFilter

Backtest using OptionChainProvider

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: