Beispiel #1
0
    def find_eligible_contracts(self,
                                symbol,
                                right,
                                min_strike=0,
                                excluded_expirations=[]):
        click.echo()
        click.secho(
            f"Searching option chain for symbol={symbol} right={right}, this can take a while...",
            fg="green",
        )
        click.echo()
        stock = Stock(symbol, "SMART", currency="USD")
        contracts = self.ib.qualifyContracts(stock)

        [ticker] = self.ib.reqTickers(stock)
        tickerValue = ticker.marketPrice()

        chains = self.ib.reqSecDefOptParams(stock.symbol, "", stock.secType,
                                            stock.conId)
        chain = next(c for c in chains if c.exchange == "SMART")

        def valid_strike(strike):
            if right.startswith("P"):
                return strike <= tickerValue
            if right.startswith("C"):
                return strike >= tickerValue and strike >= min_strike
            return False

        chain_expirations = self.config["option_chains"]["expirations"]

        strikes = sorted(strike for strike in chain.strikes
                         if valid_strike(strike))
        expirations = sorted(
            exp for exp in chain.expirations
            if option_dte(exp) >= self.config["target"]["dte"]
            and exp not in excluded_expirations)[:chain_expirations]
        rights = [right]

        def nearest_strikes(strikes):
            chain_strikes = self.config["option_chains"]["strikes"]
            if right.startswith("P"):
                return strikes[-chain_strikes:]
            if right.startswith("C"):
                return strikes[:chain_strikes]

        contracts = [
            Option(
                symbol,
                expiration,
                strike,
                right,
                "SMART",
                tradingClass=chain.tradingClass,
            ) for right in rights for expiration in expirations
            for strike in nearest_strikes(strikes)
        ]

        contracts = self.ib.qualifyContracts(*contracts)

        tickers = self.ib.reqTickers(*contracts)

        # Filter out tickers which don't have a midpoint price
        tickers = [t for t in tickers if not util.isNan(t.midpoint())]

        def open_interest_is_valid(ticker):
            ticker = self.ib.reqMktData(ticker.contract, genericTickList="101")

            def open_interest_is_not_ready():
                if right.startswith("P"):
                    return util.isNan(ticker.putOpenInterest)
                if right.startswith("C"):
                    return util.isNan(ticker.callOpenInterest)

            try:
                while_n_times(
                    open_interest_is_not_ready,
                    lambda: self.ib.waitOnUpdate(timeout=5),
                    25,
                )
            except:
                return False

            self.ib.cancelMktData(ticker.contract)

            # The open interest value is never present when using historical
            # data, so just ignore it when the value is None
            if right.startswith("P"):
                return (ticker.putOpenInterest >=
                        self.config["target"]["minimum_open_interest"])
            if right.startswith("C"):
                return (ticker.callOpenInterest >=
                        self.config["target"]["minimum_open_interest"])

        def delta_is_valid(ticker):
            return (ticker.modelGreeks
                    and not util.isNan(ticker.modelGreeks.delta)
                    and abs(ticker.modelGreeks.delta) <= get_target_delta(
                        self.config, symbol, right))

        # Filter by delta and open interest
        tickers = [ticker for ticker in tickers if delta_is_valid(ticker)]
        tickers = [
            ticker for ticker in tickers if open_interest_is_valid(ticker)
        ]
        tickers = sorted(
            reversed(sorted(tickers, key=lambda t: abs(t.modelGreeks.delta))),
            key=lambda t: option_dte(t.contract.lastTradeDateOrContractMonth),
        )

        if len(tickers) == 0:
            raise RuntimeError(
                f"No valid contracts found for {symbol}. Aborting.")

        # Return the first result
        return tickers[0]
