Ejemplo n.º 1
0
 def ibContract(self):
     c = None
     if self.symbol == 'TQQQ' or self.symbol == 'AAPL' or self.symbol == 'AMZN' or self.symbol == 'FB' or self.symbol == 'GOOG':
         c = Stock(symbol=self.symbol,
                   exchange='SMART',
                   currency='USD',
                   primaryExchange='NASDAQ')
     elif self.symbol == 'SQQQ':
         c = Stock(symbol=self.symbol,
                   exchange='SMART',
                   currency='USD',
                   primaryExchange='NASDAQ')
     elif self.symbol == 'AAP2' or self.symbol == 'AMZ2' or self.symbol == 'CRM2' or self.symbol == 'FB2' or self.symbol == 'GOO2' or self.symbol == 'GS2' or self.symbol == 'MSF2' or self.symbol == 'NFL2' or self.symbol == 'NVD2' or self.symbol == 'VIS2':
         c = Stock(symbol=self.symbol,
                   exchange='SMART',
                   currency='USD',
                   primaryExchange='LSE')
     elif (self.symbol == 'ES'
           or self.symbol == 'NQ') and self.localSymbol != None:
         c = Contract(secType='FUT',
                      symbol=self.symbol,
                      localSymbol=self.localSymbol,
                      exchange='GLOBEX',
                      currency='USD')
     else:
         fatal.errorAndExit('no security specified')
     self.contract = c
Ejemplo n.º 2
0
def lookup_contracts_Stock1(symbols):
    futures = []
    for s in symbols:
        futures.append([
            Stock(**c.contract.dict())
            for c in ib.reqContractDetails(Stock(**s))
        ])
        #log.debug(futures)
    #return futures
    return futures
Ejemplo n.º 3
0
    def put_is_itm(self, contract):
        stock = Stock(contract.symbol, "SMART", currency="USD")
        [ticker] = self.ib.reqTickers(stock)

        self.wait_for_market_price(ticker)

        return contract.strike >= ticker.marketPrice()
Ejemplo n.º 4
0
    def get_ticker_for(self, symbol):
        stock = Stock(symbol, "SMART", currency="USD")
        [ticker] = self.ib.reqTickers(stock)

        self.wait_for_market_price(ticker)

        return ticker
Ejemplo n.º 5
0
 def get_ticker_for_stock(self, symbol, primary_exchange, midpoint=False):
     stock = Stock(symbol,
                   "SMART",
                   currency="USD",
                   primaryExchange=primary_exchange)
     self.ib.qualifyContracts(stock)
     return self.get_ticker_for(stock)
Ejemplo n.º 6
0
    def get_ticker_for(self, symbol, primary_exchange):
        stock = Stock(symbol,
                      "SMART",
                      currency="USD",
                      primaryExchange=primary_exchange)
        [ticker] = self.ib.reqTickers(stock)

        self.wait_for_market_price(ticker)

        return ticker
Ejemplo n.º 7
0
def lookup_contracts_Stock(symbols):
    futures = []
    for s in symbols:
        #log.format_string = '{record.channel}: {record.message}'
        #log.formatter
        log.debug(f'www{s}')
        #st=Stock(s['symbol'] ,s['exchange'],s['currency'],primaryExchange=s['primaryExchange'])
        st = Stock(s, 'SMART', 'USD', primaryExchange='NASDAQ')
        #st= Stock('AMD', 'SMART','NASDAQ','USD')
        futures.append(st)
    return futures
Ejemplo n.º 8
0
    def add(self, ticker, updateDB=True):
        contract = Stock(ticker, "SMART", "USD", primaryExchange="NASDAQ")
        result = self.ibService.getContractDetail(contract)
        if result is None:
            print(f"Contract {ticker} was not found")
        else:
            if updateDB:
                self.dbService.addToStockWatchlist(ticker)

            self.state.stocks_watchlist.add(ticker, contract)
            self.taskManager.run(
                ticker,
                self.ibService.startRealtimeData(
                    contract, self.state.stocks_realtime_data.update),
            )
