From 4c3b40d36b799b1a327c0585eb17ec24e872b316 Mon Sep 17 00:00:00 2001 From: Rahul Raut Date: Mon, 26 Dec 2022 02:44:34 +0530 Subject: [PATCH 1/3] GTT create and get Added code 1. To get pending GTT orders 2. To get enabled GTT orders 3. To place GTT order --- NorenRestApiPy/NorenApi.py | 1058 ++++++++++++++++++++---------------- 1 file changed, 599 insertions(+), 459 deletions(-) diff --git a/NorenRestApiPy/NorenApi.py b/NorenRestApiPy/NorenApi.py index 377a2ce..10cc545 100644 --- a/NorenRestApiPy/NorenApi.py +++ b/NorenRestApiPy/NorenApi.py @@ -3,7 +3,7 @@ import threading import websocket import logging -import enum +from enum import Enum import datetime import hashlib import time @@ -13,92 +13,131 @@ logger = logging.getLogger(__name__) + class position: - prd:str - exch:str - instname:str - symname:str - exd:int - optt:str - strprc:float - buyqty:int - sellqty:int - netqty:int + prd: str + exch: str + instname: str + symname: str + exd: int + optt: str + strprc: float + buyqty: int + sellqty: int + netqty: int + def encode(self): return self.__dict__ + class ProductType: Delivery = 'C' Intraday = 'I' - Normal = 'M' - CF = 'M' + Normal = 'M' + CF = 'M' + class FeedType: - TOUCHLINE = 1 + TOUCHLINE = 1 SNAPQUOTE = 2 - + + class PriceType: Market = 'MKT' Limit = 'LMT' StopLossLimit = 'SL-LMT' StopLossMarket = 'SL-MKT' + class BuyorSell: Buy = 'B' Sell = 'S' - + +class AlertType: + LTP_ABOVE = 'LTP_A_O' + LTP_BELOW = 'LTP_B_O' + LTP_OCO = 'LMT_BOS_O' + def reportmsg(msg): - #print(msg) + # print(msg) logger.debug(msg) + def reporterror(msg): - #print(msg) + # print(msg) logger.error(msg) + def reportinfo(msg): - #print(msg) + # print(msg) logger.info(msg) -class NorenApi: + +class NorenApi(object): + + TRANSACTION_TYPE_SELL = 'S' + TRANSACTION_TYPE_BUY = 'B' + + PRODUCT_TYPE_INTRADAY = 'I' + PRODUCT_TYPE_DELIVERY = 'C' + PRODUCT_TYPE_NORMAL = 'M' + + PRICE_TYPE_MARKET = 'MKT' + PRICE_TYPE_LIMIT = 'LMT' + PRICE_TYPE_STOPLOSS_LIMIT = 'SL-LMT' + PRICE_TYPE_STOPLOSS_MARKET = 'SL-MKT' + + ALERT_TYPE_ABOVE = 'LTP_A_O' + ALERT_TYPE_BELOW = 'LTP_B_O' + ALERT_TYPE_OCO = 'LTP_BOS_O' + + FEED_TYPE_TOUCHLINE = 1 + FEED_TYPE_SNAPSHOT = 2 + __service_config = { - 'host': 'http://wsapihost/', - 'routes': { - 'authorize': '/QuickAuth', - 'logout': '/Logout', - 'forgot_password': '/ForgotPassword', - 'change_password': '/Changepwd', - 'watchlist_names': '/MWList', - 'watchlist': '/MarketWatch', - 'watchlist_add': '/AddMultiScripsToMW', - 'watchlist_delete': '/DeleteMultiMWScrips', - 'placeorder': '/PlaceOrder', - 'modifyorder': '/ModifyOrder', - 'cancelorder': '/CancelOrder', - 'exitorder': '/ExitSNOOrder', - 'product_conversion': '/ProductConversion', - 'orderbook': '/OrderBook', - 'tradebook': '/TradeBook', - 'singleorderhistory': '/SingleOrdHist', - 'searchscrip': '/SearchScrip', - 'TPSeries' : '/TPSeries', - 'optionchain' : '/GetOptionChain', - 'holdings' : '/Holdings', - 'limits' : '/Limits', - 'positions': '/PositionBook', - 'scripinfo': '/GetSecurityInfo', - 'getquotes': '/GetQuotes', - 'span_calculator' :'/SpanCalc', - 'option_greek' :'/GetOptionGreek', - 'get_daily_price_series' :'/EODChartData', - }, - 'websocket_endpoint': 'wss://wsendpoint/', - #'eoddata_endpoint' : 'http://eodhost/' + 'host': 'http://wsapihost/', + 'routes': { + 'authorize': '/QuickAuth', + 'logout': '/Logout', + 'forgot_password': '/ForgotPassword', + 'change_password': '/Changepwd', + 'watchlist_names': '/MWList', + 'watchlist': '/MarketWatch', + 'watchlist_add': '/AddMultiScripsToMW', + 'watchlist_delete': '/DeleteMultiMWScrips', + 'placeorder': '/PlaceOrder', + 'modifyorder': '/ModifyOrder', + 'cancelorder': '/CancelOrder', + 'exitorder': '/ExitSNOOrder', + 'product_conversion': '/ProductConversion', + 'orderbook': '/OrderBook', + 'tradebook': '/TradeBook', + 'singleorderhistory': '/SingleOrdHist', + 'searchscrip': '/SearchScrip', + 'TPSeries': '/TPSeries', + 'optionchain': '/GetOptionChain', + 'holdings': '/Holdings', + 'limits': '/Limits', + 'positions': '/PositionBook', + 'scripinfo': '/GetSecurityInfo', + 'getquotes': '/GetQuotes', + 'span_calculator': '/SpanCalc', + 'option_greek': '/GetOptionGreek', + 'get_daily_price_series': '/EODChartData', + "placegtt": "/PlaceGTTOrder", + "gtt": "/GetPendingGTTOrder", + "enabledgtt": "/GetEnabledGTTs", + "cancelgtt": "/CancelGTTOrder", + "ocogtt": "/PlaceOCOOrder" + }, + 'websocket_endpoint': 'wss://wsendpoint/', + # 'eoddata_endpoint' : 'http://eodhost/' } def __init__(self, host, websocket): self.__service_config['host'] = host self.__service_config['websocket_endpoint'] = websocket - #self.__service_config['eoddata_endpoint'] = eodhost + # self.__service_config['eoddata_endpoint'] = eodhost self.__websocket = None self.__websocket_connected = False @@ -113,18 +152,21 @@ def __init__(self, host, websocket): self.__exchange_messages = [] def __ws_run_forever(self): - + while self.__stop_event.is_set() == False: try: - self.__websocket.run_forever( ping_interval=3, ping_payload='{"t":"h"}') + self.__websocket.run_forever( + ping_interval=3, ping_payload='{"t":"h"}') except Exception as e: - logger.warning(f"websocket run forever ended in exception, {e}") - - sleep(0.1) # Sleep for 100ms between reconnection. + logger.warning( + f"websocket run forever ended in exception, {e}") + + sleep(0.1) # Sleep for 100ms between reconnection. def __ws_send(self, *args, **kwargs): while self.__websocket_connected == False: - sleep(0.05) # sleep for 50ms if websocket is not connected, wait for reconnection + # sleep for 50ms if websocket is not connected, wait for reconnection + sleep(0.05) with self.__ws_mutex: ret = self.__websocket.send(*args, **kwargs) return ret @@ -140,36 +182,35 @@ def __on_close_callback(self, wsapp, close_status_code, close_msg): def __on_open_callback(self, ws=None): self.__websocket_connected = True - #prepare the data - values = { "t": "c" } - values["uid"] = self.__username - values["actid"] = self.__username - values["susertoken"] = self.__susertoken - values["source"] = 'API' + # prepare the data + values = {"t": "c"} + values["uid"] = self.__username + values["actid"] = self.__username + values["susertoken"] = self.__susertoken + values["source"] = 'API' payload = json.dumps(values) reportmsg(payload) self.__ws_send(payload) - #self.__resubscribe() - + # self.__resubscribe() def __on_error_callback(self, ws=None, error=None): - if(type(ws) is not websocket.WebSocketApp): # This workaround is to solve the websocket_client's compatiblity issue of older versions. ie.0.40.0 which is used in upstox. Now this will work in both 0.40.0 & newer version of websocket_client + if (type(ws) is not websocket.WebSocketApp): # This workaround is to solve the websocket_client's compatiblity issue of older versions. ie.0.40.0 which is used in upstox. Now this will work in both 0.40.0 & newer version of websocket_client error = ws if self.__on_error: self.__on_error(error) def __on_data_callback(self, ws=None, message=None, data_type=None, continue_flag=None): - #print(ws) - #print(message) - #print(data_type) - #print(continue_flag) + # print(ws) + # print(message) + # print(data_type) + # print(continue_flag) res = json.loads(message) - if(self.__subscribe_callback is not None): + if (self.__subscribe_callback is not None): if res['t'] == 'tk' or res['t'] == 'tf': self.__subscribe_callback(res) return @@ -177,12 +218,12 @@ def __on_data_callback(self, ws=None, message=None, data_type=None, continue_fla self.__subscribe_callback(res) return - if(self.__on_error is not None): + if (self.__on_error is not None): if res['t'] == 'ck' and res['s'] != 'OK': self.__on_error(res) return - if(self.__order_update_callback is not None): + if (self.__order_update_callback is not None): if res['t'] == 'om': self.__order_update_callback(res) return @@ -192,12 +233,11 @@ def __on_data_callback(self, ws=None, message=None, data_type=None, continue_fla self.__on_open() return - - def start_websocket(self, subscribe_callback = None, - order_update_callback = None, - socket_open_callback = None, - socket_close_callback = None, - socket_error_callback = None): + def start_websocket(self, subscribe_callback=None, + order_update_callback=None, + socket_open_callback=None, + socket_close_callback=None, + socket_error_callback=None): """ Start a websocket connection for getting live data """ self.__on_open = socket_open_callback self.__on_disconnect = socket_close_callback @@ -205,26 +245,27 @@ def start_websocket(self, subscribe_callback = None, self.__subscribe_callback = subscribe_callback self.__order_update_callback = order_update_callback self.__stop_event = threading.Event() - url = self.__service_config['websocket_endpoint'].format(access_token=self.__susertoken) + url = self.__service_config['websocket_endpoint'].format( + access_token=self.__susertoken) reportmsg('connecting to {}'.format(url)) self.__websocket = websocket.WebSocketApp(url, - on_data=self.__on_data_callback, - on_error=self.__on_error_callback, - on_close=self.__on_close_callback, - on_open=self.__on_open_callback) - #th = threading.Thread(target=self.__send_heartbeat) - #th.daemon = True - #th.start() - #if run_in_background is True: + on_data=self.__on_data_callback, + on_error=self.__on_error_callback, + on_close=self.__on_close_callback, + on_open=self.__on_open_callback) + # th = threading.Thread(target=self.__send_heartbeat) + # th.daemon = True + # th.start() + # if run_in_background is True: self.__ws_thread = threading.Thread(target=self.__ws_run_forever) self.__ws_thread.daemon = True self.__ws_thread.start() - + def close_websocket(self): if self.__websocket_connected == False: return - self.__stop_event.set() + self.__stop_event.set() self.__websocket_connected = False self.__websocket.close() self.__ws_thread.join() @@ -232,22 +273,22 @@ def close_websocket(self): def login(self, userid, password, twoFA, vendor_code, api_secret, imei): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['authorize']}" + # prepare the uri + url = f"{config['host']}{config['routes']['authorize']}" reportmsg(url) - #Convert to SHA 256 for password and app key + # Convert to SHA 256 for password and app key pwd = hashlib.sha256(password.encode('utf-8')).hexdigest() u_app_key = '{0}|{1}'.format(userid, api_secret) - app_key=hashlib.sha256(u_app_key.encode('utf-8')).hexdigest() - #prepare the data - values = { "source": "API" , "apkversion": "1.0.0"} - values["uid"] = userid - values["pwd"] = pwd - values["factor2"] = twoFA - values["vc"] = vendor_code - values["appkey"] = app_key - values["imei"] = imei + app_key = hashlib.sha256(u_app_key.encode('utf-8')).hexdigest() + # prepare the data + values = {"source": "API", "apkversion": "1.0.0"} + values["uid"] = userid + values["pwd"] = pwd + values["factor2"] = twoFA + values["vc"] = vendor_code + values["appkey"] = app_key + values["imei"] = imei payload = 'jData=' + json.dumps(values) reportmsg("Req:" + payload) @@ -256,22 +297,22 @@ def login(self, userid, password, twoFA, vendor_code, api_secret, imei): reportmsg("Reply:" + res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict['stat'] != 'Ok': return None - - self.__username = userid - self.__accountid = userid - self.__password = password + + self.__username = userid + self.__accountid = userid + self.__password = password self.__susertoken = resDict['susertoken'] - #reportmsg(self.__susertoken) + # reportmsg(self.__susertoken) return resDict def set_session(self, userid, password, usertoken): - - self.__username = userid - self.__accountid = userid - self.__password = password + + self.__username = userid + self.__accountid = userid + self.__password = password self.__susertoken = usertoken reportmsg(f'{userid} session set to : {self.__susertoken}') @@ -281,15 +322,15 @@ def set_session(self, userid, password, usertoken): def forgot_password(self, userid, pan, dob): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['forgot_password']}" + # prepare the uri + url = f"{config['host']}{config['routes']['forgot_password']}" reportmsg(url) - #prepare the data - values = { "source": "API" } - values["uid"] = userid - values["pan"] = pan - values["dob"] = dob + # prepare the data + values = {"source": "API"} + values["uid"] = userid + values["pan"] = pan + values["dob"] = dob payload = 'jData=' + json.dumps(values) reportmsg("Req:" + payload) @@ -298,36 +339,36 @@ def forgot_password(self, userid, pan, dob): reportmsg("Reply:" + res.text) resDict = json.loads(res.text) - - if resDict['stat'] != 'Ok': + + if resDict['stat'] != 'Ok': return None - + return resDict def logout(self): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['logout']}" + # prepare the uri + url = f"{config['host']}{config['routes']['logout']}" reportmsg(url) - #prepare the data - values = {'ordersource':'API'} - values["uid"] = self.__username - + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict['stat'] != 'Ok': return None - self.__username = None - self.__accountid = None - self.__password = None + self.__username = None + self.__accountid = None + self.__password = None self.__susertoken = None return resDict @@ -335,44 +376,44 @@ def logout(self): def subscribe(self, instrument, feed_type=FeedType.TOUCHLINE): values = {} - if(feed_type == FeedType.TOUCHLINE): - values['t'] = 't' - elif(feed_type == FeedType.SNAPQUOTE): - values['t'] = 'd' + if (feed_type == FeedType.TOUCHLINE): + values['t'] = 't' + elif (feed_type == FeedType.SNAPQUOTE): + values['t'] = 'd' else: - values['t'] = str(feed_type) + values['t'] = str(feed_type) if type(instrument) == list: values['k'] = '#'.join(instrument) - else : + else: values['k'] = instrument data = json.dumps(values) - #print(data) + # print(data) self.__ws_send(data) def unsubscribe(self, instrument, feed_type=FeedType.TOUCHLINE): values = {} - if(feed_type == FeedType.TOUCHLINE): - values['t'] = 'u' - elif(feed_type == FeedType.SNAPQUOTE): - values['t'] = 'ud' - + if (feed_type == FeedType.TOUCHLINE): + values['t'] = 'u' + elif (feed_type == FeedType.SNAPQUOTE): + values['t'] = 'ud' + if type(instrument) == list: values['k'] = '#'.join(instrument) - else : + else: values['k'] = instrument data = json.dumps(values) - #print(data) + # print(data) self.__ws_send(data) def subscribe_orders(self): values = {'t': 'o'} - values['actid'] = self.__accountid + values['actid'] = self.__accountid data = json.dumps(values) @@ -382,22 +423,22 @@ def subscribe_orders(self): def get_watch_list_names(self): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['watchlist_names']}" + # prepare the uri + url = f"{config['host']}{config['routes']['watchlist_names']}" reportmsg(url) - #prepare the data - values = {'ordersource':'API'} - values["uid"] = self.__username - + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict['stat'] != 'Ok': return None return resDict @@ -405,52 +446,51 @@ def get_watch_list_names(self): def get_watch_list(self, wlname): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['watchlist']}" + # prepare the uri + url = f"{config['host']}{config['routes']['watchlist']}" reportmsg(url) - #prepare the data - values = {'ordersource':'API'} - values["uid"] = self.__username - values["wlname"] = wlname - + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username + values["wlname"] = wlname + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict['stat'] != 'Ok': return None return resDict - def add_watch_list_scrip(self, wlname, instrument): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['watchlist_add']}" + # prepare the uri + url = f"{config['host']}{config['routes']['watchlist_add']}" reportmsg(url) - #prepare the data - values = {'ordersource':'API'} - values["uid"] = self.__username - values["wlname"] = wlname + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username + values["wlname"] = wlname if type(instrument) == list: values['scrips'] = '#'.join(instrument) - else : + else: values['scrips'] = instrument payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict['stat'] != 'Ok': return None return resDict @@ -458,104 +498,103 @@ def add_watch_list_scrip(self, wlname, instrument): def delete_watch_list_scrip(self, wlname, instrument): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['watchlist_delete']}" + # prepare the uri + url = f"{config['host']}{config['routes']['watchlist_delete']}" reportmsg(url) - #prepare the data - values = {'ordersource':'API'} - values["uid"] = self.__username - values["wlname"] = wlname + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username + values["wlname"] = wlname if type(instrument) == list: values['scrips'] = '#'.join(instrument) - else : + else: values['scrips'] = instrument payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict['stat'] != 'Ok': return None return resDict - def place_order(self, buy_or_sell, product_type, exchange, tradingsymbol, quantity, discloseqty, price_type, price=0.0, trigger_price=None, - retention='DAY', amo='NO', remarks=None, bookloss_price = 0.0, bookprofit_price = 0.0, trail_price = 0.0): + retention='DAY', amo='NO', remarks=None, bookloss_price=0.0, bookprofit_price=0.0, trail_price=0.0): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['placeorder']}" + # prepare the uri + url = f"{config['host']}{config['routes']['placeorder']}" reportmsg(url) - #prepare the data - values = {'ordersource':'API'} - values["uid"] = self.__username - values["actid"] = self.__accountid - values["trantype"] = buy_or_sell - values["prd"] = product_type - values["exch"] = exchange - values["tsym"] = urllib.parse.quote_plus(tradingsymbol) - values["qty"] = str(quantity) - values["dscqty"] = str(discloseqty) - values["prctyp"] = price_type - values["prc"] = str(price) - values["trgprc"] = str(trigger_price) - values["ret"] = retention - values["remarks"] = remarks - values["amo"] = amo - - #if cover order or high leverage order - if product_type == 'H': - values["blprc"] = str(bookloss_price) - #trailing price + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username + values["actid"] = self.__accountid + values["trantype"] = buy_or_sell + values["prd"] = product_type + values["exch"] = exchange + values["tsym"] = urllib.parse.quote_plus(tradingsymbol) + values["qty"] = str(quantity) + values["dscqty"] = str(discloseqty) + values["prctyp"] = price_type + values["prc"] = str(price) + values["trgprc"] = str(trigger_price) + values["ret"] = retention + values["remarks"] = remarks + values["amo"] = amo + + # if cover order or high leverage order + if product_type == 'H': + values["blprc"] = str(bookloss_price) + # trailing price if trail_price != 0.0: values["trailprc"] = str(trail_price) - #bracket order - if product_type == 'B': - values["blprc"] = str(bookloss_price) - values["bpprc"] = str(bookprofit_price) - #trailing price + # bracket order + if product_type == 'B': + values["blprc"] = str(bookloss_price) + values["bpprc"] = str(bookprofit_price) + # trailing price if trail_price != 0.0: values["trailprc"] = str(trail_price) payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict['stat'] != 'Ok': return None return resDict def modify_order(self, orderno, exchange, tradingsymbol, newquantity, - newprice_type, newprice=0.0, newtrigger_price=None, bookloss_price = 0.0, bookprofit_price = 0.0, trail_price = 0.0): + newprice_type, newprice=0.0, newtrigger_price=None, bookloss_price=0.0, bookprofit_price=0.0, trail_price=0.0): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['modifyorder']}" + # prepare the uri + url = f"{config['host']}{config['routes']['modifyorder']}" print(url) - #prepare the data - values = {'ordersource':'API'} - values["uid"] = self.__username - values["actid"] = self.__accountid - values["norenordno"] = str(orderno) - values["exch"] = exchange - values["tsym"] = urllib.parse.quote_plus(tradingsymbol) - values["qty"] = str(newquantity) - values["prctyp"] = newprice_type - values["prc"] = str(newprice) + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username + values["actid"] = self.__accountid + values["norenordno"] = str(orderno) + values["exch"] = exchange + values["tsym"] = urllib.parse.quote_plus(tradingsymbol) + values["qty"] = str(newquantity) + values["prctyp"] = newprice_type + values["prc"] = str(newprice) if (newprice_type == 'SL-LMT') or (newprice_type == 'SL-MKT'): if (newtrigger_price != None): @@ -564,25 +603,25 @@ def modify_order(self, orderno, exchange, tradingsymbol, newquantity, reporterror('trigger price is missing') return None - #if cover order or high leverage order - if bookloss_price != 0.0: - values["blprc"] = str(bookloss_price) - #trailing price + # if cover order or high leverage order + if bookloss_price != 0.0: + values["blprc"] = str(bookloss_price) + # trailing price if trail_price != 0.0: - values["trailprc"] = str(trail_price) - #book profit of bracket order + values["trailprc"] = str(trail_price) + # book profit of bracket order if bookprofit_price != 0.0: - values["bpprc"] = str(bookprofit_price) - + values["bpprc"] = str(bookprofit_price) + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict['stat'] != 'Ok': return None return resDict @@ -590,24 +629,24 @@ def modify_order(self, orderno, exchange, tradingsymbol, newquantity, def cancel_order(self, orderno): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['cancelorder']}" + # prepare the uri + url = f"{config['host']}{config['routes']['cancelorder']}" print(url) - #prepare the data - values = {'ordersource':'API'} - values["uid"] = self.__username - values["norenordno"] = str(orderno) - + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username + values["norenordno"] = str(orderno) + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) print(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict['stat'] != 'Ok': return None return resDict @@ -615,25 +654,25 @@ def cancel_order(self, orderno): def exit_order(self, orderno, product_type): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['exitorder']}" + # prepare the uri + url = f"{config['host']}{config['routes']['exitorder']}" print(url) - #prepare the data - values = {'ordersource':'API'} - values["uid"] = self.__username - values["norenordno"] = orderno - values["prd"] = product_type - + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username + values["norenordno"] = orderno + values["prd"] = product_type + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict['stat'] != 'Ok': return None return resDict @@ -644,135 +683,133 @@ def position_product_conversion(self, exchange, tradingsymbol, quantity, new_pro ''' config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['product_conversion']}" + # prepare the uri + url = f"{config['host']}{config['routes']['product_conversion']}" print(url) - #prepare the data - values = {'ordersource':'API'} - values["uid"] = self.__username - values["actid"] = self.__accountid - values["exch"] = exchange - values["tsym"] = urllib.parse.quote_plus(tradingsymbol) - values["qty"] = str(quantity) - values["prd"] = new_product_type - values["prevprd"] = previous_product_type - values["trantype"] = buy_or_sell - values["postype"] = day_or_cf - + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username + values["actid"] = self.__accountid + values["exch"] = exchange + values["tsym"] = urllib.parse.quote_plus(tradingsymbol) + values["qty"] = str(quantity) + values["prd"] = new_product_type + values["prevprd"] = previous_product_type + values["trantype"] = buy_or_sell + values["postype"] = day_or_cf + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) resDict = json.loads(res.text) - - if resDict['stat'] != 'Ok': + + if resDict['stat'] != 'Ok': return None return resDict - def single_order_history(self, orderno): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['singleorderhistory']}" + # prepare the uri + url = f"{config['host']}{config['routes']['singleorderhistory']}" print(url) - - #prepare the data - values = {'ordersource':'API'} - values["uid"] = self.__username - values["norenordno"] = orderno - + + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username + values["norenordno"] = orderno + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) resDict = json.loads(res.text) - #error is a json with stat and msg wchih we printed earlier. - if type(resDict) != list: - return None + # error is a json with stat and msg wchih we printed earlier. + if type(resDict) != list: + return None return resDict - def get_order_book(self): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['orderbook']}" + # prepare the uri + url = f"{config['host']}{config['routes']['orderbook']}" reportmsg(url) - #prepare the data - values = {'ordersource':'API'} - values["uid"] = self.__username - + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) resDict = json.loads(res.text) - - #error is a json with stat and msg wchih we printed earlier. - if type(resDict) != list: - return None + + # error is a json with stat and msg wchih we printed earlier. + if type(resDict) != list: + return None return resDict def get_trade_book(self): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['tradebook']}" + # prepare the uri + url = f"{config['host']}{config['routes']['tradebook']}" reportmsg(url) - #prepare the data - values = {'ordersource':'API'} - values["uid"] = self.__username - values["actid"] = self.__accountid - + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username + values["actid"] = self.__accountid + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) resDict = json.loads(res.text) - - #error is a json with stat and msg wchih we printed earlier. - if type(resDict) != list: - return None + + # error is a json with stat and msg wchih we printed earlier. + if type(resDict) != list: + return None return resDict def searchscrip(self, exchange, searchtext): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['searchscrip']}" + # prepare the uri + url = f"{config['host']}{config['routes']['searchscrip']}" reportmsg(url) - + if searchtext == None: reporterror('search text cannot be null') return None - - values = {} - values["uid"] = self.__username - values["exch"] = exchange - values["stext"] = urllib.parse.quote_plus(searchtext) - + + values = {} + values["uid"] = self.__username + values["exch"] = exchange + values["stext"] = urllib.parse.quote_plus(searchtext) + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) @@ -780,29 +817,27 @@ def searchscrip(self, exchange, searchtext): resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': - return None + if resDict['stat'] != 'Ok': + return None return resDict def get_option_chain(self, exchange, tradingsymbol, strikeprice, count=2): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['optionchain']}" + # prepare the uri + url = f"{config['host']}{config['routes']['optionchain']}" reportmsg(url) - - - values = {} - values["uid"] = self.__username - values["exch"] = exchange - values["tsym"] = urllib.parse.quote_plus(tradingsymbol) - values["strprc"] = str(strikeprice) - values["cnt"] = str(count) - - + + values = {} + values["uid"] = self.__username + values["exch"] = exchange + values["tsym"] = urllib.parse.quote_plus(tradingsymbol) + values["strprc"] = str(strikeprice) + values["cnt"] = str(count) + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) @@ -810,25 +845,25 @@ def get_option_chain(self, exchange, tradingsymbol, strikeprice, count=2): resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': - return None + if resDict['stat'] != 'Ok': + return None return resDict def get_security_info(self, exchange, token): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['scripinfo']}" - reportmsg(url) - - values = {} - values["uid"] = self.__username - values["exch"] = exchange - values["token"] = token - + # prepare the uri + url = f"{config['host']}{config['routes']['scripinfo']}" + reportmsg(url) + + values = {} + values["uid"] = self.__username + values["exch"] = exchange + values["token"] = token + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) @@ -836,25 +871,25 @@ def get_security_info(self, exchange, token): resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': - return None + if resDict['stat'] != 'Ok': + return None return resDict def get_quotes(self, exchange, token): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['getquotes']}" - reportmsg(url) - - values = {} - values["uid"] = self.__username - values["exch"] = exchange - values["token"] = token - + # prepare the uri + url = f"{config['host']}{config['routes']['getquotes']}" + reportmsg(url) + + values = {} + values["uid"] = self.__username + values["exch"] = exchange + values["token"] = token + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) @@ -862,79 +897,79 @@ def get_quotes(self, exchange, token): resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': - return None + if resDict['stat'] != 'Ok': + return None return resDict - def get_time_price_series(self, exchange, token, starttime=None, endtime=None, interval= None): + def get_time_price_series(self, exchange, token, starttime=None, endtime=None, interval=None): ''' gets the chart data interval possible values 1, 3, 5 , 10, 15, 30, 60, 120, 240 ''' config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['TPSeries']}" + # prepare the uri + url = f"{config['host']}{config['routes']['TPSeries']}" reportmsg(url) - #prepare the data + # prepare the data if starttime == None: timestring = time.strftime('%d-%m-%Y') + ' 00:00:00' - timeobj = time.strptime(timestring,'%d-%m-%Y %H:%M:%S') + timeobj = time.strptime(timestring, '%d-%m-%Y %H:%M:%S') starttime = time.mktime(timeobj) # - values = {'ordersource':'API'} - values["uid"] = self.__username - values["exch"] = exchange - values["token"] = token + values = {'ordersource': 'API'} + values["uid"] = self.__username + values["exch"] = exchange + values["token"] = token values["st"] = str(starttime) if endtime != None: - values["et"] = str(endtime) + values["et"] = str(endtime) if interval != None: values["intrv"] = str(interval) payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) resDict = json.loads(res.text) - - #error is a json with stat and msg wchih we printed earlier. - if type(resDict) != list: - return None + + # error is a json with stat and msg wchih we printed earlier. + if type(resDict) != list: + return None return resDict def get_daily_price_series(self, exchange, tradingsymbol, startdate=None, enddate=None): config = NorenApi.__service_config - #prepare the uri - #url = f"{config['eoddata_endpoint']}" - url = f"{config['host']}{config['routes']['get_daily_price_series']}" + # prepare the uri + # url = f"{config['eoddata_endpoint']}" + url = f"{config['host']}{config['routes']['get_daily_price_series']}" reportmsg(url) - #prepare the data - if startdate == None: + # prepare the data + if startdate == None: week_ago = datetime.date.today() - datetime.timedelta(days=7) startdate = dt.combine(week_ago, dt.min.time()).timestamp() - if enddate == None: + if enddate == None: enddate = dt.now().timestamp() # - values = {} - values["uid"] = self.__username - values["sym"] = '{0}:{1}'.format(exchange, tradingsymbol) - values["from"] = str(startdate) - values["to"] = str(enddate) - + values = {} + values["uid"] = self.__username + values["sym"] = '{0}:{1}'.format(exchange, tradingsymbol) + values["from"] = str(startdate) + values["to"] = str(enddate) + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - #payload = json.dumps(values) + # payload = json.dumps(values) reportmsg(payload) headers = {"Content-Type": "application/json; charset=utf-8"} @@ -948,30 +983,30 @@ def get_daily_price_series(self, exchange, tradingsymbol, startdate=None, enddat return None resDict = json.loads(res.text) - - #error is a json with stat and msg wchih we printed earlier. - if type(resDict) != list: + + # error is a json with stat and msg wchih we printed earlier. + if type(resDict) != list: return None return resDict - - def get_holdings(self, product_type = None): + + def get_holdings(self, product_type=None): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['holdings']}" + # prepare the uri + url = f"{config['host']}{config['routes']['holdings']}" reportmsg(url) - + if product_type == None: product_type = ProductType.Delivery - - values = {} - values["uid"] = self.__username - values["actid"] = self.__accountid - values["prd"] = product_type - + + values = {} + values["uid"] = self.__username + values["actid"] = self.__accountid + values["prd"] = product_type + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) @@ -979,55 +1014,55 @@ def get_holdings(self, product_type = None): resDict = json.loads(res.text) - if type(resDict) != list: - return None + if type(resDict) != list: + return None return resDict - def get_limits(self, product_type = None, segment = None, exchange = None): + def get_limits(self, product_type=None, segment=None, exchange=None): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['limits']}" - reportmsg(url) - - values = {} - values["uid"] = self.__username - values["actid"] = self.__accountid - + # prepare the uri + url = f"{config['host']}{config['routes']['limits']}" + reportmsg(url) + + values = {} + values["uid"] = self.__username + values["actid"] = self.__accountid + if product_type != None: - values["prd"] = product_type - + values["prd"] = product_type + if product_type != None: - values["seg"] = segment - + values["seg"] = segment + if exchange != None: - values["exch"] = exchange - + values["exch"] = exchange + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) - resDict = json.loads(res.text) + resDict = json.loads(res.text) return resDict def get_positions(self): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['positions']}" - reportmsg(url) - - values = {} - values["uid"] = self.__username - values["actid"] = self.__accountid - + # prepare the uri + url = f"{config['host']}{config['routes']['positions']}" + reportmsg(url) + + values = {} + values["uid"] = self.__username + values["actid"] = self.__accountid + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) @@ -1035,54 +1070,159 @@ def get_positions(self): resDict = json.loads(res.text) - if type(resDict) != list: + if type(resDict) != list: return None return resDict - def span_calculator(self,actid,positions:list): + def span_calculator(self, positions: list): config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['span_calculator']}" - reportmsg(url) + # prepare the uri + url = f"{config['host']}{config['routes']['span_calculator']}" + reportmsg(url) senddata = {} - senddata['actid'] =self.__accountid + senddata['actid'] = self.__accountid senddata['pos'] = positions - payload = 'jData=' + json.dumps(senddata,default=lambda o: o.encode())+ f'&jKey={self.__susertoken}' + payload = 'jData=' + \ + json.dumps(senddata, default=lambda o: o.encode()) + \ + f'&jKey={self.__susertoken}' reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) - resDict = json.loads(res.text) + resDict = json.loads(res.text) return resDict - - def option_greek(self,expiredate,StrikePrice,SpotPrice,InterestRate,Volatility,OptionType): - config = NorenApi.__service_config - #prepare the uri - url = f"{config['host']}{config['routes']['option_greek']}" + def option_greek(self, expiredate, StrikePrice, SpotPrice, InterestRate, Volatility, OptionType): + config = NorenApi.__service_config + + # prepare the uri + url = f"{config['host']}{config['routes']['option_greek']}" reportmsg(url) - #prepare the data - values = { "source": "API" } - values["actid"] = self.__accountid - values["exd"] = expiredate - values["strprc"] = StrikePrice - values["sptprc"] = SpotPrice - values["int_rate"] = InterestRate + # prepare the data + values = {"source": "API"} + values["actid"] = self.__accountid + values["exd"] = expiredate + values["strprc"] = StrikePrice + values["sptprc"] = SpotPrice + values["int_rate"] = InterestRate values["volatility"] = Volatility - values["optt"] = OptionType + values["optt"] = OptionType + + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + + reportmsg(payload) + + res = requests.post(url, data=payload) + reportmsg(res.text) + + resDict = json.loads(res.text) + + return resDict + + def get_pending_gtt_orders(self): + config = NorenApi.__service_config + + # prepare the uri + url = f"{config['host']}{config['routes']['gtt']}" + reportmsg(url) + + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username + + payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + + reportmsg(payload) + + res = requests.post(url, data=payload) + reportmsg(res.text) + + resDict = json.loads(res.text) + + # error is a json with stat and msg wchih we printed earlier. + if type(resDict) != list: + return None + + return resDict + + def get_enabled_gtt_orders(self): + config = NorenApi.__service_config + + # prepare the uri + url = f"{config['host']}{config['routes']['enabledgtt']}" + reportmsg(url) + + # prepare the data + values = {'ordersource': 'API'} + values["uid"] = self.__username payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' - + reportmsg(payload) res = requests.post(url, data=payload) reportmsg(res.text) - resDict = json.loads(res.text) + resDict = json.loads(res.text) + + # error is a json with stat and msg wchih we printed earlier. + if type(resDict) != list: + return None return resDict + + def place_gtt_order( + self, + tradingsymbol, + exchange, + alert_type, # 'LTP_A_O' or 'LTP_B_O' + alert_price, + buy_or_sell, # 'B' or 'S' + product_type, # 'I' Intraday, 'C' Delivery, 'M' Normal Margin for options + quantity, + price_type='MKT', + price=0.0, + remarks = None, + retention= 'DAY', + validity = 'GTT', + discloseqty=0, + ): + # prepare the uri + config = NorenApi.__service_config + url = f"{config['host']}{config['routes']['placegtt']}" + reportmsg(url) + + # prepare the data + values = {"ordersource": "API"} + values["uid"] = self.__username + values["actid"] = self.__accountid + values["tsym"] = urllib.parse.quote_plus(tradingsymbol) + values["exch"] = exchange + values["ai_t"] = alert_type + values["validity"] = validity + values["d"] = str(alert_price) + values["remarks"] = remarks + values["trantype"] = buy_or_sell + values["prctyp"] = price_type + values["prd"] = product_type + values["ret"] = retention + values["qty"] = str(quantity) + values["prc"] = str(price) + values["dscqty"] = str(discloseqty) + + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" + reportmsg(payload) + + res = requests.post(url, data=payload) + reportmsg(res.text) + + resDict = json.loads(res.text) + if resDict["stat"] != "OI created": + return None + + return resDict['al_id'] \ No newline at end of file From 59452c08155501c36b4cd96dd19efdb340b57779 Mon Sep 17 00:00:00 2001 From: Rahul Raut Date: Sun, 8 Jan 2023 00:57:59 +0530 Subject: [PATCH 2/3] Added code for OCO gtt order Fixed formatting Updated README for example code. --- NorenRestApiPy/NorenApi.py | 652 ++++++++++++++++++++++++------------- README.md | 80 +++++ 2 files changed, 508 insertions(+), 224 deletions(-) diff --git a/NorenRestApiPy/NorenApi.py b/NorenRestApiPy/NorenApi.py index 10cc545..e4490db 100644 --- a/NorenRestApiPy/NorenApi.py +++ b/NorenRestApiPy/NorenApi.py @@ -30,33 +30,35 @@ def encode(self): return self.__dict__ -class ProductType: - Delivery = 'C' - Intraday = 'I' - Normal = 'M' - CF = 'M' +class ProductType(Enum): + Delivery = "C" + Intraday = "I" + Normal = "M" + CF = "M" -class FeedType: +class FeedType(Enum): TOUCHLINE = 1 SNAPQUOTE = 2 -class PriceType: - Market = 'MKT' - Limit = 'LMT' - StopLossLimit = 'SL-LMT' - StopLossMarket = 'SL-MKT' +class PriceType(Enum): + Market = "MKT" + Limit = "LMT" + StopLossLimit = "SL-LMT" + StopLossMarket = "SL-MKT" -class BuyorSell: - Buy = 'B' - Sell = 'S' +class BuyorSell(Enum): + Buy = "B" + Sell = "S" + + +class AlertType(Enum): + LTP_ABOVE = "LTP_A_O" + LTP_BELOW = "LTP_B_O" + LTP_OCO = "LMT_BOS_O" -class AlertType: - LTP_ABOVE = 'LTP_A_O' - LTP_BELOW = 'LTP_B_O' - LTP_OCO = 'LMT_BOS_O' def reportmsg(msg): # print(msg) @@ -75,68 +77,69 @@ def reportinfo(msg): class NorenApi(object): - TRANSACTION_TYPE_SELL = 'S' - TRANSACTION_TYPE_BUY = 'B' - - PRODUCT_TYPE_INTRADAY = 'I' - PRODUCT_TYPE_DELIVERY = 'C' - PRODUCT_TYPE_NORMAL = 'M' + TRANSACTION_TYPE_SELL = "S" + TRANSACTION_TYPE_BUY = "B" + + PRODUCT_TYPE_INTRADAY = "I" + PRODUCT_TYPE_DELIVERY = "C" + PRODUCT_TYPE_NORMAL = "M" - PRICE_TYPE_MARKET = 'MKT' - PRICE_TYPE_LIMIT = 'LMT' - PRICE_TYPE_STOPLOSS_LIMIT = 'SL-LMT' - PRICE_TYPE_STOPLOSS_MARKET = 'SL-MKT' + PRICE_TYPE_MARKET = "MKT" + PRICE_TYPE_LIMIT = "LMT" + PRICE_TYPE_STOPLOSS_LIMIT = "SL-LMT" + PRICE_TYPE_STOPLOSS_MARKET = "SL-MKT" - ALERT_TYPE_ABOVE = 'LTP_A_O' - ALERT_TYPE_BELOW = 'LTP_B_O' - ALERT_TYPE_OCO = 'LTP_BOS_O' + ALERT_TYPE_ABOVE = "LTP_A_O" + ALERT_TYPE_BELOW = "LTP_B_O" + ALERT_TYPE_OCO = "LMT_BOS_O" FEED_TYPE_TOUCHLINE = 1 FEED_TYPE_SNAPSHOT = 2 __service_config = { - 'host': 'http://wsapihost/', - 'routes': { - 'authorize': '/QuickAuth', - 'logout': '/Logout', - 'forgot_password': '/ForgotPassword', - 'change_password': '/Changepwd', - 'watchlist_names': '/MWList', - 'watchlist': '/MarketWatch', - 'watchlist_add': '/AddMultiScripsToMW', - 'watchlist_delete': '/DeleteMultiMWScrips', - 'placeorder': '/PlaceOrder', - 'modifyorder': '/ModifyOrder', - 'cancelorder': '/CancelOrder', - 'exitorder': '/ExitSNOOrder', - 'product_conversion': '/ProductConversion', - 'orderbook': '/OrderBook', - 'tradebook': '/TradeBook', - 'singleorderhistory': '/SingleOrdHist', - 'searchscrip': '/SearchScrip', - 'TPSeries': '/TPSeries', - 'optionchain': '/GetOptionChain', - 'holdings': '/Holdings', - 'limits': '/Limits', - 'positions': '/PositionBook', - 'scripinfo': '/GetSecurityInfo', - 'getquotes': '/GetQuotes', - 'span_calculator': '/SpanCalc', - 'option_greek': '/GetOptionGreek', - 'get_daily_price_series': '/EODChartData', + "host": "http://wsapihost/", + "routes": { + "authorize": "/QuickAuth", + "logout": "/Logout", + "forgot_password": "/ForgotPassword", + "change_password": "/Changepwd", + "watchlist_names": "/MWList", + "watchlist": "/MarketWatch", + "watchlist_add": "/AddMultiScripsToMW", + "watchlist_delete": "/DeleteMultiMWScrips", + "placeorder": "/PlaceOrder", + "modifyorder": "/ModifyOrder", + "cancelorder": "/CancelOrder", + "exitorder": "/ExitSNOOrder", + "product_conversion": "/ProductConversion", + "orderbook": "/OrderBook", + "tradebook": "/TradeBook", + "singleorderhistory": "/SingleOrdHist", + "searchscrip": "/SearchScrip", + "TPSeries": "/TPSeries", + "optionchain": "/GetOptionChain", + "holdings": "/Holdings", + "limits": "/Limits", + "positions": "/PositionBook", + "scripinfo": "/GetSecurityInfo", + "getquotes": "/GetQuotes", + "span_calculator": "/SpanCalc", + "option_greek": "/GetOptionGreek", + "get_daily_price_series": "/EODChartData", "placegtt": "/PlaceGTTOrder", "gtt": "/GetPendingGTTOrder", "enabledgtt": "/GetEnabledGTTs", "cancelgtt": "/CancelGTTOrder", - "ocogtt": "/PlaceOCOOrder" + "ocogtt": "/PlaceOCOOrder", + "modifyoco": "/ModifyOCOOrder", }, - 'websocket_endpoint': 'wss://wsendpoint/', + "websocket_endpoint": "wss://wsendpoint/", # 'eoddata_endpoint' : 'http://eodhost/' } def __init__(self, host, websocket): - self.__service_config['host'] = host - self.__service_config['websocket_endpoint'] = websocket + self.__service_config["host"] = host + self.__service_config["websocket_endpoint"] = websocket # self.__service_config['eoddata_endpoint'] = eodhost self.__websocket = None @@ -155,11 +158,9 @@ def __ws_run_forever(self): while self.__stop_event.is_set() == False: try: - self.__websocket.run_forever( - ping_interval=3, ping_payload='{"t":"h"}') + self.__websocket.run_forever(ping_interval=3, ping_payload='{"t":"h"}') except Exception as e: - logger.warning( - f"websocket run forever ended in exception, {e}") + logger.warning(f"websocket run forever ended in exception, {e}") sleep(0.1) # Sleep for 100ms between reconnection. @@ -187,7 +188,7 @@ def __on_open_callback(self, ws=None): values["uid"] = self.__username values["actid"] = self.__username values["susertoken"] = self.__susertoken - values["source"] = 'API' + values["source"] = "API" payload = json.dumps(values) @@ -197,12 +198,16 @@ def __on_open_callback(self, ws=None): # self.__resubscribe() def __on_error_callback(self, ws=None, error=None): - if (type(ws) is not websocket.WebSocketApp): # This workaround is to solve the websocket_client's compatiblity issue of older versions. ie.0.40.0 which is used in upstox. Now this will work in both 0.40.0 & newer version of websocket_client + if ( + type(ws) is not websocket.WebSocketApp + ): # This workaround is to solve the websocket_client's compatiblity issue of older versions. ie.0.40.0 which is used in upstox. Now this will work in both 0.40.0 & newer version of websocket_client error = ws if self.__on_error: self.__on_error(error) - def __on_data_callback(self, ws=None, message=None, data_type=None, continue_flag=None): + def __on_data_callback( + self, ws=None, message=None, data_type=None, continue_flag=None + ): # print(ws) # print(message) # print(data_type) @@ -210,50 +215,56 @@ def __on_data_callback(self, ws=None, message=None, data_type=None, continue_fla res = json.loads(message) - if (self.__subscribe_callback is not None): - if res['t'] == 'tk' or res['t'] == 'tf': + if self.__subscribe_callback is not None: + if res["t"] == "tk" or res["t"] == "tf": self.__subscribe_callback(res) return - if res['t'] == 'dk' or res['t'] == 'df': + if res["t"] == "dk" or res["t"] == "df": self.__subscribe_callback(res) return - if (self.__on_error is not None): - if res['t'] == 'ck' and res['s'] != 'OK': + if self.__on_error is not None: + if res["t"] == "ck" and res["s"] != "OK": self.__on_error(res) return - if (self.__order_update_callback is not None): - if res['t'] == 'om': + if self.__order_update_callback is not None: + if res["t"] == "om": self.__order_update_callback(res) return if self.__on_open: - if res['t'] == 'ck' and res['s'] == 'OK': + if res["t"] == "ck" and res["s"] == "OK": self.__on_open() return - def start_websocket(self, subscribe_callback=None, - order_update_callback=None, - socket_open_callback=None, - socket_close_callback=None, - socket_error_callback=None): - """ Start a websocket connection for getting live data """ + def start_websocket( + self, + subscribe_callback=None, + order_update_callback=None, + socket_open_callback=None, + socket_close_callback=None, + socket_error_callback=None, + ): + """Start a websocket connection for getting live data""" self.__on_open = socket_open_callback self.__on_disconnect = socket_close_callback self.__on_error = socket_error_callback self.__subscribe_callback = subscribe_callback self.__order_update_callback = order_update_callback self.__stop_event = threading.Event() - url = self.__service_config['websocket_endpoint'].format( - access_token=self.__susertoken) - reportmsg('connecting to {}'.format(url)) - - self.__websocket = websocket.WebSocketApp(url, - on_data=self.__on_data_callback, - on_error=self.__on_error_callback, - on_close=self.__on_close_callback, - on_open=self.__on_open_callback) + url = self.__service_config["websocket_endpoint"].format( + access_token=self.__susertoken + ) + reportmsg("connecting to {}".format(url)) + + self.__websocket = websocket.WebSocketApp( + url, + on_data=self.__on_data_callback, + on_error=self.__on_error_callback, + on_close=self.__on_close_callback, + on_open=self.__on_open_callback, + ) # th = threading.Thread(target=self.__send_heartbeat) # th.daemon = True # th.start() @@ -278,9 +289,9 @@ def login(self, userid, password, twoFA, vendor_code, api_secret, imei): reportmsg(url) # Convert to SHA 256 for password and app key - pwd = hashlib.sha256(password.encode('utf-8')).hexdigest() - u_app_key = '{0}|{1}'.format(userid, api_secret) - app_key = hashlib.sha256(u_app_key.encode('utf-8')).hexdigest() + pwd = hashlib.sha256(password.encode("utf-8")).hexdigest() + u_app_key = "{0}|{1}".format(userid, api_secret) + app_key = hashlib.sha256(u_app_key.encode("utf-8")).hexdigest() # prepare the data values = {"source": "API", "apkversion": "1.0.0"} values["uid"] = userid @@ -290,20 +301,20 @@ def login(self, userid, password, twoFA, vendor_code, api_secret, imei): values["appkey"] = app_key values["imei"] = imei - payload = 'jData=' + json.dumps(values) + payload = "jData=" + json.dumps(values) reportmsg("Req:" + payload) res = requests.post(url, data=payload) reportmsg("Reply:" + res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None self.__username = userid self.__accountid = userid self.__password = password - self.__susertoken = resDict['susertoken'] + self.__susertoken = resDict["susertoken"] # reportmsg(self.__susertoken) return resDict @@ -315,7 +326,7 @@ def set_session(self, userid, password, usertoken): self.__password = password self.__susertoken = usertoken - reportmsg(f'{userid} session set to : {self.__susertoken}') + reportmsg(f"{userid} session set to : {self.__susertoken}") return True @@ -332,7 +343,7 @@ def forgot_password(self, userid, pan, dob): values["pan"] = pan values["dob"] = dob - payload = 'jData=' + json.dumps(values) + payload = "jData=" + json.dumps(values) reportmsg("Req:" + payload) res = requests.post(url, data=payload) @@ -340,7 +351,7 @@ def forgot_password(self, userid, pan, dob): resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None return resDict @@ -352,10 +363,10 @@ def logout(self): url = f"{config['host']}{config['routes']['logout']}" reportmsg(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -363,7 +374,7 @@ def logout(self): reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None self.__username = None @@ -376,17 +387,17 @@ def logout(self): def subscribe(self, instrument, feed_type=FeedType.TOUCHLINE): values = {} - if (feed_type == FeedType.TOUCHLINE): - values['t'] = 't' - elif (feed_type == FeedType.SNAPQUOTE): - values['t'] = 'd' + if feed_type == FeedType.TOUCHLINE: + values["t"] = "t" + elif feed_type == FeedType.SNAPQUOTE: + values["t"] = "d" else: - values['t'] = str(feed_type) + values["t"] = str(feed_type) if type(instrument) == list: - values['k'] = '#'.join(instrument) + values["k"] = "#".join(instrument) else: - values['k'] = instrument + values["k"] = instrument data = json.dumps(values) @@ -396,15 +407,15 @@ def subscribe(self, instrument, feed_type=FeedType.TOUCHLINE): def unsubscribe(self, instrument, feed_type=FeedType.TOUCHLINE): values = {} - if (feed_type == FeedType.TOUCHLINE): - values['t'] = 'u' - elif (feed_type == FeedType.SNAPQUOTE): - values['t'] = 'ud' + if feed_type == FeedType.TOUCHLINE: + values["t"] = "u" + elif feed_type == FeedType.SNAPQUOTE: + values["t"] = "ud" if type(instrument) == list: - values['k'] = '#'.join(instrument) + values["k"] = "#".join(instrument) else: - values['k'] = instrument + values["k"] = instrument data = json.dumps(values) @@ -412,8 +423,8 @@ def unsubscribe(self, instrument, feed_type=FeedType.TOUCHLINE): self.__ws_send(data) def subscribe_orders(self): - values = {'t': 'o'} - values['actid'] = self.__accountid + values = {"t": "o"} + values["actid"] = self.__accountid data = json.dumps(values) @@ -427,10 +438,10 @@ def get_watch_list_names(self): url = f"{config['host']}{config['routes']['watchlist_names']}" reportmsg(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -438,7 +449,7 @@ def get_watch_list_names(self): reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None return resDict @@ -450,11 +461,11 @@ def get_watch_list(self, wlname): url = f"{config['host']}{config['routes']['watchlist']}" reportmsg(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username values["wlname"] = wlname - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -462,7 +473,7 @@ def get_watch_list(self, wlname): reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None return resDict @@ -474,15 +485,15 @@ def add_watch_list_scrip(self, wlname, instrument): url = f"{config['host']}{config['routes']['watchlist_add']}" reportmsg(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username values["wlname"] = wlname if type(instrument) == list: - values['scrips'] = '#'.join(instrument) + values["scrips"] = "#".join(instrument) else: - values['scrips'] = instrument - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + values["scrips"] = instrument + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -490,7 +501,7 @@ def add_watch_list_scrip(self, wlname, instrument): reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None return resDict @@ -502,15 +513,15 @@ def delete_watch_list_scrip(self, wlname, instrument): url = f"{config['host']}{config['routes']['watchlist_delete']}" reportmsg(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username values["wlname"] = wlname if type(instrument) == list: - values['scrips'] = '#'.join(instrument) + values["scrips"] = "#".join(instrument) else: - values['scrips'] = instrument - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + values["scrips"] = instrument + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -518,22 +529,36 @@ def delete_watch_list_scrip(self, wlname, instrument): reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None return resDict - def place_order(self, buy_or_sell, product_type, - exchange, tradingsymbol, quantity, discloseqty, - price_type, price=0.0, trigger_price=None, - retention='DAY', amo='NO', remarks=None, bookloss_price=0.0, bookprofit_price=0.0, trail_price=0.0): + def place_order( + self, + buy_or_sell, + product_type, + exchange, + tradingsymbol, + quantity, + discloseqty, + price_type, + price=0.0, + trigger_price=None, + retention="DAY", + amo="NO", + remarks=None, + bookloss_price=0.0, + bookprofit_price=0.0, + trail_price=0.0, + ): config = NorenApi.__service_config # prepare the uri url = f"{config['host']}{config['routes']['placeorder']}" reportmsg(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username values["actid"] = self.__accountid values["trantype"] = buy_or_sell @@ -550,21 +575,21 @@ def place_order(self, buy_or_sell, product_type, values["amo"] = amo # if cover order or high leverage order - if product_type == 'H': + if product_type == "H": values["blprc"] = str(bookloss_price) # trailing price if trail_price != 0.0: values["trailprc"] = str(trail_price) # bracket order - if product_type == 'B': + if product_type == "B": values["blprc"] = str(bookloss_price) values["bpprc"] = str(bookprofit_price) # trailing price if trail_price != 0.0: values["trailprc"] = str(trail_price) - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -572,13 +597,24 @@ def place_order(self, buy_or_sell, product_type, reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None return resDict - def modify_order(self, orderno, exchange, tradingsymbol, newquantity, - newprice_type, newprice=0.0, newtrigger_price=None, bookloss_price=0.0, bookprofit_price=0.0, trail_price=0.0): + def modify_order( + self, + orderno, + exchange, + tradingsymbol, + newquantity, + newprice_type, + newprice=0.0, + newtrigger_price=None, + bookloss_price=0.0, + bookprofit_price=0.0, + trail_price=0.0, + ): config = NorenApi.__service_config # prepare the uri @@ -586,7 +622,7 @@ def modify_order(self, orderno, exchange, tradingsymbol, newquantity, print(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username values["actid"] = self.__accountid values["norenordno"] = str(orderno) @@ -596,11 +632,11 @@ def modify_order(self, orderno, exchange, tradingsymbol, newquantity, values["prctyp"] = newprice_type values["prc"] = str(newprice) - if (newprice_type == 'SL-LMT') or (newprice_type == 'SL-MKT'): - if (newtrigger_price != None): + if (newprice_type == "SL-LMT") or (newprice_type == "SL-MKT"): + if newtrigger_price != None: values["trgprc"] = str(newtrigger_price) else: - reporterror('trigger price is missing') + reporterror("trigger price is missing") return None # if cover order or high leverage order @@ -613,7 +649,7 @@ def modify_order(self, orderno, exchange, tradingsymbol, newquantity, if bookprofit_price != 0.0: values["bpprc"] = str(bookprofit_price) - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -621,7 +657,7 @@ def modify_order(self, orderno, exchange, tradingsymbol, newquantity, reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None return resDict @@ -634,11 +670,11 @@ def cancel_order(self, orderno): print(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username values["norenordno"] = str(orderno) - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -646,7 +682,7 @@ def cancel_order(self, orderno): print(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None return resDict @@ -659,12 +695,12 @@ def exit_order(self, orderno, product_type): print(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username values["norenordno"] = orderno values["prd"] = product_type - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -672,15 +708,24 @@ def exit_order(self, orderno, product_type): reportmsg(res.text) resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None return resDict - def position_product_conversion(self, exchange, tradingsymbol, quantity, new_product_type, previous_product_type, buy_or_sell, day_or_cf): - ''' - Coverts a day or carryforward position from one product to another. - ''' + def position_product_conversion( + self, + exchange, + tradingsymbol, + quantity, + new_product_type, + previous_product_type, + buy_or_sell, + day_or_cf, + ): + """ + Coverts a day or carryforward position from one product to another. + """ config = NorenApi.__service_config # prepare the uri @@ -688,7 +733,7 @@ def position_product_conversion(self, exchange, tradingsymbol, quantity, new_pro print(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username values["actid"] = self.__accountid values["exch"] = exchange @@ -699,7 +744,7 @@ def position_product_conversion(self, exchange, tradingsymbol, quantity, new_pro values["trantype"] = buy_or_sell values["postype"] = day_or_cf - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -708,7 +753,7 @@ def position_product_conversion(self, exchange, tradingsymbol, quantity, new_pro resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None return resDict @@ -721,11 +766,11 @@ def single_order_history(self, orderno): print(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username values["norenordno"] = orderno - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -747,10 +792,10 @@ def get_order_book(self): reportmsg(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -773,11 +818,11 @@ def get_trade_book(self): reportmsg(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username values["actid"] = self.__accountid - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -800,7 +845,7 @@ def searchscrip(self, exchange, searchtext): reportmsg(url) if searchtext == None: - reporterror('search text cannot be null') + reporterror("search text cannot be null") return None values = {} @@ -808,7 +853,7 @@ def searchscrip(self, exchange, searchtext): values["exch"] = exchange values["stext"] = urllib.parse.quote_plus(searchtext) - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -817,7 +862,7 @@ def searchscrip(self, exchange, searchtext): resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None return resDict @@ -836,7 +881,7 @@ def get_option_chain(self, exchange, tradingsymbol, strikeprice, count=2): values["strprc"] = str(strikeprice) values["cnt"] = str(count) - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -845,7 +890,7 @@ def get_option_chain(self, exchange, tradingsymbol, strikeprice, count=2): resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None return resDict @@ -862,7 +907,7 @@ def get_security_info(self, exchange, token): values["exch"] = exchange values["token"] = token - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -871,7 +916,7 @@ def get_security_info(self, exchange, token): resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None return resDict @@ -888,7 +933,7 @@ def get_quotes(self, exchange, token): values["exch"] = exchange values["token"] = token - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -897,16 +942,18 @@ def get_quotes(self, exchange, token): resDict = json.loads(res.text) - if resDict['stat'] != 'Ok': + if resDict["stat"] != "Ok": return None return resDict - def get_time_price_series(self, exchange, token, starttime=None, endtime=None, interval=None): - ''' - gets the chart data + def get_time_price_series( + self, exchange, token, starttime=None, endtime=None, interval=None + ): + """ + gets the chart data interval possible values 1, 3, 5 , 10, 15, 30, 60, 120, 240 - ''' + """ config = NorenApi.__service_config # prepare the uri @@ -915,12 +962,12 @@ def get_time_price_series(self, exchange, token, starttime=None, endtime=None, i # prepare the data if starttime == None: - timestring = time.strftime('%d-%m-%Y') + ' 00:00:00' - timeobj = time.strptime(timestring, '%d-%m-%Y %H:%M:%S') + timestring = time.strftime("%d-%m-%Y") + " 00:00:00" + timeobj = time.strptime(timestring, "%d-%m-%Y %H:%M:%S") starttime = time.mktime(timeobj) # - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username values["exch"] = exchange values["token"] = token @@ -930,7 +977,7 @@ def get_time_price_series(self, exchange, token, starttime=None, endtime=None, i if interval != None: values["intrv"] = str(interval) - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -945,7 +992,9 @@ def get_time_price_series(self, exchange, token, starttime=None, endtime=None, i return resDict - def get_daily_price_series(self, exchange, tradingsymbol, startdate=None, enddate=None): + def get_daily_price_series( + self, exchange, tradingsymbol, startdate=None, enddate=None + ): config = NorenApi.__service_config # prepare the uri @@ -964,11 +1013,11 @@ def get_daily_price_series(self, exchange, tradingsymbol, startdate=None, enddat # values = {} values["uid"] = self.__username - values["sym"] = '{0}:{1}'.format(exchange, tradingsymbol) + values["sym"] = "{0}:{1}".format(exchange, tradingsymbol) values["from"] = str(startdate) values["to"] = str(enddate) - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" # payload = json.dumps(values) reportmsg(payload) @@ -1005,7 +1054,7 @@ def get_holdings(self, product_type=None): values["actid"] = self.__accountid values["prd"] = product_type - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -1039,7 +1088,7 @@ def get_limits(self, product_type=None, segment=None, exchange=None): if exchange != None: values["exch"] = exchange - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -1061,7 +1110,7 @@ def get_positions(self): values["uid"] = self.__username values["actid"] = self.__accountid - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -1082,11 +1131,13 @@ def span_calculator(self, positions: list): reportmsg(url) senddata = {} - senddata['actid'] = self.__accountid - senddata['pos'] = positions - payload = 'jData=' + \ - json.dumps(senddata, default=lambda o: o.encode()) + \ - f'&jKey={self.__susertoken}' + senddata["actid"] = self.__accountid + senddata["pos"] = positions + payload = ( + "jData=" + + json.dumps(senddata, default=lambda o: o.encode()) + + f"&jKey={self.__susertoken}" + ) reportmsg(payload) res = requests.post(url, data=payload) @@ -1096,7 +1147,9 @@ def span_calculator(self, positions: list): return resDict - def option_greek(self, expiredate, StrikePrice, SpotPrice, InterestRate, Volatility, OptionType): + def option_greek( + self, expiredate, StrikePrice, SpotPrice, InterestRate, Volatility, OptionType + ): config = NorenApi.__service_config # prepare the uri @@ -1113,7 +1166,7 @@ def option_greek(self, expiredate, StrikePrice, SpotPrice, InterestRate, Volatil values["volatility"] = Volatility values["optt"] = OptionType - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -1132,10 +1185,10 @@ def get_pending_gtt_orders(self): reportmsg(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -1149,7 +1202,7 @@ def get_pending_gtt_orders(self): return None return resDict - + def get_enabled_gtt_orders(self): config = NorenApi.__service_config @@ -1158,10 +1211,10 @@ def get_enabled_gtt_orders(self): reportmsg(url) # prepare the data - values = {'ordersource': 'API'} + values = {"ordersource": "API"} values["uid"] = self.__username - payload = 'jData=' + json.dumps(values) + f'&jKey={self.__susertoken}' + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" reportmsg(payload) @@ -1173,24 +1226,48 @@ def get_enabled_gtt_orders(self): # error is a json with stat and msg wchih we printed earlier. if type(resDict) != list: return None - return resDict - + + def cancelgtt(self, alert_id): + config = NorenApi.__service_config + + # prepare the uri + url = f"{config['host']}{config['routes']['cancelgtt']}" + reportmsg(url) + + # prepare the data + values = {"ordersource": "API"} + values["uid"] = self.__username + values["al_id"] = str(alert_id) + + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" + reportmsg(payload) + + res = requests.post(url, data=payload) + reportmsg(res.text) + + resDict = json.loads(res.text) + + # error is a json with stat and msg wchih we printed earlier. + if resDict["stat"] != "OI deleted": + return None + return resDict["al_id"] + def place_gtt_order( self, - tradingsymbol, - exchange, - alert_type, # 'LTP_A_O' or 'LTP_B_O' - alert_price, - buy_or_sell, # 'B' or 'S' - product_type, # 'I' Intraday, 'C' Delivery, 'M' Normal Margin for options - quantity, - price_type='MKT', - price=0.0, - remarks = None, - retention= 'DAY', - validity = 'GTT', - discloseqty=0, + tradingsymbol: str, + exchange: str, + alert_type: str, # 'LTP_A_O' or 'LTP_B_O' + alert_price: float, + buy_or_sell: str, # 'B' or 'S' + product_type: str, # 'I' Intraday, 'C' Delivery, 'M' Normal Margin for options + quantity: int, + price_type: str = "MKT", + price: float = 0.0, + remarks: str = None, + retention: str = "DAY", + validity: str = "GTT", + discloseqty: int = 0, ): # prepare the uri config = NorenApi.__service_config @@ -1225,4 +1302,131 @@ def place_gtt_order( if resDict["stat"] != "OI created": return None - return resDict['al_id'] \ No newline at end of file + return resDict["al_id"] + + def place_gtt_oco_mkt_order( + self, + tradingsymbol, + exchange, + alert_price_above_1, + alert_price_below_2, + buy_or_sell, # 'B' or 'S' + product_type, # 'I' Intraday, 'C' Delivery, 'M' Normal Margin for options + quantity, + remarks="PLACE_OCO_MKT", + ): + # prepare the uri + config = NorenApi.__service_config + url = f"{config['host']}{config['routes']['ocogtt']}" + reportmsg(url) + + retention = "DAY" + validity = "GTT" + price_type = self.PRICE_TYPE_MARKET + price = 0.0 + + oivariable = [ + {"d": str(alert_price_above_1), "var_name": "x"}, + {"d": str(alert_price_below_2), "var_name": "y"}, + ] + + order_params = {} + order_params["tsym"] = tradingsymbol + order_params["exch"] = exchange + order_params["trantype"] = buy_or_sell + order_params["prctyp"] = price_type + order_params["prd"] = product_type + order_params["ret"] = retention + order_params["actid"] = self.__accountid + order_params["uid"] = self.__username + order_params["ordersource"] = "API" + order_params["qty"] = str(quantity) + order_params["prc"] = str(price) + + # prepare the data + values = {} + values["uid"] = self.__username + values["ai_t"] = self.ALERT_TYPE_OCO + values["remarks"] = remarks + values["validity"] = validity + values["tsym"] = urllib.parse.quote_plus(tradingsymbol) + values["exch"] = exchange + values["oivariable"] = oivariable + values["place_order_params"] = order_params + values["place_order_params_leg2"] = order_params + + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" + reportmsg(payload) + + res = requests.post(url, data=payload) + reportmsg(res.text) + + resDict = json.loads(res.text) + if resDict["stat"] != "OI created": + return None + + return resDict["al_id"] + + def modify_gtt_oco_mkt_order( + self, + tradingsymbol: str, + exchange: str, + alert_id: int, + alert_price_above_1: float, + alert_price_below_2: float, + buy_or_sell: str, # 'B' or 'S' + product_type: str, # 'I' Intraday, 'C' Delivery, 'M' Normal Margin for options + quantity: int, + remarks: str = "MODIFY_OCO_MKT", + ): + # prepare the uri + config = NorenApi.__service_config + url = f"{config['host']}{config['routes']['modifyoco']}" + reportmsg(url) + + retention = "DAY" + validity = "GTT" + price = 0.0 + price_type = self.PRICE_TYPE_MARKET + + oivariable = [ + {"d": str(alert_price_above_1), "var_name": "x"}, + {"d": str(alert_price_below_2), "var_name": "y"}, + ] + + order_params = {"ordersource": "API"} + order_params["tsym"] = tradingsymbol + order_params["exch"] = exchange + order_params["trantype"] = buy_or_sell + order_params["prctyp"] = price_type + order_params["prd"] = product_type + order_params["qty"] = str(quantity) + order_params["uid"] = self.__username + order_params["actid"] = self.__accountid + order_params["ret"] = retention + order_params["prc"] = str(price) + + # prepare the data + values = {"ordersource": "API"} + values["uid"] = self.__username + values["ai_t"] = self.ALERT_TYPE_OCO + values["remarks"] = remarks + values["validity"] = validity + values["tsym"] = urllib.parse.quote_plus(tradingsymbol) + values["exch"] = exchange + values["al_id"] = alert_id + values["oivariable"] = oivariable + values["place_order_params"] = order_params + values["place_order_params_leg2"] = order_params + + payload = "jData=" + json.dumps(values) + f"&jKey={self.__susertoken}" + print(payload) + + res = requests.post(url, data=payload) + print(res.text) + + resDict = json.loads(res.text) + if resDict["stat"] != "OI replaced": + return None + + return resDict["al_id"] diff --git a/README.md b/README.md index ad9cbfa..b240548 100644 --- a/README.md +++ b/README.md @@ -2323,6 +2323,86 @@ while(feed_opened==False): ``` +### Place GTT Order + +Placing GTT order example is shown below. + +```python + alert_id = api.place_gtt_order( + "SBIN-EQ", + "NSE", + api.ALERT_TYPE_BELOW, + 573.4, + "S", + "I", + 5, + "LMT", + 575.3, + "checking gtt below", + ) + print("===================================") + print(f"Alert ID for GTT Order :: {alert_id}") + print("===================================") + +``` + +### Get Pending GTT orders + +Get list of pendingg GTT orders + +```python + resp = api.get_pending_gtt_orders() + print(resp) + if len(resp) > 0: + print(resp[0]['al_id']) # Alert Id or Order Id +``` + +### Place GTT OCO (One Cancel Other) Market Order + +Following is the example code for place OCO GTT Market order + +```python + alert_id = api.place_gtt_oco_mkt_order( + "SILVERMIC28FEB23", + "MCX", + 69200.0, + 69000.0, + api.TRANSACTION_TYPE_SELL, + api.PRODUCT_TYPE_INTRADAY, + 1, + ) + print("===================================") + + print("===================================") + print(f"Alert ID for GTT OCO MKT Order :: {alert_id}") + print("===================================") + +``` + +### Modify GTT OCO (One Cancel Other) Market Order + +Modify GTT OCO Market order by changing the price condition above and below for a given Alert Id (`al_id`) + +```python + # alert_id - can be extracted using place_gtt_oco_mkt_order method see example above. + alert_id = api.modify_gtt_oco_mkt_order( + "SILVERMIC28FEB23", + "MCX", + alert_id, + 69500.0, + 69100.0, + api.TRANSACTION_TYPE_SELL, + api.PRODUCT_TYPE_INTRADAY, + 1 + ) + + print("===================================") + print(f"Alert ID for Modified GTT OCO MKT Order :: {alert_id}") + print("===================================") + +``` + + **** ## Author From 6b55adb578e42cdfbcce6eae2af3c53b36fc7fed Mon Sep 17 00:00:00 2001 From: Rahul Raut Date: Sun, 8 Jan 2023 01:04:37 +0530 Subject: [PATCH 3/3] Added example for cancelgtt order(s) --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index b240548..72783c3 100644 --- a/README.md +++ b/README.md @@ -2401,7 +2401,27 @@ Modify GTT OCO Market order by changing the price condition above and below for print("===================================") ``` +### Cancel GTT orders +Cancel GTT orders example codes are below. + +```python + alert_id = 23010700000205 + resp = api.cancelgtt(alert_id) + time.sleep(1.0) + resp = api.get_pending_gtt_orders() + print("===================================") + print("Pending GTT orders\n", resp) + print("===================================") + + # Cancel all pending GTT orders + for i in range(0, len(resp)): + print( + f'Cancelled GTT Order/Alert - Alert Id :: {api.cancelgtt(resp[i]["al_id"])}' + ) + + +``` ****