Beispiel #2
0
#     asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
    from ib_insync.contract import Stock, Forex, Index, Option, Future, CFD
    asyncio.get_event_loop().set_debug(True)
    util.logToConsole(logging.DEBUG)
    ib = IB()
    ib.connect('127.0.0.1', 7497, clientId=21)

    aex = Index('EOE', 'FTA')
    eurusd = Forex('EURUSD')
    intc = Stock('INTC', 'SMART', 'USD', primaryExchange='NASDAQ')
    amd = Stock('AMD', 'SMART', 'USD')
    aapl = Stock('AAPL', 'SMART', 'USD')
    tsla = Stock('TSLA', 'SMART', 'USD')
    spy = Stock('SPY', 'ARCA')
    wrongContract = Forex('lalala')
    option = Option('EOE', '20171215', 490, 'P', 'FTA', multiplier=100)

    if 0:
        cds = ib.reqContractDetails(aex)
        print(cds)
        cd = cds[0]
        print(cd)
        conId = cd.summary.conId
        ib.qualifyContracts(aex, eurusd, intc)
        print(aex, eurusd, intc)
        print(ib.reqContractDetails(wrongContract))
    if 0:
        sub = ScannerSubscription(instrument='FUT.US',
                locationCode='FUT.GLOBEX', scanCode='TOP_PERC_GAIN')
        print(ib.reqScannerData(sub, []))
        print(len(ib.reqScannerParameters()))
