def listen(self): 'Checks update queues and calls the required update method' # Extra sleep so main thread can finish print statements time.sleep(1.0) # DB init here for thread compatibility. self.db = StockDB() self.db.initialize('stock_db.sqlite') for key in self.stock_dict: if self.db.create_table(key, table_types.ohlc): print_l('Table verified for: ' + str(key)) print_l('Receiving updates...') while self.listening: try: with self.condition: self.condition.wait() if len(self.quote_queue) > 0: for q in self.quote_queue: o = OHLC.fromquote(q) self.db.add_data(q['symbol'], table_types.ohlc, o) self.quote_update(q) self.quote_queue.remove(q) if len(self.order_queue) > 0: self.order_update(self.order_queue.pop()) if len(self.trade_queue) > 0: self.trade_update(self.trade_queue.pop()) time.sleep(0.2) except KeyboardInterrupt as e: self.listening = False if not is_trade_active(): self.listening = False
def run(self, offline=False): '''Executes boilerplate Initiates listener for updates on a separate thread''' if self.config is None: print_s() print_l("No config provided. Unable to sign in.") return self.sign_in() self.register_masters() self.register_handlers()
def close_ops(self): 'Unsubscribe from upstox scrips and closes other threads' print_s() print_l('Shutting Down') for sym, stock in self.stock_dict.items(): self.client.unsubscribe(stock.instrument, LiveFeedType.Full) print_l('Shut Down Complete.') print_s() with self.condition: self.listening = False self.condition.notify_all()
def order_update(self, order_info): if self.not_rejected(order_info['status']): if order_info['transaction_type'] == 'B': self.buy_orderid = order_info['order_id'] if order_info['status'] == 'complete': self.order_attempts += 1 elif order_info['trigger_price'] > 0: self.stoploss_orderid = order_info['order_id'] else: self.target_orderid = order_info['order_id'] else: self.order_attempts += 1 print_l('Order rejected, {} attempts remaining'.format(self.max_attempts - self.order_attempts)) self.orders.append(order_info)
def start_listener(self): try: print_l('Opening Websocket to Upstox server') self.client.start_websocket(True) except Exception as e: print_l('Error while starting websocket - ') print_l(e.args[0]) listener = threading.Thread(target=self.listen) try: listener.start() self.listening = True except Exception as e: print_s() print_l('Unexpected error') print_l(e) print_s()
def make_reports(self): ''' Currently testing. Saves the day's total trades and orders in a text file''' orders = self.client.get_order_history() sorted_orders = [] print_l("Generating order book") for order in orders: if order['product'] == 'D': continue if order['transaction_type'] == 'B': if order['status'] != 'rejected' and \ order['status'] != 'cancelled': sorted_orders.append(order) p_id = order['order_id'] for order in orders: if order['parent_order_id'] == p_id and \ order['transaction_type'] == 'S': sorted_orders.append(order) print_keys = ['symbol', 'product', 'order_type', 'transaction_type', 'status', 'price', 'trigger_price', 'order_id', 'parent_order_id', 'exchange_time'] dmy = date.today().strftime('%d%m%y') with open('orders{}.txt'.format(dmy), 'w') as f: f.write('Orders placed ----\n') for order in sorted_orders: for key in print_keys: f.write("{} :: {}\n".format(key, order[key])) f.write("\n----------------------------------\n") print_l("Generating trade book") trades = self.client.get_trade_book() with open('trades{}.txt'.format(dmy), 'w') as f: f.write('Trades Completed ----\n') for trade in trades: for key, val in trade.items(): f.write("{} :: {}\n".format(key, val)) f.write("\n-----------------\n")
def __init__(self, config=None): print_l("Initializing...") self.client = None self.condition = threading.Condition() self.indices = ['NSE_FO'] self.stock_dict = {} self.listening = False self.trading = False # init db in listen() for thread compatibility self.db = None if config is None: print_s() print_l('No config provided. Will be unable to sign in.') self.config = config self.quote_queue = [] self.trade_queue = [] self.order_queue = []
def initialize(self, quote_info, test=False): self.ohlc = OHLC().fromquote(quote_info) self.test = test if is_trade_active(): self.calc_resistance(self.ohlc.ltp) self.calc_support(self.ohlc.ltp) self.init = True print_s() print_l('Gann Angle for {}'.format(self.instrument.symbol)) print_l('Calculated on ltp = {}'.format(self.ohlc.ltp)) print_l('Buy Trigger = {}'.format(self.res_trigger)) print_l('Support Trigger = {}'.format(self.sup_trigger)) print_s()
def save_new_tokens(self, key, secret): 'Gets and saves new credentials fom Upstox server' print_l("New access token required") sesh = Session(key) sesh.set_redirect_uri("https://upstox.com") sesh.set_api_secret(secret) print("\nOpen below link to login to Upstox:\n") url = sesh.get_login_url() print(url) auth_code = input("\nPlease enter the code from URL: ") sesh.set_code(auth_code) print_l("Authenticating...") access_token = str(sesh.retrieve_access_token()) access_time = datetime.now() print("Access token - {0} \nreceived at {1}". format(access_token, access_time)) with open('data.pkl', 'wb') as f: pickle.dump(access_token, f) pickle.dump(access_time, f) return access_token
def register_masters(self, masters=["nse_fo", 'nse_index']): 'Boilerplate for adding exchanges to enable stock data subscriptions' try: print_s() print_l("Registering Indices") for ind in masters: print(len(self.client.get_master_contract(ind))) except AttributeError: print_l("Masters preloaded/no valid masters provided") except HTTPError as e: print_s() print_l('Server error - ') print_l(e.args[0]) print_s()
def quote_update(self, quote_info): if self.init is False: self.initialize(quote_info) return Actions.none, None self.last_update = datetime.now() self.ohlc.ltp = float(quote_info['ltp']) self.ohlc.atp = float(quote_info['atp']) self.ohlc.op = float(quote_info['open']) self.ohlc.hi = float(quote_info['high']) self.ohlc.lo = float(quote_info['low']) self.ohlc.cl = float(quote_info['close']) self.epoch = int(quote_info['timestamp']) / 1000 if self.ordered or self.order_attempts > self.max_attempts: return Actions.none, None elif self.ohlc.ltp >= self.res_trigger and is_trade_active(): self.ordered = True print_l('Order attempt {} of {}'.format(self.order_attempts, self.max_attempts)) return Actions.buy, self.buy_args() elif self.ohlc.ltp <= self.sup_trigger: self.calc_resistance(self.ohlc.ltp) return Actions.none, None
def register_handlers(self): 'Registers quote, order and trade handlers for Upstox updates' try: print_s() print_l('Registering handlers') self.client.set_on_quote_update(self.quote_handler) self.client.set_on_order_update(self.order_handler) self.client.set_on_trade_update(self.trade_handler) except Exception as e: print_l('Unable to register handlers - ') print_l(e.args[0])
def order_update(self, message): '''Processes items from the order queue. Updates the relevant TradeStrategy object in stock_dict with the order info ''' sym = message['symbol'].upper() print_s('IN') try: self.stock_dict[sym].order_update(message) except KeyError as e: print_l('Update received for unregistered stock') except Exception as e: print_l("Unhandled Error in order_update:") print_l(e) print_s('IN')
def trade_update(self, message): '''Processes items from the trade queue. Updates the relevant TradeStrategy object in stock_dict with the trade info ''' sym = message['symbol'].upper() print_s('IN') try: self.stock_dict[sym].order_update(message) except KeyError as e: print_l('Update received for unregistered stock') except Exception as e: print("Error in trade_update_handler:") print(e) print_l('Trade info received:') for key in message: print_l(message[key]) print_s('IN')
def sign_in(self): '''Login to Upstox.''' # # token_file = 'data.pkl' # # print_s() token = '' try: print_l('Loading previous credentials') with open(token_file, "rb") as f: token = pickle.load(f) except FileNotFoundError: print_l('Data file not found. Creating new file...') with open(token_file, "wb") as f: pass except EOFError: print_l('Data file empty. New credentials needed.') token = self.save_new_tokens(self.config['api_key'], self.config['api_secret']) print_s() print_l("Signing in to upstox-") max_tries = 5 tries = 1 client = None while tries <= max_tries: print_l('Attempt {}/{}'.format(tries, max_tries)) try: client = Upstox(self.config['api_key'], token) except HTTPError as e: err = e.args[0] # Need to get new security token and keys if 'Invalid' in err and '401' in err: print_s() print_l("Credentials expired") token = self.save_new_tokens(self.config['api_key'], self.config['api_secret']) else: raise except Exception as e: print_s() print_l("Unhandled Exception:") print_l(e.args[0]) print_s() finally: if client is not None: print_l('Logged in successfully.') self.client = client return tries += 1 else: print_l("Unable to login to upstox. Quitting...") return None
def quote_update(self, message): '''Processes quotes from the queue. Implemented this way to keep function executions client-side whenever possible. Message object: {'bids': [{'orders': 2, 'price': 97.5, 'quantity': 150},], 'high': 111.85, 'asks': [{'orders': 2, 'price': 97.75, 'quantity': 225}], 'vtt': 3107850.0, 'open': 100.0, 'timestamp': '1517377333000', 'ltp': 97.85, 'total_buy_qty': 651975, 'spot_price': 11019.55, 'oi': 2665875.0, 'upper_circuit': 229.55, 'symbol': 'NIFTY18FEB11200CE', 'yearly_low': None, 'lower_circuit': 1.95, 'exchange': 'NSE_FO', 'low': 95.0, 'instrument': namedtuple Instrument, 'close': 115.75, 'ltt': 1517377332000, 'total_sell_qty': 221775, 'atp': 103.58} ''' sym = message['symbol'] try: action, args = self.stock_dict[sym].quote_update(message) except KeyError: print('Update for unsubscribed stock/symbol, unsubscribing') self.client.unsubscribe(quote_update['instrument'], LiveFeedType.Full) order = '' if action == Actions.buy and args is not None: print_l('') print_s('OUT') print_l('Placing order:') print_l('Instrument: {}'.format(args[1].symbol)) print_l('Order Price: {}'.format(args[5])) print_l('Trigger price: {}'.format(args[6])) print_l('Sell Target: {}'.format(args[5] + args[10])) print_l('Stoploss: {}'.format(args[5] - args[9])) print_l('Quantity: {}'.format(args[2])) print_s('OUT') print_l('') if self.trading: try: order = self.client.place_order(*args) except Exception as e: print_s() print_l('Error while placing order!') print_l('order args:') print_l(args) print_l(e.args[0]) print_s() elif action == Actions.mod_sl and args is not None: print_s('OUT') print_l("{} - modifying stoploss order".format(sym)) print_l("order_id = {}".format(args[0])) try: order = self.client.modify_order(order_id=args[0], trigger_price=args[1]) except Exception as e: print_s() print_l('Exception while modifying order!') print_l(e.args[0]) print_s() if len(order) > 0: print_s('IN') print_l('Response on place_order() - ') print_l('Object of type - {}.'.format(type(order))) print_l(order) print_s('IN')