Overall Statistics
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Common")

from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from datetime import timedelta
from decimal import Decimal
from functools import reduce

import QuantConnect.Securities.Option
import QuantConnect.Securities.Equity
from QuantConnect.Securities.Option import OptionHolding
from QuantConnect.Securities.Equity import EquityHolding


class GaboOptionsIssues04(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2016, 3, 27)
        self.SetEndDate(2016, 4, 5)
        # self.SetEndDate(2016, 6, 30)
        self.SetCash(100000)

        self.option = self.AddOption("GOOG")
        self.equity = self.AddEquity("GOOG", Resolution.Minute)

        self.slice = None

        # set our strike/expiry filter for this option chain
        self.option.SetFilter(-10000000, +0, timedelta(14), timedelta(50))


        # use the underlying equity as the benchmark
        self.SetBenchmark("GOOG")

        self.Schedule.On(
            self.DateRules.EveryDay(self.option.Symbol.Value),
            self.TimeRules.AfterMarketOpen(
                self.option.Symbol.Value,
                200),
            Action(self.buy_underlying)
        )
        
        self.Schedule.On(
            self.DateRules.MonthStart(self.option.Symbol.Value),
            self.TimeRules.BeforeMarketClose(
                self.option.Symbol.Value,
                40),
            Action(self.buy_option)
        )

    def buy_underlying(self):
        if not self.Securities[self.equity.Symbol.Value].Invested:
            buy_pct = 0.95
            self.Log('Buying %f%% of %s' % (buy_pct, self.equity.Symbol.Value))
            self.SetHoldings(self.equity.Symbol.Value, buy_pct)
            
        return
    
    def buy_option(self):
        self.Log('On buy_option method')
        
        underlaying_chains = list(filter(
            lambda chain: chain.Key.Underlying == self.equity.Symbol,
            self.slice.OptionChains,
        ))
        
        if len(underlaying_chains) == 0:
            self.Log('No option contract for underlying %s.' %
                             self.underlying.Symbol.Value)
            return
        
        underlying_chain = underlaying_chains[0].Value
        
        # Keep only the puts
        puts = list(filter(
            lambda opt: opt.Right == OptionRight.Put,
            underlying_chain,
        ))
        
        # Compute the min and max strike price
        underlying_price = self.equity.Price
        min_strike = underlying_price * Decimal(.8)
        max_strike = underlying_price * Decimal(.9)
        
        # Keep the option between the threshold strikes
        opt_in_strike = list(filter(
            lambda opt: opt.Strike >= min_strike and \
                opt.Strike <= max_strike,
            puts,
        ))
        
        # Filter options without volume
        opt_volume = list(filter(
            lambda opt: opt.Volume > 0,
            opt_in_strike,
        ))
        
        # Sort by priority
        priority_contracts = sorted(
            opt_volume,
            key=lambda opt: opt.Volume,
            reverse=True,
        )
        
        if len(priority_contracts) == 0:
            self.Log('No option volume')
            return
        
        contract = priority_contracts[0]
        qty = 1
        self.Log('Buy %d lot of %s' % (qty, contract.Symbol.Value))
        self.MarketOrder(contract.Symbol.Value, qty)
    
    def OnData(self, slice):
        self.slice = slice