Ejemplo n.º 9
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]
Ejemplo n.º 10
0
    def check_if_can_write_puts(self, account_summary, portfolio_positions):
        # Get stock positions
        stock_positions = [
            position for symbol in portfolio_positions
            for position in portfolio_positions[symbol]
            if isinstance(position.contract, Stock)
        ]

        total_buying_power = math.floor(
            float(account_summary["NetLiquidation"].value) *
            self.config["account"]["margin_usage"])

        click.echo()
        click.secho(
            f"Total buying power: ${total_buying_power} at {round(self.config['account']['margin_usage'] * 100, 1)}% margin usage",
            fg="green",
        )

        # Sum stock values that we care about
        total_value = (sum([stock.marketValue for stock in stock_positions]) +
                       total_buying_power)
        click.secho(f"Total value: ${total_value}", fg="green")
        click.echo()

        stock_symbols = dict()
        for stock in stock_positions:
            symbol = stock.contract.symbol
            stock_symbols[symbol] = stock

        targets = dict()
        target_additional_quantity = dict()

        # Determine target quantity of each stock
        for symbol in self.config["symbols"].keys():
            click.secho(f"  {symbol}", fg="green")
            stock = Stock(symbol, "SMART", currency="USD")
            [ticker] = self.ib.reqTickers(stock)

            self.wait_for_market_price(ticker)

            current_position = math.floor(stock_symbols[symbol].position
                                          if symbol in stock_symbols else 0)
            click.secho(
                f"    Current position quantity {current_position}",
                fg="cyan",
            )

            targets[symbol] = round(
                self.config["symbols"][symbol]["weight"] * total_value, 2)
            click.secho(f"    Target value ${targets[symbol]}", fg="cyan")
            target_quantity = math.floor(targets[symbol] /
                                         ticker.marketPrice())
            click.secho(f"    Target quantity {target_quantity}", fg="cyan")

            target_additional_quantity[symbol] = math.floor(target_quantity -
                                                            current_position)

            click.secho(
                f"    Target additional quantity (excl. existing options) {target_additional_quantity[symbol]}",
                fg="cyan",
            )

        click.echo()

        # Figure out how many additional puts are needed, if they're needed
        for symbol in target_additional_quantity.keys():
            additional_quantity = target_additional_quantity[symbol]
            # NOTE: it's possible there are non-standard option contract sizes,
            # like with futures, but we don't bother handling those cases.
            # Please don't use this code with futures.
            if additional_quantity >= 100:
                put_count = count_option_positions(symbol, portfolio_positions,
                                                   "P")
                target_put_count = additional_quantity // 100
                maximum_new_contracts = self.config["target"][
                    "maximum_new_contracts"]
                puts_to_write = min(
                    [target_put_count - put_count, maximum_new_contracts])
                if puts_to_write > 0:
                    click.secho(
                        f"Preparing to write additional {puts_to_write} puts to purchase {symbol}, capped at {maximum_new_contracts}",
                        fg="cyan",
                    )
                    self.write_puts(symbol, puts_to_write)

        return
Ejemplo n.º 11
0
 def call_is_itm(self, contract):
     stock = Stock(contract.symbol, "SMART", currency="USD")
     [ticker] = self.ib.reqTickers(stock)
     return contract.strike <= ticker.marketPrice()