Beispiel #3
0
    def find_eligible_contracts(self, symbol, right):
        stock = Stock(symbol, "SMART", currency="USD")
        contracts = self.ib.qualifyContracts(stock)

        [ticker] = self.ib.reqTickers(stock)
        tickerValue = ticker.marketPrice()

        chains = self.ib.reqSecDefOptParams(
            stock.symbol, "", stock.secType, stock.conId
        )
        chain = next(c for c in chains if c.exchange == "SMART")

        def valid_strike(strike):
            if right.startswith("P"):
                return strike <= tickerValue
            if right.startswith("C"):
                return strike >= tickerValue
            return False

        chain_expirations = self.config["option_chains"]["expirations"]

        strikes = sorted(strike for strike in chain.strikes if valid_strike(strike))
        expirations = sorted(
            exp
            for exp in chain.expirations
            if option_dte(exp) >= self.config["target"]["dte"]
        )[:chain_expirations]
        rights = [right]

        def nearest_strikes(strikes):
            chain_strikes = self.config["option_chains"]["strikes"]
            if right.startswith("P"):
                return strikes[-chain_strikes:]
            if right.startswith("C"):
                return strikes[:chain_strikes]

        contracts = [
            Option(
                symbol,
                expiration,
                strike,
                right,
                "SMART",
                tradingClass=chain.tradingClass,
            )
            for right in rights
            for expiration in expirations
            for strike in nearest_strikes(strikes)
        ]

        contracts = self.ib.qualifyContracts(*contracts)

        tickers = self.ib.reqTickers(*contracts)

        def open_interest_is_valid(ticker):
            ticker = self.ib.reqMktData(ticker.contract, genericTickList="101")

            while util.isNan(ticker.putOpenInterest) or util.isNan(
                ticker.callOpenInterest
            ):
                self.ib.waitOnUpdate(timeout=2)

            self.ib.cancelMktData(ticker.contract)

            # The open interest value is never present when using historical
            # data, so just ignore it when the value is None
            if right.startswith("P"):
                return (
                    ticker.putOpenInterest
                    >= self.config["target"]["minimum_open_interest"]
                )
            if right.startswith("C"):
                return (
                    ticker.callOpenInterest
                    >= self.config["target"]["minimum_open_interest"]
                )

        def delta_is_valid(ticker):
            return (
                ticker.modelGreeks
                and ticker.modelGreeks.delta
                and abs(ticker.modelGreeks.delta) <= self.config["target"]["delta"]
            )

        # Filter by delta and open interest
        tickers = [ticker for ticker in tickers if delta_is_valid(ticker)]
        tickers = [ticker for ticker in tickers if open_interest_is_valid(ticker)]
        tickers = sorted(
            reversed(sorted(tickers, key=lambda t: abs(t.modelGreeks.delta))),
            key=lambda t: option_dte(t.contract.lastTradeDateOrContractMonth),
        )

        if len(tickers) == 0:
            raise RuntimeError(f"No valid contracts found for {symbol}. Aborting.")

        return tickers[0]
    def find_eligible_contracts(
        self,
        symbol,
        primary_exchange,
        right,
        strike_limit,
        exclude_expirations_before=None,
        exclude_first_exp_strike=None,
    ):
        click.echo()
        click.secho(
            f"Searching option chain for symbol={symbol} "
            f"right={right}, this can take a while...",
            fg="green",
        )
        click.echo()
        stock = Stock(symbol,
                      "SMART",
                      currency="USD",
                      primaryExchange=primary_exchange)
        self.ib.qualifyContracts(stock)

        ticker = self.get_ticker_for(stock)
        tickerValue = ticker.marketPrice()

        chains = self.get_chains_for_stock(stock)
        chain = next(c for c in chains if c.exchange == "SMART")

        def valid_strike(strike):
            if right.startswith("P") and strike_limit:
                return strike <= tickerValue and strike <= strike_limit
            elif right.startswith("P"):
                return strike <= tickerValue
            elif right.startswith("C") and strike_limit:
                return strike >= tickerValue and strike >= strike_limit
            elif right.startswith("C"):
                return strike >= tickerValue
            return False

        chain_expirations = self.config["option_chains"]["expirations"]
        min_dte = (option_dte(exclude_expirations_before)
                   if exclude_expirations_before else 0)

        strikes = sorted(strike for strike in chain.strikes
                         if valid_strike(strike))
        expirations = sorted(
            exp for exp in chain.expirations
            if option_dte(exp) >= self.config["target"]["dte"]
            and option_dte(exp) >= min_dte)[:chain_expirations]
        rights = [right]

        def nearest_strikes(strikes):
            chain_strikes = self.config["option_chains"]["strikes"]
            if right.startswith("P"):
                return strikes[-chain_strikes:]
            if right.startswith("C"):
                return strikes[:chain_strikes]

        contracts = [
            Option(
                symbol,
                expiration,
                strike,
                right,
                "SMART",
                # tradingClass=chain.tradingClass,
            ) for right in rights for expiration in expirations
            for strike in nearest_strikes(strikes)
        ]

        contracts = self.ib.qualifyContracts(*contracts)

        # exclude strike, but only for the first exp
        if exclude_first_exp_strike:
            contracts = [
                c for c in contracts
                if (c.lastTradeDateOrContractMonth == expirations[0]
                    and c.strike != exclude_first_exp_strike)
                or c.lastTradeDateOrContractMonth != expirations[0]
            ]

        tickers = self.get_ticker_list_for(tuple(contracts))

        # Filter out contracts which don't have a midpoint price
        tickers = [t for t in tickers if not util.isNan(t.midpoint())]

        def open_interest_is_valid(ticker):
            def open_interest_is_not_ready():
                if right.startswith("P"):
                    return util.isNan(ticker.putOpenInterest)
                if right.startswith("C"):
                    return util.isNan(ticker.callOpenInterest)

            try:
                wait_n_seconds(
                    open_interest_is_not_ready,
                    lambda: self.ib.waitOnUpdate(timeout=15),
                    API_RESPONSE_WAIT_TIME,
                )
            except RuntimeError:
                click.secho(
                    f"Timeout waiting on market data for "
                    f"{ticker.contract}. Continuing...",
                    fg="yellow",
                )
                return False
            finally:
                self.ib.cancelMktData(ticker.contract)

            # The open interest value is never present when using historical
            # data, so just ignore it when the value is None
            if right.startswith("P"):
                return (ticker.putOpenInterest >=
                        self.config["target"]["minimum_open_interest"])
            if right.startswith("C"):
                return (ticker.callOpenInterest >=
                        self.config["target"]["minimum_open_interest"])

        def delta_is_valid(ticker):
            return (ticker.modelGreeks
                    and not util.isNan(ticker.modelGreeks.delta)
                    and ticker.modelGreeks.delta is not None
                    and abs(ticker.modelGreeks.delta) <= get_target_delta(
                        self.config, symbol, right))

        def price_is_valid(ticker):
            return not util.isNan(ticker.midpoint()) or not util.isNan(
                ticker.marketPrice())

        # Filter out tickers without prices
        tickers = [ticker for ticker in tickers if price_is_valid(ticker)]
        # Filter by delta and open interest
        tickers = [ticker for ticker in tickers if delta_is_valid(ticker)]
        # Fetch market data
        tickers = [
            self.ib.reqMktData(ticker.contract, genericTickList="101")
            for ticker in tickers
        ]
        # Fetch open interest
        tickers = [
            ticker for ticker in tickers if open_interest_is_valid(ticker)
        ]
        # Sort by delta first, then expiry date
        tickers = sorted(
            reversed(sorted(tickers, key=lambda t: abs(t.modelGreeks.delta))),
            key=lambda t: option_dte(t.contract.lastTradeDateOrContractMonth),
        )

        if len(tickers) == 0:
            raise RuntimeError(
                f"No valid contracts found for {symbol}. Aborting.")

        # Return the first result
        return tickers[0]