def refresh_form_token(self, tree=None):
        self.form_token = None

        if tree is None:
            self.form_token = None
            uri = UrlHelper.set_query(self.base_url, self.query_params)
            resp = Session().get(uri, data=self.form_data)
            tree = html.fromstring(resp.text)
        fon = lambda x: x[0] if len(x) > 0 else None
        token = fon(tree.xpath('//input[@name="formToken"]/@value'))
        self.form_token = token
        print("form token: %s" % self.form_token)
        print("form data: %s" % self.form_data)
    def _get_max_shares(self):
        if self.form_token is None:
            self.refresh_form_token()
        uri = UrlHelper.set_query(self.base_url, self.query_params)
        self.form_data['isShowMax'] = 1
        resp = Session().post(uri, data=self.form_data)
        tree = html.fromstring(resp.text)
        self.form_data['isShowMax'] = 0
        self.refresh_form_token(tree)
        fon = lambda x: x[0] if len(x)> 0 else None

        try:
            xpath1 = '//div[@id="limitDiv"]/span[@id="limitationLabel"]/text()'
            xpath2 = '//div[@id="limitDiv"]/span/text()'
            text = fon(tree.xpath(xpath1)) or fon(tree.xpath(xpath2))
            shares_match = re.search(
                r'maximum\s*of\s*(\d+)\s*(?:shares|option)', text)
            return int(shares_match.group(1))

        except Exception as e:
            error = e
            warnings.warn("Unable to determine max shares: %s" % e)
            return
        return 0
 def go_to_preview(self):
     session = Session()
     uri = UrlHelper.set_query(self.base_url, self.query_params)
     self.form_data.update({'isShowMax': 0})
     return session.post(uri, data=self.form_data)
Ejemplo n.º 4
0
def option_lookup(symbol,strike_price_proximity=3):
    logging.debug("OPTION LOOKUP FOR %s" % symbol)
    def filter_contracts(olist,stock_price,spp):
        if olist is None:
            return []
        middle_index = 0
        for i in range(len(olist)):
            if stock_price < olist[i]['StrikePrice']:
                middle_index += 1
                break
        start = middle_index - spp
        end = middle_index + spp
        if start < 0:
            start = 0
        if end > len(olist) - 1:
            end = len(olist) - 1

        return olist[start:end]


    session = Session()
    resp = session.get(UrlHelper.route('optionlookup'))
    tree = html.fromstring(resp.text)

    option_token = None
    option_user_id = None

    token = None
    user_id = None
    param_script = tree.xpath('//script[contains(text(),"quoteOptions")]/text()')[0]
    param_search = re.search(r'\#get\-quote\-options\'\)\,\s*\'(.+)\'\s*\,\s*(\d+)\s*\)\;', param_script)
    try:
        option_token = param_search.group(1)
        option_user_id = param_search.group(2)
    except Exception:
        raise Exception("Unable to get option lookup token")

    option_quote_qp = {
        'IdentifierType': 'Symbol',
        'Identifier': symbol,
        'SymbologyType': 'DTNSymbol',
        'OptionExchange': None,
        '_token': option_token,
        '_token_userid': option_user_id
    }

    url = UrlHelper.set_query(OPTIONS_QUOTE_URL, option_quote_qp)

    resp = requests.get(url)
    option_data = json.loads(resp.text)

    quote = option_data['Quote']
    if quote is None:
        logging.debug(option_data)
        raise Exception("No option quote data for %s" % symbol)


    try:
        last_price = option_data['Quote']['Last']
    except Exception as e:
        logging.debug(option_data)
        logging.debug(e)
    option_chains = []
    for e in option_data['Expirations']:
        expiration = e['ExpirationDate']
        filtered_calls = filter_contracts(e['Calls'],last_price,strike_price_proximity)
        filtered_puts = filter_contracts(e['Puts'],last_price,strike_price_proximity)


        calls = [OptionContract(o) for o in filtered_calls]
        puts = [OptionContract(o) for o in filtered_puts]
        option_chains.append(OptionChain(expiration,calls=calls,puts=puts))


    option_chain_lookup = OptionChainLookup(symbol,*option_chains)
    return option_chain_lookup
 def go_to_preview(self):
     session = Session()
     self.form_data.update({'btnReview': 'Preview+Order', 'isShowMax': 0})
     uri = UrlHelper.set_query(UrlHelper.route(
         'tradeoption'), self.query_params)
     return session.post(uri, data=self.form_data)
    def validate(self):
        if self.form_token is None:
            print("refreshing form token")
            self.refresh_form_token()

        if self.validated:
            warnings.warn(
                "Warning: trade has already been validated.  Revalidating...")
            self.form_data.pop('btnReview', None)
            self.refresh_form_token()
            self.validated = False
        assert type(self._trade_type).__name__ == 'TradeType'
        assert type(self._order_type).__name__ == 'OrderType'
        assert type(self._duration).__name__ == 'Duration'
        assert type(self.quantity) == int
        try:
            assert self.security_type == 'stock' or self.security_type == 'option'
        except AssertionError:
            raise InvalidTradeTypeException(
                "security type is not specified.  Must be either 'stock' or 'option'"
            )

        if self.security_type == 'stock':
            try:
                assert self.trade_type in ('BUY', 'SELL', 'SELL_SHORT',
                                           'BUY_TO_COVER')
            except AssertionError:
                raise InvalidTradeTypeException(
                    "A stock's trade type must be one of the following: BUY,SELL,SELL_SHORT,BUY_TO_COVER.  Got %s "
                    % self.trade_type)
        if self.security_type == 'option':
            try:
                assert self.trade_type in ('BUY_TO_OPEN', 'SELL_TO_CLOSE')
            except AssertionError:
                raise InvalidTradeTypeException(
                    "An option's trade type must be one of the following: BUY_TO_OPEN,SELL_TO_CLOSE"
                )
        try:
            max_shares = self._get_max_shares()
            assert self.quantity <= max_shares
        except AssertionError:
            raise TradeExceedsMaxSharesException(
                "Quantity %s exceeds max of %s" % (self.quantity, max_shares),
                max_shares)
        try:
            resp = self.go_to_preview()
            redirect_url = resp.history[0].headers['Location']
            redirect_qp = UrlHelper.get_query_params(redirect_url)

            tree = html.fromstring(resp.text)
            self.refresh_form_token(tree)
            trade_info = self._get_trade_info(tree)

            submit_query_params = redirect_qp

            submit_form_data = {
                'submitOrder':
                tree.xpath('//input[@name="submitOrder"]/@value')[0],
                'formToken': self.form_token
            }

            submit_url = UrlHelper.set_query(self.submit_url,
                                             submit_query_params)
            prepared_trade = PreparedTrade(submit_url, submit_form_data,
                                           **trade_info)
            self.execute = prepared_trade.execute
            self.validated = True
            return prepared_trade
        except Exception as e:
            print("trade failed for %s %s %s" %
                  (self.symbol, self.quantity, self.trade_type))
            print(e)
            raise e
            return False