Ejemplo n.º 12
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]
Ejemplo n.º 13
0
    def check_if_can_write_puts(self, account_summary, portfolio_positions):
        # Get stock positions
        stock_positions = [
            position
            for symbol in portfolio_positions
            for position in portfolio_positions[symbol]
            if isinstance(position.contract, Stock)
        ]

        remaining_buying_power = math.floor(
            min(
                [
                    float(account_summary["BuyingPower"].value),
                    float(account_summary["ExcessLiquidity"].value)
                    - float(account_summary["NetLiquidation"].value)
                    * self.config["account"]["minimum_cushion"],
                ]
            )
        )

        click.echo()
        click.secho(f"Remaining buying power: ${remaining_buying_power}", fg="green")
        #
        # Sum stock values that we care about
        total_value = (
            sum([stock.marketValue for stock in stock_positions])
            + remaining_buying_power
        )
        click.secho(f"Total value: ${total_value}", fg="green")
        click.echo()

        stock_symbols = dict()
        for stock in stock_positions:
            symbol = stock.contract.symbol
            stock_symbols[symbol] = stock

        targets = dict()
        target_additional_quantity = dict()

        # Determine target quantity of each stock
        for symbol in self.config["symbols"].keys():
            click.secho(f"  {symbol}", fg="green")
            stock = Stock(symbol, "SMART", currency="USD")
            [ticker] = self.ib.reqTickers(stock)

            current_position = math.floor(
                stock_symbols[symbol].position if symbol in stock_symbols else 0
            )
            click.secho(
                f"    Current position quantity {current_position}",
                fg="cyan",
            )

            targets[symbol] = round(
                self.config["symbols"][symbol]["weight"] * total_value, 2
            )
            click.secho(f"    Target value ${targets[symbol]}", fg="cyan")
            target_quantity = math.floor(targets[symbol] / ticker.marketPrice())
            click.secho(f"    Target quantity {target_quantity}", fg="cyan")

            target_additional_quantity[symbol] = math.floor(
                target_quantity - current_position
            )

            click.secho(
                f"    Target additional quantity (excl. existing options) {target_additional_quantity[symbol]}",
                fg="cyan",
            )

        click.echo()

        # Figure out how many addition puts are needed, if they're needed
        for symbol in target_additional_quantity.keys():
            additional_quantity = target_additional_quantity[symbol]
            if additional_quantity >= 100:
                put_count = count_option_positions(symbol, portfolio_positions, "P")
                target_put_count = additional_quantity // 100
                puts_to_write = target_put_count - put_count
                if puts_to_write > 0:
                    click.secho(
                        f"Preparing to write additional {puts_to_write} puts to purchase {symbol}",
                        fg="cyan",
                    )
                    self.write_puts(symbol, puts_to_write)

        return
Ejemplo n.º 14
0
def test_position_pnl():
    qqq_put = PortfolioItem(
        contract=Option(
            conId=397556522,
            symbol="QQQ",
            lastTradeDateOrContractMonth="20201218",
            strike=300.0,
            right="P",
            multiplier="100",
            primaryExchange="AMEX",
            currency="USD",
            localSymbol="QQQ   201218P00300000",
            tradingClass="QQQ",
        ),
        position=-1.0,
        marketPrice=4.1194396,
        marketValue=-411.94,
        averageCost=222.4293,
        unrealizedPNL=-189.51,
        realizedPNL=0.0,
        account="DU2962946",
    )
    assert round(position_pnl(qqq_put), 2) == -0.85

    spy = PortfolioItem(
        contract=Stock(
            conId=756733,
            symbol="SPY",
            right="0",
            primaryExchange="ARCA",
            currency="USD",
            localSymbol="SPY",
            tradingClass="SPY",
        ),
        position=100.0,
        marketPrice=365.4960022,
        marketValue=36549.6,
        averageCost=368.42,
        unrealizedPNL=-292.4,
        realizedPNL=0.0,
        account="DU2962946",
    )
    assert round(position_pnl(spy), 4) == -0.0079

    spy_call = PortfolioItem(
        contract=Option(
            conId=454208258,
            symbol="SPY",
            lastTradeDateOrContractMonth="20201214",
            strike=373.0,
            right="C",
            multiplier="100",
            primaryExchange="AMEX",
            currency="USD",
            localSymbol="SPY   201214C00373000",
            tradingClass="SPY",
        ),
        position=-1.0,
        marketPrice=0.08,
        marketValue=-8.0,
        averageCost=96.422,
        unrealizedPNL=88.42,
        realizedPNL=0.0,
        account="DU2962946",
    )
    assert round(position_pnl(spy_call), 2) == 0.92

    spy_put = PortfolioItem(
        contract=Option(
            conId=458705534,
            symbol="SPY",
            lastTradeDateOrContractMonth="20210122",
            strike=352.5,
            right="P",
            multiplier="100",
            primaryExchange="AMEX",
            currency="USD",
            localSymbol="SPY   210122P00352500",
            tradingClass="SPY",
        ),
        position=-1.0,
        marketPrice=5.96710015,
        marketValue=-596.71,
        averageCost=528.9025,
        unrealizedPNL=-67.81,
        realizedPNL=0.0,
        account="DU2962946",
    )
    assert round(position_pnl(spy_put), 2) == -0.13
Ejemplo n.º 15
0
        except asyncio.TimeoutError:
            _logger.error('requestFAAsync: Timeout')


if __name__ == '__main__':
#     import uvloop
#     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)
Ejemplo n.º 16
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]