From ee48512f6b7e830070094e8dd269f599fa93829f Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 30 Nov 2020 17:56:23 +0530 Subject: [PATCH 01/33] changes in socket files and readme --- README.md | 24 ++ SmartApi/__pycache__/__init__.cpython-36.pyc | Bin 122 -> 122 bytes .../__pycache__/smartConnect.cpython-36.pyc | Bin 10813 -> 10813 bytes .../__pycache__/smartSocket.cpython-36.pyc | Bin 0 -> 8456 bytes SmartApi/__pycache__/socketTP.cpython-36.pyc | Bin 8986 -> 8916 bytes SmartApi/smartConnect.py | 2 +- SmartApi/smartSocket.py | 359 ++++++++++++++---- SmartApi/socket1.py | 32 -- SmartApi/socketTP.py | 301 --------------- test/test.py | 127 ++++--- 10 files changed, 380 insertions(+), 465 deletions(-) create mode 100644 SmartApi/__pycache__/smartSocket.cpython-36.pyc delete mode 100644 SmartApi/socket1.py delete mode 100644 SmartApi/socketTP.py diff --git a/README.md b/README.md index c2807f8..c8d39ef 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,30 @@ try: except Exception as e: print("Logout failed: {}".format(e.message)) +#websocket +from smartapi.smartSocket import SmartSocket +FEED_TOKEN= "your feed token" +CLIENT_CODE="your client code" +token="channel you want the information of" #"nse_cm|2885&nse_cm|1594&nse_cm|11536" + +ss = SmartSocket(FEED_TOKEN, CLIENT_CODE) + +def on_tick(ws, tick): + print("Ticks: {}".format(tick)) + +def on_connect(ws, response): + ws.send_request(token) + +def on_close(ws, code, reason): + ws.stop() + +# Assign the callbacks. +ss.on_ticks = on_tick +ss.on_connect = on_connect +ss.on_close = on_close + +ss.connect( ) + License MIT diff --git a/SmartApi/__pycache__/__init__.cpython-36.pyc b/SmartApi/__pycache__/__init__.cpython-36.pyc index d9cb64366e71c1538c60371f05df7862bf84ba8a..f619741a91256bb1d9bdccb6de0f3f4660282320 100644 GIT binary patch delta 15 Wcmb=b;xy*v<(lw(bv(yJ&O!hsDFo>N delta 15 Wcmb=b;xy*v<=P-KF`i)}XCVL|-~=21 diff --git a/SmartApi/__pycache__/smartConnect.cpython-36.pyc b/SmartApi/__pycache__/smartConnect.cpython-36.pyc index 3f5e4801c3d97d04318920e21ff166084da359ad..2f026f4f4c0f646094054cef2dd68a0260e5aabf 100644 GIT binary patch delta 18 ZcmdlRvNwd&n3tC;>*0}j`;D9?S^z&(21oz^ delta 18 ZcmdlRvNwd&n3tC;Ie1;X^+rw;EdV+91(^T< diff --git a/SmartApi/__pycache__/smartSocket.cpython-36.pyc b/SmartApi/__pycache__/smartSocket.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..99c5ce76ec693eecd9d0c7dd42322946387804f2 GIT binary patch literal 8456 zcmb_h&2Jn>cJHt0>G|NND3YRWsco;d8fP`ywY6TyVYCt`YNhp>QcOCsI$pGUx|(DU zd%8!}H6l4XV;D;X3oIbRmmC5Z!5;Roxdgcd2yzIJoN~%7K<5%5C;kh2Nq(=oXE>y! zH3DP?{pzEut6#lW@AuxTes^lB`n&)7SNGR%E6RT>6F&p>o4C@y2Vn|RBgM%})lp?z zb2M4%jxI~XF=SbCO0qN^QY`Z2gx zHX3SXF;4^{>;w%hEAznfMZz;ZO(WdXqhzO{XG;%*)@I`G1!64%Zu<0^(N8Zb=_)FLLSk~XUn$!vQJXIj35;IYjSeaQU zO;%x5l;vM3hT>RYzm{Ft?08(fh$~+$UPG^=YX(=k2qF}r4wNIUtqs(H_LWNV#ANCQ z)>uk=-GK87hGmxPhH)rd7yU*WMBAC+@trg?_x7oTU@ETbM_!t`?%yiEe|znN&r;&X z>xNgmhhjI0KaW2A^oXuwUkk>H(Jn^G}C~E(WmoB3@V#1e0F`7zR&l;}u4Uhr; zZNXC-Ek)E~wkJh{>3YfjW8^rclUv?VsCjqw$MTJRh?|Z2oq{3@O zVY(YI5=wcyP^h+_X4NEii{TB8*YW<$;z8O?V$3y*W=`hlMkR^Y@-1*4&C~=@G)uG8 z{+lmf@c5ar21%2&YPsTNROAX(zL1yD<%AA3PJ+$KU^D3kaYL0np5@F;;`_M!Du$+H z!iox}>_5a54fjdz^rMmnZ6(Odi1?g95gFADpCy&sBQn+4lmFA}y75NUb-p4|z6Z_Iw;MZF+x-q~nW zvl0thy&ZlIEbt{FuMxRO8zYxzDHXCJ57|Gux@*N_C?T*zgoL8=R+FCDBEiv1~CC$!K4NbD|qi6i1Mcu@e z{v*gpspQPak&zQ42S(28n+lv;4UVl2r&fnUyT+#3%u^Mff0oU`wOQ=@Y@VG%PlYY8 z^XRFvAFxHXgq|9Ehb^-UsMXmDdj$=VSQ#7u$aa$HK1&_FMa|ZB;+Uw(o{oRult9vhtQ^KH^nrO#Rav@`uP6+E%%d; z?_~y05|LGjSyv=`L7dfm84kfKvVeaVFP2azLVqvK4MEy~v<7JdWDSi{j{em<>+84O zt@|IYZ)CN#pWR#E*mBqI-(HvV@E>C2$+pa)h74i@S4wj!YMl(iF!d9&=r2qtacl?U z@PTwm*N3>$PeBAc!L|&9uzU(4R0KvOETs)WwN(gAX&bUu0ySl=3`)XP-3n+`)@q=2 zS(_^S#9M37kqB&WBI3w}H4$;ZS4`)SK#n`dk6emw;lrgA5p0cIiA0vXEggyknXE?l z3+E~kC+{iTlZ2lFZydeHBZ)U>gqzK~zT|im;UFM#NlrQVOzTyxs#n$g-@kZD&d)tK z_Pk^+v^m#kreA_UMs%rp*fJ#9YHgig9%yxdqcGZ~BV}j^lC(B32uPm6Cx^6hUQE| zKq5F01#miLN&=FexZ|7;W5j_`v>EQiUUb)sSrqUT`GF}A{{})zaH}!HZ(=5Xod{{r zvBGpS@OwPq1R2gko-H5{oOlf<~N&N2&A1h9dN{KZ9l8*YcbC!ox%1l&J3bY_Z0yG3N{ z7)e*8XLm!n*gIXYnXZ5+T3s`=Y1PtZbps}6=$1NSpJ{7>efq9@C zg|8587h(IJ##hK{7(B3q9erc#4)!a#Q@KtNIMvOqTU+by{RivF*yNhea$H9YS-d=8 zzs93Q%)JP|)t`(dnv(-hg|(y;xl>1h_BhO@kd_jPB3aTTZ%!o*VwOi*c|^-EVFqp! zA+yN|`SQ%nerPh1m<+8?5}Ql%-L}{bCP608I-qf&i^}ie z(NV1NQtnC;Oa6+OBR8UG{kcijaZ(y@=VZ!0sVPw!>|^{STgNI_B_zeQ!B4zZqo zV-pFDu=c9_Z&cu=s`M%Kt*{ahu{JPhPG&wsYWPd#q4Eg(mSNNv#-~cGeVXs$@`j`N zaRzVf7{W{UoH9u<4x+4-yLJP5;*RP0z6jY?|I#{TGRUD3huA!LjM!Hog+?e7?|fkY zVhAzXSbL++-$TKFM1&03snMV!Bg3gmc#x^B%xELoLD<~ubknS|e&7dP!YH|0GjluP z9Zz7e;6<>&KccDT(XsCde;4_=NPQl5Q$T3WOQt@Tg4gNIZgKxNm>?y)Mh2y6+9G0y zd3_N;Hm@7%th%V4#)!#BUu=^y^_BSsB(HKxf6;moPE7jW+{e?Az!`+#KStj_;L2f3 z#`^uG$xTN-euS>%UFb*U*uQ=c4FM|zADWh$+mKHh_H(lqOH>i_)r}H=lyPF?5r& zqf5$-k_wU-pCw8sYehJM(@|B%;l-g}uD>%}{0W}^4_vu-hxwk#MPR&iCO3XHsf+R% z`RXUAkQYS^Ov(Xz3ms9>>OgHH20l`Us-SZVsUGP!s82&5DGe$+TozUvCmE-EA1d(z zyhIgVVpoNKhBDzdfdBGrd58oZiEp`o?g8n+o>XA7U+RhNtM5DI2e%&m?EbCWj&b|e z)~$^(_jF)Ey4b{({vDzLDKh!~9c8G0tsZes( zRoq!vRd(=a=fBa0wSzC|jEPN&3i)HUNF3Z&e!lyeHmnb)2DL$*E$x-QR{2e~j8$H^ zP~?&WV=y(CV%m~&By&(|QwwxO_LW~Lc+7i1Us+P~(YSD<2edIbAjO?Y;MLwms zdWZ50Lv&2$%dZmICK3>lucR}kOudVb4z<>y2;4k8Xy}fGL(Eu&;?Ng?e49OpRBtd-Fmon*f9YFRl&SYlot=$CC<^Kb zh;fi?z~m?>*Z)$xfG=hYR2~pt`9$s@JO5r`la_5{FTFV331iA^kn7`!fH!}y-jGH{ zrv{{ZUpQvI`$j=+O3S+qlIe(4d7GMN+)4+1D=^hjUUoVnJlV`+WG>?Yx};zE5*0e* zlFlA;?_dcM-;kRiKY<5$W(+k#Y^Dy4g9mwF0F=57oF*KE7znw6FZoy#IHFT8^%c}y zQly9|(#-qOGc+DwC)9z+O8w?08KF!GrMQsk(HZEIkl`Z)@-%5McCu~DgTp3&8*JzJ z6ru*_OOnCvAfw|X5&oD6r`~dY7(k+Q=3u3*fV;`|$l$p^f2OuMd01yEf0c{yV+YaP z8Bs?Va*;$$fqCm5EI52wI`lTqZ7p;b(*OsY5S^L5Tyil%xE%QaIW>)@6AY;$*eLix2t+UlA_*6e3#2#~A$lQ7#2?^x z);4xZZ0yBK3&F}Ff5Fm5!P%rz7G~!?-p-r1*X!?V)^ai#AC8_5PVcQ1+kOE62_6m* z!J{5^&s5!ZXF~9WZ^(#m%BUX;#efA`A|Vv&#$Iy&QsdXr8W4uliEA3QR#HJ89x`q%EI|$Sq2IWu$Wl13o(8IRDm|52F zlA0S3>%`F}V?$$|qy`0{?lP;QQi!OpOw&y0HApqG5B+2ABu_}dcq#{zqD?#%eMA35 z4`sxoa6DIN(N4eH=UJo5s2LZd?TBvnjXL8=)-I_j#{PSp4BWBy_VW{x2Ds2Y2jdea)yuY6=7d(&wt{% HD(6SPayn-? delta 498 zcmYjNJxc>Y5S`h(+vH*tT!TqKqk@IOMlb{{1PiqhLNK5~5H)TJFBsu+P2dj2v$C*o zu@QfQO^B8F7c2y;6e1R4XJ;okdr^>Kc9@TS@69}~T(8>mgM*3S;eMynu@{B-000jp zhKL|pz}h#eDst*pjH+FcGDB*pOEEViO`rMTAi0iA@*7JxqkpjqnBdusg!`smMH4Mm z9{J8q5;R~OO~&XQCFeM8{Kf8J>XB`4{G-?K?pU9M$c)fH&{XcSZ@9~z;j<7WYnYTr zBIqSiB!SVK(ORe6(m5>x704SUb&+0*<++#fN?ssfEnl@%b;chYr&aIwrv_ z6A^9YnGNQaeRM2IkO9(-bY0JJC#EL?Ml}-P#6uzuLHF7j&vp|3ySlmw%@o~dfbQcX zXd{6Fsvs@N&mb@&y|I!y$j)}JvSpJe` 4: + self.on_ticks(self, self._parse_binary(payload)) + + # Parse text messages + if not is_binary: + self._parse_text_message(payload) + + def _on_open(self, ws): + if self.on_open: + return self.on_open(self) + + def _parse_text_message(self, payload): + """Parse text message.""" + # Decode unicode data + if not six.PY2 and type(payload) == bytes: + payload = payload.decode("utf-8") + print("PAYLOAD",payload) + data =base64.b64decode(payload) + print("DATA",data) + try: + data = json.loads(payload) + print("DATA",data) + except ValueError: + return + + def _parse_binary(self, bin): + #print("""Parse binary data to a (list of) ticks structure.""") + packets = self._split_packets(bin) # split data to individual ticks packet + data = [] + + for packet in packets: + instrument_token = self._unpack_int(packet, 0, 4) + segment = instrument_token & 0xff # Retrive segment constant from instrument_token + + divisor = 10000000.0 if segment == self.EXCHANGE_MAP["cds"] else 100.0 + + # All indices are not tradable + tradable = False if segment == self.EXCHANGE_MAP["indices"] else True + try: + last_trade_time = datetime.fromtimestamp(self._unpack_int(packet, 44, 48)) + except Exception: + last_trade_time = None + + try: + timestamp = datetime.fromtimestamp(self._unpack_int(packet, 60, 64)) + except Exception: + timestamp = None + + d["last_trade_time"] = last_trade_time + d["oi"] = self._unpack_int(packet, 48, 52) + d["oi_day_high"] = self._unpack_int(packet, 52, 56) + d["oi_day_low"] = self._unpack_int(packet, 56, 60) + d["timestamp"] = timestamp + + # Market depth entries. + depth = { + "buy": [], + "sell": [] + } + + # Compile the market depth lists. + for i, p in enumerate(range(64, len(packet), 12)): + depth["sell" if i >= 5 else "buy"].append({ + "quantity": self._unpack_int(packet, p, p + 4), + "price": self._unpack_int(packet, p + 4, p + 8) / divisor, + "orders": self._unpack_int(packet, p + 8, p + 10, byte_format="H") + }) + + d["depth"] = depth + + data.append(d) + + return data + + def _unpack_int(self, bin, start, end, byte_format="I"): + """Unpack binary data as unsgined interger.""" + return struct.unpack(">" + byte_format, bin[start:end])[0] + + def _split_packets(self, bin): + """Split the data to individual packets of ticks.""" + # Ignore heartbeat data. + if len(bin) < 2: + return [] + + number_of_packets = self._unpack_int(bin, 0, 2, byte_format="H") + packets = [] + + j = 2 + for i in range(number_of_packets): + packet_length = self._unpack_int(bin, j, j + 2, byte_format="H") + packets.append(bin[j + 2: j + 2 + packet_length]) + j = j + 2 + packet_length + + return packets + diff --git a/SmartApi/socket1.py b/SmartApi/socket1.py deleted file mode 100644 index e540fdf..0000000 --- a/SmartApi/socket1.py +++ /dev/null @@ -1,32 +0,0 @@ -# import websocket -# import ssl -# import base64 -# ws = websocket.WebSocket() -# from websocket import create_connection -# FEED_TOKEN='125645827' -# CLIENT_CODE='S212741' -# ws= create_connection("wss://omnefeeds.angelbroking.com/NestHtml5Mobile/socket/stream",sslopt={"cert_reqs": ssl.CERT_NONE}) -# _req='{"task":"cn","channel":"","token":"' + FEED_TOKEN + '","user": "' + CLIENT_CODE + '","acctid":"' + CLIENT_CODE + '"}'; -# ws.send(_req) -# strwatchlistscrips = "nse_cm|2885&nse_cm|1594&nse_cm|11536"; -# _req = '{"task":"cn","channel":"'+strwatchlistscrips+'","token":"' + FEED_TOKEN + '","user": "' + CLIENT_CODE + '","acctid":"' + CLIENT_CODE + '"}'; -# ws.send(_req) -# print("Sent") -# print("Receiving...") -# result = ws.recv() -# print(result) -# #str = unicode(str, errors='ignore') -# print("Received '%s'" % result.decode(encoding="utf-8")) -# ws.close() - -import asyncio -import websockets - -async def message(): - async with websockets.connect("wss://omnefeeds.angelbroking.com/NestHtml5Mobile/socket/stream") as socket: - await socket.send({"task":"cn","channel":"","token":"' + FEED_TOKEN + '","user": "' + CLIENT_CODE + '","acctid":"' + CLIENT_CODE + '"}) - strwatchlistscrips = "nse_cm|2885&nse_cm|1594&nse_cm|11536" - await socket.send({"task":"cn","channel":strwatchlistscrips,"token":"' + FEED_TOKEN + '","user": "' + CLIENT_CODE + '","acctid":"' + CLIENT_CODE + '"}) - print(await socket.recv()) - -asyncio.get_event_loop().run_until_complete(message()) diff --git a/SmartApi/socketTP.py b/SmartApi/socketTP.py deleted file mode 100644 index 8149ab3..0000000 --- a/SmartApi/socketTP.py +++ /dev/null @@ -1,301 +0,0 @@ -import six -import sys -import time -import json -import struct -import logging -import threading -import base64 -from datetime import datetime -from twisted.internet import reactor, ssl -from twisted.python import log as twisted_log -from autobahn.twisted.websocket import WebSocketClientProtocol, \ - WebSocketClientFactory, connectWS - - -class SmartSocketClientProtocol(WebSocketClientProtocol): - def __init__(self, *args, **kwargs): - super(SmartSocketClientProtocol,self).__init__(*args,**kwargs) - - def onConnect(self, response): # noqa - """Called when WebSocket server connection was established""" - self.factory.ws = self - - if self.factory.on_connect: - self.factory.on_connect(self, response) - - def onOpen(self): - if self.factory.on_open: - self.factory.on_open(self) - - def onMessage(self, payload, is_binary): # noqa - print("""Called when text or binary message is received.""",payload,is_binary) - if self.factory.on_message: - self.factory.on_message(self, payload, is_binary) - - def onClose(self, was_clean, code, reason): # noqa - """Called when connection is closed.""" - if not was_clean: - if self.factory.on_error: - self.factory.on_error(self, code, reason) - - if self.factory.on_close: - self.factory.on_close(self, code, reason) - -class SmartSocketClientFactory(WebSocketClientFactory): - protocol = SmartSocketClientProtocol - - def __init__(self, *args, **kwargs): - """Initialize with default callback method values.""" - self.debug = False - self.ws = None - self.on_open = None - self.on_error = None - self.on_close = None - self.on_message = None - self.on_connect = None - - - super(SmartSocketClientFactory, self).__init__(*args, **kwargs) - - -class SmartSocket(object): - EXCHANGE_MAP = { - "nse": 1, - "nfo": 2, - "cds": 3, - "bse": 4, - "bfo": 5, - "bsecds": 6, - "mcx": 7, - "mcxsx": 8, - "indices": 9 - } - ROOT_URI='wss://omnefeeds.angelbroking.com/NestHtml5Mobile/socket/stream' - feed_token=None - client_code=None - def __init__(self, FEED_TOKEN, CLIENT_CODE, debug=False, root=None): - self.root = root or self.ROOT_URI - self.feed_token= FEED_TOKEN - self.client_code= CLIENT_CODE - - - # Debug enables logs - self.debug = debug - - # Placeholders for callbacks. - self.on_ticks = None - self.on_open = None - self.on_close = None - self.on_error = None - self.on_connect = None - self.on_message = None - - def _create_connection(self, url, **kwargs): - """Create a WebSocket client connection.""" - self.factory = SmartSocketClientFactory(url, **kwargs) - - # Alias for current websocket connection - self.ws = self.factory.ws - - self.factory.debug = self.debug - - # Register private callbacks - self.factory.on_open = self._on_open - self.factory.on_error = self._on_error - self.factory.on_close = self._on_close - self.factory.on_message = self._on_message - self.factory.on_connect = self._on_connect - - - def connect(self, threaded=False, disable_ssl_verification=False, proxy=None): - print("Connect") - self._create_connection(self.ROOT_URI) - - context_factory = None - print(self.factory.isSecure,disable_ssl_verification) - if self.factory.isSecure and not disable_ssl_verification: - context_factory = ssl.ClientContextFactory() - print("context_factory",context_factory) - connectWS(self.factory, contextFactory=context_factory, timeout=30) - - # Run in seperate thread of blocking - opts = {} - - # Run when reactor is not running - if not reactor.running: - if threaded: - print("inside threaded") - # Signals are not allowed in non main thread by twisted so suppress it. - opts["installSignalHandlers"] = False - self.websocket_thread = threading.Thread(target=reactor.run, kwargs=opts) - self.websocket_thread.daemon = True - self.websocket_thread.start() - else: - reactor.run(**opts) - - def is_connected(self): - print("Check if WebSocket connection is established.") - if self.ws and self.ws.state == self.ws.STATE_OPEN: - return True - else: - return False - def _close(self, code=None, reason=None): - print("Close the WebSocket connection.") - if self.ws: - self.ws.sendClose(code, reason) - - def close(self, code=None, reason=None): - """Close the WebSocket connection.""" - self._close(code, reason) - - def stop(self): - """Stop the event loop. Should be used if main thread has to be closed in `on_close` method. - Reconnection mechanism cannot happen past this method - """ - print("stop") - reactor.stop() - - def send_request(self,token): - print('Request Send') - strwatchlistscrips = "nse_cm|2885&nse_cm|1594&nse_cm|11536" #or token - #token_scripts=token //dynamic call - try: - print("Inside") - request={"task":"cn","channel":"","token":self.feed_token,"user":self.client_code,"acctid":self.client_code} - self.ws.sendMessage( - six.b(json.dumps(request)) - ) - - request={"task":"cn","channel":strwatchlistscrips,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} - #request={"task":"cn","channel":token_scripts,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} //dynamic call - self.ws.sendMessage( - six.b(json.dumps(request)) - ) - - return True - except Exception as e: - self._close(reason="Error while request sending: {}".format(str(e))) - raise - - def _on_connect(self, ws, response): - self.ws = ws - if self.on_connect: - self.on_connect(self, response) - - def _on_close(self, ws, code, reason): - """Call `on_close` callback when connection is closed.""" - print("Connection closed: {} - {}".format(code, str(reason))) - - if self.on_close: - self.on_close(self, code, reason) - - def _on_error(self, ws, code, reason): - """Call `on_error` callback when connection throws an error.""" - print("Connection error: {} - {}".format(code, str(reason))) - - if self.on_error: - self.on_error(self, code, reason) - - def _on_message(self, ws, payload, is_binary): - """Call `on_message` callback when text message is received.""" - if self.on_message: - self.on_message(self, payload, is_binary) - - # If the message is binary, parse it and send it to the callback. - if self.on_ticks and is_binary and len(payload) > 4: - self.on_ticks(self, self._parse_binary(payload)) - - # Parse text messages - if not is_binary: - self._parse_text_message(payload) - - def _on_open(self, ws): - if self.on_open: - return self.on_open(self) - - def _parse_text_message(self, payload): - """Parse text message.""" - # Decode unicode data - if not six.PY2 and type(payload) == bytes: - payload = payload.decode("utf-8") - print("PAYLOAD",payload) - data =base64.b64decode(payload) - print("DATA",data.encode().decode()) - try: - data = json.loads(payload) - print("DATA",data) - except ValueError: - return - - def _parse_binary(self, bin): - print("""Parse binary data to a (list of) ticks structure.""") - packets = self._split_packets(bin) # split data to individual ticks packet - data = [] - - for packet in packets: - instrument_token = self._unpack_int(packet, 0, 4) - segment = instrument_token & 0xff # Retrive segment constant from instrument_token - - divisor = 10000000.0 if segment == self.EXCHANGE_MAP["cds"] else 100.0 - - # All indices are not tradable - tradable = False if segment == self.EXCHANGE_MAP["indices"] else True - try: - last_trade_time = datetime.fromtimestamp(self._unpack_int(packet, 44, 48)) - except Exception: - last_trade_time = None - - try: - timestamp = datetime.fromtimestamp(self._unpack_int(packet, 60, 64)) - except Exception: - timestamp = None - - d["last_trade_time"] = last_trade_time - d["oi"] = self._unpack_int(packet, 48, 52) - d["oi_day_high"] = self._unpack_int(packet, 52, 56) - d["oi_day_low"] = self._unpack_int(packet, 56, 60) - d["timestamp"] = timestamp - - # Market depth entries. - depth = { - "buy": [], - "sell": [] - } - - # Compile the market depth lists. - for i, p in enumerate(range(64, len(packet), 12)): - depth["sell" if i >= 5 else "buy"].append({ - "quantity": self._unpack_int(packet, p, p + 4), - "price": self._unpack_int(packet, p + 4, p + 8) / divisor, - "orders": self._unpack_int(packet, p + 8, p + 10, byte_format="H") - }) - - d["depth"] = depth - - data.append(d) - - return data - - def _unpack_int(self, bin, start, end, byte_format="I"): - """Unpack binary data as unsgined interger.""" - return struct.unpack(">" + byte_format, bin[start:end])[0] - - def _split_packets(self, bin): - """Split the data to individual packets of ticks.""" - # Ignore heartbeat data. - if len(bin) < 2: - return [] - - number_of_packets = self._unpack_int(bin, 0, 2, byte_format="H") - packets = [] - - j = 2 - for i in range(number_of_packets): - packet_length = self._unpack_int(bin, j, j + 2, byte_format="H") - packets.append(bin[j + 2: j + 2 + packet_length]) - j = j + 2 + packet_length - - return packets - - diff --git a/test/test.py b/test/test.py index 1ce0ae0..1d67ec7 100644 --- a/test/test.py +++ b/test/test.py @@ -2,86 +2,86 @@ import os dir = os.getcwd() -print(dir) +#print(dir) #paths=dir.split("\") sys.path.append(dir + "\SmartApi") -print(sys.path) +#print(sys.path) -# import smartConnect +import smartConnect -# smartApi = smartConnect.SmartConnect() +smartApi = smartConnect.SmartConnect() -# login = smartApi.generateSession('D88311', 'Angel@444') -# print(login) -# refreshToken = login['data']['refreshToken'] -# smartApi.getProfile(refreshToken) -# smartApi.generateToken(refreshToken) -# orderparams = { -# "variety": "NORMAL", -# "tradingsymbol": "SBIN-EQ", -# "symboltoken": "3045", -# "transactiontype": "BUY", -# "exchange": "NSE", -# "ordertype": "LIMIT", -# "producttype": "INTRADAY", -# "duration": "DAY", -# "price": "19500", -# "squareoff": "0", -# "stoploss": "0", -# "quantity": "1" -# } -# orderid = smartApi.placeOrder(orderparams) +login = smartApi.generateSession('D88311', 'Angel@444') +print(login) +refreshToken = login['data']['refreshToken'] +smartApi.getProfile(refreshToken) +smartApi.generateToken(refreshToken) +orderparams = { + "variety": "NORMAL", + "tradingsymbol": "SBIN-EQ", + "symboltoken": "3045", + "transactiontype": "BUY", + "exchange": "NSE", + "ordertype": "LIMIT", + "producttype": "INTRADAY", + "duration": "DAY", + "price": "19500", + "squareoff": "0", + "stoploss": "0", + "quantity": "1" +} +orderid = smartApi.placeOrder(orderparams) -# modifyparams = { -# "variety": "NORMAL", -# "orderid": orderid, -# "ordertype": "LIMIT", -# "producttype": "INTRADAY", -# "duration": "DAY", -# "price": "19500", -# "quantity": "1", -# "tradingsymbol":"SBIN-EQ", -# "symboltoken":"3045", -# "exchange":"NSE" -# } -# smartApi.modifyOrder(modifyparams) +modifyparams = { + "variety": "NORMAL", + "orderid": orderid, + "ordertype": "LIMIT", + "producttype": "INTRADAY", + "duration": "DAY", + "price": "19500", + "quantity": "1", + "tradingsymbol":"SBIN-EQ", + "symboltoken":"3045", + "exchange":"NSE" +} +smartApi.modifyOrder(modifyparams) -# smartApi.cancelOrder(orderid, "NORMAL") +smartApi.cancelOrder(orderid, "NORMAL") -# smartApi.orderBook() -# smartApi.tradeBook() -# smartApi.rmsLimit() -# smartApi.position() -# smartApi.holding() -# exchange = "NSE" -# tradingsymbol = "SBIN-EQ" -# symboltoken = 3045 -# smartApi.ltpData("NSE", "SBIN-EQ", "3045") -# params={ -# "exchange": "NSE", -# "oldproducttype":"DELIVERY", -# "newproducttype": "MARGIN", -# "tradingsymbol": "SBIN-EQ", -# "transactiontype":"BUY", -# "quantity":1, -# "type":"DAY" +smartApi.orderBook() +smartApi.tradeBook() +smartApi.rmsLimit() +smartApi.position() +smartApi.holding() +exchange = "NSE" +tradingsymbol = "SBIN-EQ" +symboltoken = 3045 +smartApi.ltpData("NSE", "SBIN-EQ", "3045") +params={ + "exchange": "NSE", + "oldproducttype":"DELIVERY", + "newproducttype": "MARGIN", + "tradingsymbol": "SBIN-EQ", + "transactiontype":"BUY", + "quantity":1, + "type":"DAY" -# } +} -# smartApi.convertPosition(params) -# smartApi.terminateSession('D88311') +smartApi.convertPosition(params) +smartApi.terminateSession('D88311') -from socketTP import SmartSocket -FEED_TOKEN='2017967114' +from smartSocket import SmartSocket +FEED_TOKEN='1731759952' CLIENT_CODE='S212741' token=None ss = SmartSocket(FEED_TOKEN, CLIENT_CODE) def on_tick(ws, tick): print("Ticks: {}".format(tick)) def on_connect(ws, response): - ws.send_request(token) - + a=ws.send_request(token) + print("Back to Function",a) def on_close(ws, code, reason): ws.stop() @@ -90,5 +90,6 @@ def on_close(ws, code, reason): ss.on_connect = on_connect ss.on_close = on_close -ss.connect() +ss.connect( ) + From 161544455340b13b5ac11119671641e8d33ab80f Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 30 Nov 2020 18:04:01 +0530 Subject: [PATCH 02/33] changes in endpoint url for prod --- .../__pycache__/smartConnect.cpython-36.pyc | Bin 10813 -> 10823 bytes SmartApi/smartConnect.py | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/SmartApi/__pycache__/smartConnect.cpython-36.pyc b/SmartApi/__pycache__/smartConnect.cpython-36.pyc index 2f026f4f4c0f646094054cef2dd68a0260e5aabf..87d7f6cf32a2cff265de5513bc7f0d91c811bc0f 100644 GIT binary patch delta 40 wcmdlRay*37n3tEU;^~oi&yAdM%#4PUGnkdQ3QCi5GK(`(i*z@4F>h7_02@{f;Q#;t delta 29 lcmX>evNwd&n3tC;>*0}j`;DA&%#7-jGnkb&PhsAy1^}2H3BUjV diff --git a/SmartApi/smartConnect.py b/SmartApi/smartConnect.py index 8ff2a2a..0d4b880 100644 --- a/SmartApi/smartConnect.py +++ b/SmartApi/smartConnect.py @@ -21,8 +21,9 @@ class SmartConnect(object): _rootUrl = "https://openapisuat.angelbroking.com" - _loginUrl = "https://openapisuat.angelbroking.com/rest/auth/angelbroking/user/v1/loginByPassword" + #_rootUrl="https://apiconnect.angelbroking.com" _login_url ="https://smartapi.angelbroking.com/login" + #_login_url="https://smartapi.angelbroking.com/publisher-login" _default_timeout = 7 # In seconds # Products PRODUCT_MIS = "MIS" From 29a05e26d8756463d87704091341771a3524a133 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 30 Nov 2020 18:07:30 +0530 Subject: [PATCH 03/33] changes in endpoint url for prod --- SmartApi/smartConnect.py | 358 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 SmartApi/smartConnect.py diff --git a/SmartApi/smartConnect.py b/SmartApi/smartConnect.py new file mode 100644 index 0000000..5ea37e6 --- /dev/null +++ b/SmartApi/smartConnect.py @@ -0,0 +1,358 @@ +from six.moves.urllib.parse import urljoin +import sys + +sys.path.append('c:\AngelSmartApi\SmartApi') +import csv +import json +import dateutil.parser +import hashlib +import logging +import datetime +import smartapi.smartExceptions as ex +import requests +from requests import get +import re, uuid +import socket + +from smartapi.version import __version__, __title__ + +log = logging.getLogger(__name__) + + +class SmartConnect(object): + #_rootUrl = "https://openapisuat.angelbroking.com" + _rootUrl="https://apiconnect.angelbroking.com" #prod endpoint + #_login_url ="https://smartapi.angelbroking.com/login" + _login_url="https://smartapi.angelbroking.com/publisher-login" #prod endpoint + _default_timeout = 7 # In seconds + # Products + PRODUCT_MIS = "MIS" + + PRODUCT_CNC = "CNC" + PRODUCT_NRML = "NRML" + PRODUCT_CO = "CO" + PRODUCT_BO = "BO" + + # Order types + ORDER_TYPE_MARKET = "MARKET" + ORDER_TYPE_LIMIT = "LIMIT" + ORDER_TYPE_SLM = "SL-M" + ORDER_TYPE_SL = "SL" + + # Varities + VARIETY_REGULAR = "regular" + VARIETY_BO = "bo" + VARIETY_CO = "co" + VARIETY_AMO = "amo" + + # Transaction type + TRANSACTION_TYPE_BUY = "BUY" + TRANSACTION_TYPE_SELL = "SELL" + + # Validity + VALIDITY_DAY = "DAY" + VALIDITY_IOC = "IOC" + + # Exchanges + EXCHANGE_NSE = "NSE" + EXCHANGE_BSE = "BSE" + EXCHANGE_NFO = "NFO" + EXCHANGE_CDS = "CDS" + EXCHANGE_BFO = "BFO" + EXCHANGE_MCX = "MCX" + EXCHANGE_NCDEX="NCDEX" + + # Status constants + STATUS_COMPLETE = "COMPLETE" + STATUS_REJECTED = "REJECTED" + STATUS_CANCELLED = "CANCELLED" + + _routes = { + "api.login":"/rest/auth/angelbroking/user/v1/loginByPassword", + "api.logout":"/rest/secure/angelbroking/user/v1/logout", + "api.token": "/rest/auth/angelbroking/jwt/v1/generateTokens", + "api.refresh": "/rest/auth/angelbroking/jwt/v1/generateTokens", + "api.user.profile": "/rest/secure/angelbroking/user/v1/getProfile", + + "api.order.place": "/rest/secure/angelbroking/order/v1/placeOrder", + "api.order.modify": "/rest/secure/angelbroking/order/v1/modifyOrder", + "api.order.cancel": "/rest/secure/angelbroking/order/v1/cancelOrder", + "api.order.book":"/rest/secure/angelbroking/order/v1/getOrderBook", + + "api.ltp.data": "/rest/secure/angelbroking/order/v1/getLtpData", + "api.trade.book": "/rest/secure/angelbroking/order/v1/getTradeBook", + "api.rms.limit": "/rest/secure/angelbroking/user/v1/getRMS", + "api.holding": "/rest/secure/angelbroking/portfolio/v1/getHolding", + "api.position": "/rest/secure/angelbroking/order/v1/getPosition", + "api.convert.position": "/rest/secure/angelbroking/order/v1/convertPosition" + } + + def __init__(self, api_key=None, access_token=None, refresh_token=None, userId=None, root=None, debug=False, timeout=None, proxies=None, pool=None, disable_ssl=False): + self.debug = debug + self.api_key = api_key + self.session_expiry_hook = None + self.disable_ssl = disable_ssl + self.access_token = access_token + self.refresh_token = refresh_token + self.userId = userId + self.proxies = proxies if proxies else {} + self.root = root or self._loginUrl + self.timeout = timeout or self._default_timeout + + if pool: + self.reqsession = requests.Session() + reqadapter = requests.adapters.HTTPAdapter(**pool) + self.reqsession.mount("https://", reqadapter) + print("in pool") + else: + self.reqsession = requests + + # disable requests SSL warning + requests.packages.urllib3.disable_warnings() + + def setSessionExpiryHook(self, method): + if not callable(method): + raise TypeError("Invalid input type. Only functions are accepted.") + self.session_expiry_hook = method + + def getUserId(): + return userId; + + def setUserId(self,id): + self.userId=id + + def setAccessToken(self, access_token): + + self.access_token = access_token + + def setRefreshToken(self, refresh_token): + + self.refresh_token = refresh_token + + def login_url(self): + """Get the remote login url to which a user should be redirected to initiate the login flow.""" + return "%s?api_key=%s" % (self._login_url, self.api_key) + + def _request(self, route, method, parameters=None): + """Make an HTTP request.""" + params = parameters.copy() if parameters else {} + + uri =self._routes[route].format(**params) + print(uri) + url = urljoin(self.root, uri) + print(url) + hostname = socket.gethostname() + clientLocalIP=socket.gethostbyname(hostname) + clientPublicIP=get('https://api.ipify.org').text + macAddress = ':'.join(re.findall('..', '%012x' % uuid.getnode())) + privateKey = "test" + accept = "application/json" + userType = "USER" + sourceID = "WEB" + + # Custom headers + headers = { + #"X-SmartApi-Version": "", + #"User-Agent": self._user_agent() + "Content-type":accept, + "X-ClientLocalIP": clientLocalIP, + "X-ClientPublicIP": clientPublicIP, + "X-MACAddress": macAddress, + "Accept": accept, + "X-PrivateKey": privateKey, + "X-UserType": userType, + "X-SourceID": sourceID + } + + #if self.api_key and self.access_token: + if self.access_token: + # set authorization header + + auth_header = self.access_token + headers["Authorization"] = "Bearer {}".format(auth_header) + + if self.debug: + log.debug("Request: {method} {url} {params} {headers}".format(method=method, url=url, params=params, headers=headers)) + + try: + r = requests.request(method, + url, + data=json.dumps(params) if method in ["POST", "PUT"] else None, + params=json.dumps(params) if method in ["GET", "DELETE"] else None, + headers=headers, + verify=not self.disable_ssl, + allow_redirects=True, + timeout=self.timeout, + proxies=self.proxies) + print("The Response Content",r.content) + except Exception as e: + raise e + + if self.debug: + log.debug("Response: {code} {content}".format(code=r.status_code, content=r.content)) + + # Validate the content type. + if "json" in headers["Content-type"]: + try: + data = json.loads(r.content.decode("utf8")) + + except ValueError: + raise ex.DataException("Couldn't parse the JSON response received from the server: {content}".format( + content=r.content)) + + # api error + if data.get("error_type"): + # Call session hook if its registered and TokenException is raised + if self.session_expiry_hook and r.status_code == 403 and data["error_type"] == "TokenException": + self.session_expiry_hook() + + # native errors + exp = getattr(ex, data["error_type"], ex.GeneralException) + raise exp(data["message"], code=r.status_code) + + return data + elif "csv" in headers["Content-type"]: + return r.content + else: + raise ex.DataException("Unknown Content-type ({content_type}) with response: ({content})".format( + content_type=headers["Content-type"], + content=r.content)) + + def _deleteRequest(self, route, params=None): + """Alias for sending a DELETE request.""" + return self._request(route, "DELETE", params) + def _putRequest(self, route, params=None): + """Alias for sending a PUT request.""" + return self._request(route, "PUT", params) + def _postRequest(self, route, params=None): + """Alias for sending a POST request.""" + return self._request(route, "POST", params) + def _getRequest(self, route, params=None): + """Alias for sending a GET request.""" + return self._request(route, "GET", params) + + def generateSession(self,clientCode,password): + + params={"clientcode":clientCode,"password":password} + loginResultObject=self._postRequest("api.login",params) + jwtToken=loginResultObject['data']['jwtToken'] + self.setAccessToken(jwtToken) + refreshToken=loginResultObject['data']['refreshToken'] + self.setRefreshToken(refreshToken) + user=self.getProfile(refreshToken) + + id=user['data']['clientcode'] + #id='D88311' + print(id) + + self.setUserId(id) + user['data']['jwtToken']="Bearer "+jwtToken + user['data']['refreshToken']=refreshToken + print("USER",user) + return user + + def terminateSession(self,clientCode): + logoutResponseObject=self._postRequest("api.logout",{"clientcode":clientCode}) + return logoutResponseObject + + def generateToken(self,refresh_token): + response=self._postRequest('api.token',{"refreshToken":refresh_token}) + jwtToken=response['data']['jwtToken'] + self.setAccessToken(jwtToken) + return response + + def renewAccessToken(self): + + # h = hashlib.sha256(self.api_key.encode("utf-8") + refresh_token.encode("utf-8") + access_token.encode("utf-8")) + # checksum = h.hexdigest() + + response =self._postRequest('api.refresh', { + "jwtToken": self.access_token, + "refreshToken": self.refresh_token, + #"checksum": checksum + }) + + tokenSet={} + + if "jwtToken" in response: + tokenSet['jwtToken']=response['data']['jwtToken'] + tokenSet['clientcode']=self. userId + tokenSet['refreshToken']=response['data']["refreshToken"] + + return tokenSet + + def getProfile(self,refreshToken): + user=self._getRequest("api.user.profile",{"refreshToken":refreshToken}) + print("USER PROFILE",user) + return user + + def placeOrder(self,orderparams): + #params = {"exchange":orderparams.exchange,"symbolToken":orderparams.symboltoken,"transactionType":orderparams.transactionType,"quantity":orderparams.quantity,"price":orderparams.price,"productType":orderparams.producttype,"orderType":orderparams.ordertype,"duration":orderparams.duration,"variety":orderparams.variety,"tradingSymbol":orderparams.tradingsymbol,"triggerPrice":orderparams.trigger_price,"squareoff":orderparams.squareoff,"stoploss":orderparams.stoploss,"trailingStoploss":orderparams.trailing_stoploss,"tag":orderparams.tag} + params=orderparams + + for k in list(params.keys()): + if params[k] is None : + del(params[k]) + + orderResponse= self._postRequest("api.order.place", params)['data']['orderid'] + + return orderResponse + + def modifyOrder(self,orderparams): + params = orderparams + + for k in list(params.keys()): + if params[k] is None: + del(params[k]) + + orderResponse= self._postRequest("api.order.modify", params) + #order=Order(orderResponse) + #order['orderId']=orderResponse['data']['orderid'] + return orderResponse + + def cancelOrder(self, order_id,variety): + orderResponse= self._postRequest("api.order.cancel", {"variety": variety,"orderid": order_id}) + return orderResponse + + def ltpData(self,exchange,tradingsymbol,symboltoken): + params={ + "exchange":exchange, + "tradingsymbol":tradingsymbol, + "symboltoken":symboltoken + } + ltpDataResponse= self._postRequest("api.ltp.data",params) + return ltpDataResponse + + def orderBook(self): + orderBookResponse=self._getRequest("api.order.book") + return orderBookResponse + + + def tradeBook(self): + tradeBookResponse=self._getRequest("api.trade.book") + return tradeBookResponse + + def rmsLimit(self): + rmsLimitResponse= self._getRequest("api.rms.limit") + return rmsLimitResponse + + def position(self): + positionResponse= self._getRequest("api.position") + return positionResponse + + def holding(self): + holdingResponse= self._getRequest("api.holding") + return holdingResponse + + def convertPosition(self,positionParams): + params=positionParams + for k in list(params.keys()): + if params[k] is None: + del(params[k]) + convertPositionResponse= self._postRequest("api.convert.position",params) + + return convertPositionResponse + + def _user_agent(self): + return (__title__ + "-python/").capitalize() + __version__ + From 245cfb81cb183b5f072f6691154f4ebba723a828 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 30 Nov 2020 19:05:26 +0530 Subject: [PATCH 04/33] changes in __init__.py --- SmartApi/__init__.py | 7 +++++++ test/test.py | 7 ++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/SmartApi/__init__.py b/SmartApi/__init__.py index fd40910..f5955af 100644 --- a/SmartApi/__init__.py +++ b/SmartApi/__init__.py @@ -1,3 +1,10 @@ +from __future__ import unicode_literals,absolute_import + +from smartapi import smartExceptions +from smartapi.smartConnect import SmartConnect +from smartapi.smartSocket import SmartSocket + +__all__ = ["smartExceptions","SmartConnect","SmartSocket"] diff --git a/test/test.py b/test/test.py index 1d67ec7..c09ab2d 100644 --- a/test/test.py +++ b/test/test.py @@ -8,9 +8,10 @@ sys.path.append(dir + "\SmartApi") #print(sys.path) -import smartConnect +from smartapi import SmartConnect -smartApi = smartConnect.SmartConnect() +smartApi = +SmartConnect() login = smartApi.generateSession('D88311', 'Angel@444') print(login) @@ -72,7 +73,7 @@ smartApi.convertPosition(params) smartApi.terminateSession('D88311') -from smartSocket import SmartSocket +from smartapi import SmartSocket FEED_TOKEN='1731759952' CLIENT_CODE='S212741' token=None From 3689fc66c4c7489942aa1cb2d078ceb1edc5ab78 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 30 Nov 2020 19:19:58 +0530 Subject: [PATCH 05/33] changes in sample.py- import statement --- README.md | 4 ++-- example/sample.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c8d39ef..c008a48 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ pip install smartapi-python ```python # package import statement -from smartapi.smartConnect import SmartConnect +from smartapi import SmartConnect #create object of call obj=SmartConnect() @@ -55,7 +55,7 @@ except Exception as e: print("Logout failed: {}".format(e.message)) #websocket -from smartapi.smartSocket import SmartSocket +from smartapi import SmartSocket FEED_TOKEN= "your feed token" CLIENT_CODE="your client code" token="channel you want the information of" #"nse_cm|2885&nse_cm|1594&nse_cm|11536" diff --git a/example/sample.py b/example/sample.py index eb9f1fb..1d5c4f3 100644 --- a/example/sample.py +++ b/example/sample.py @@ -1,5 +1,5 @@ # package import statement -from smartapi.smartConnect import SmartConnect +from smartapi import SmartConnect obj=SmartConnect() #login api call From 87bf4b690c3507aabf52ae26a853854677daef1a Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 30 Nov 2020 19:23:26 +0530 Subject: [PATCH 06/33] changes in version --- SmartApi/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SmartApi/version.py b/SmartApi/version.py index 6549f56..55bbe6a 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.1" +__version__ = "1.0.2" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" From 8c6b181691bea1183bee8a194f4fccae842680b3 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 30 Nov 2020 19:30:17 +0530 Subject: [PATCH 07/33] changes in version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 75ec875..03f07aa 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.1", + version="1.0.2", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", From fbdf51fc154f4d1c262e8d7c06e2682032448739 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 30 Nov 2020 20:05:27 +0530 Subject: [PATCH 08/33] bugs resolved --- README.md | 4 ++-- .../smartExceptions.cpython-36.pyc | Bin 3677 -> 3677 bytes SmartApi/__pycache__/version.cpython-36.pyc | Bin 480 -> 480 bytes SmartApi/smartConnect.py | 6 +++--- SmartApi/version.py | 2 +- example/sample.py | 2 +- setup.py | 2 +- test/test.py | 9 ++++----- 8 files changed, 12 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index c008a48..c8d39ef 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ pip install smartapi-python ```python # package import statement -from smartapi import SmartConnect +from smartapi.smartConnect import SmartConnect #create object of call obj=SmartConnect() @@ -55,7 +55,7 @@ except Exception as e: print("Logout failed: {}".format(e.message)) #websocket -from smartapi import SmartSocket +from smartapi.smartSocket import SmartSocket FEED_TOKEN= "your feed token" CLIENT_CODE="your client code" token="channel you want the information of" #"nse_cm|2885&nse_cm|1594&nse_cm|11536" diff --git a/SmartApi/__pycache__/smartExceptions.cpython-36.pyc b/SmartApi/__pycache__/smartExceptions.cpython-36.pyc index 8f9b5aa985bb0e1a1e0bb9b191002e1c45efda26..0abc8e087c8daca464e62acd1f3d0e6a089aeb77 100644 GIT binary patch delta 16 XcmcaBb61Aln3tF9-n%0k*~9n%Gv5XM delta 16 XcmcaBb61Aln3tDpDeKCO>|uNWEK>x) diff --git a/SmartApi/__pycache__/version.cpython-36.pyc b/SmartApi/__pycache__/version.cpython-36.pyc index 289b8a749518b7cceada335149ee19d1674de2b2..5c18fcb3a55deda9eb0f6d3343285d535f761f4c 100644 GIT binary patch delta 20 ccmaFB{D7I=n3tDp&d(zg*>5o#O?>nZ08MQOlmGw# delta 20 ccmaFB{D7I=n3tDpE7Qt}?6(*VCqDWI07K&kng9R* diff --git a/SmartApi/smartConnect.py b/SmartApi/smartConnect.py index 0d4b880..1bda6e1 100644 --- a/SmartApi/smartConnect.py +++ b/SmartApi/smartConnect.py @@ -1,7 +1,6 @@ from six.moves.urllib.parse import urljoin import sys -sys.path.append('c:\AngelSmartApi\SmartApi') import csv import json import dateutil.parser @@ -243,12 +242,13 @@ def generateSession(self,clientCode,password): id=user['data']['clientcode'] #id='D88311' - print(id) + # + #print(id) self.setUserId(id) user['data']['jwtToken']="Bearer "+jwtToken user['data']['refreshToken']=refreshToken - print("USER",user) + #print("USER",user) return user def terminateSession(self,clientCode): diff --git a/SmartApi/version.py b/SmartApi/version.py index 55bbe6a..5d371db 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.2" +__version__ = "1.0.3" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/example/sample.py b/example/sample.py index 1d5c4f3..eb9f1fb 100644 --- a/example/sample.py +++ b/example/sample.py @@ -1,5 +1,5 @@ # package import statement -from smartapi import SmartConnect +from smartapi.smartConnect import SmartConnect obj=SmartConnect() #login api call diff --git a/setup.py b/setup.py index 03f07aa..bac95ef 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.2", + version="1.0.3", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", diff --git a/test/test.py b/test/test.py index c09ab2d..5701eae 100644 --- a/test/test.py +++ b/test/test.py @@ -5,13 +5,12 @@ #print(dir) #paths=dir.split("\") -sys.path.append(dir + "\SmartApi") +sys.path.append(dir + "\smartapi") #print(sys.path) -from smartapi import SmartConnect +from smartapi.smartConnect import SmartConnect -smartApi = -SmartConnect() +smartApi = SmartConnect() login = smartApi.generateSession('D88311', 'Angel@444') print(login) @@ -73,7 +72,7 @@ smartApi.convertPosition(params) smartApi.terminateSession('D88311') -from smartapi import SmartSocket +from smartapi.smartSocket import SmartSocket FEED_TOKEN='1731759952' CLIENT_CODE='S212741' token=None From ff144d3762bd3966e23c0df04bf110097ad73029 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 30 Nov 2020 20:12:12 +0530 Subject: [PATCH 09/33] Changes in import statement and version --- SmartApi/smartConnect.py | 2 -- SmartApi/version.py | 2 +- example/sample.py | 2 +- setup.py | 2 +- test/test.py | 7 +++---- 5 files changed, 6 insertions(+), 9 deletions(-) diff --git a/SmartApi/smartConnect.py b/SmartApi/smartConnect.py index 8610d25..61aa61b 100644 --- a/SmartApi/smartConnect.py +++ b/SmartApi/smartConnect.py @@ -1,7 +1,5 @@ from six.moves.urllib.parse import urljoin import sys - -sys.path.append('c:\AngelSmartApi\SmartApi') import csv import json import dateutil.parser diff --git a/SmartApi/version.py b/SmartApi/version.py index 55bbe6a..5d371db 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.2" +__version__ = "1.0.3" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/example/sample.py b/example/sample.py index 1d5c4f3..eb9f1fb 100644 --- a/example/sample.py +++ b/example/sample.py @@ -1,5 +1,5 @@ # package import statement -from smartapi import SmartConnect +from smartapi.smartConnect import SmartConnect obj=SmartConnect() #login api call diff --git a/setup.py b/setup.py index 03f07aa..bac95ef 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.2", + version="1.0.3", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", diff --git a/test/test.py b/test/test.py index c09ab2d..bbd1838 100644 --- a/test/test.py +++ b/test/test.py @@ -8,10 +8,9 @@ sys.path.append(dir + "\SmartApi") #print(sys.path) -from smartapi import SmartConnect +from smartapi.smartConnect import SmartConnect -smartApi = -SmartConnect() +smartApi =SmartConnect() login = smartApi.generateSession('D88311', 'Angel@444') print(login) @@ -73,7 +72,7 @@ smartApi.convertPosition(params) smartApi.terminateSession('D88311') -from smartapi import SmartSocket +from smartapi.smartSocket import SmartSocket FEED_TOKEN='1731759952' CLIENT_CODE='S212741' token=None From c230c9efafdc8e7c4ba4c9caabee58de7c61ae6c Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 30 Nov 2020 20:18:49 +0530 Subject: [PATCH 10/33] Changes in readme --- README.md | 4 ++-- .../smartExceptions.cpython-36.pyc | Bin 3677 -> 3677 bytes SmartApi/__pycache__/version.cpython-36.pyc | Bin 480 -> 480 bytes 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c008a48..c8d39ef 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ pip install smartapi-python ```python # package import statement -from smartapi import SmartConnect +from smartapi.smartConnect import SmartConnect #create object of call obj=SmartConnect() @@ -55,7 +55,7 @@ except Exception as e: print("Logout failed: {}".format(e.message)) #websocket -from smartapi import SmartSocket +from smartapi.smartSocket import SmartSocket FEED_TOKEN= "your feed token" CLIENT_CODE="your client code" token="channel you want the information of" #"nse_cm|2885&nse_cm|1594&nse_cm|11536" diff --git a/SmartApi/__pycache__/smartExceptions.cpython-36.pyc b/SmartApi/__pycache__/smartExceptions.cpython-36.pyc index 8f9b5aa985bb0e1a1e0bb9b191002e1c45efda26..0abc8e087c8daca464e62acd1f3d0e6a089aeb77 100644 GIT binary patch delta 16 XcmcaBb61Aln3tF9-n%0k*~9n%Gv5XM delta 16 XcmcaBb61Aln3tDpDeKCO>|uNWEK>x) diff --git a/SmartApi/__pycache__/version.cpython-36.pyc b/SmartApi/__pycache__/version.cpython-36.pyc index 289b8a749518b7cceada335149ee19d1674de2b2..484ba97bb29333756e40468e7b7b97e8aa853697 100644 GIT binary patch delta 20 ccmaFB{D7I=n3tE!g5~H$_FIg`6CeEp06&}uJpcdz delta 20 ccmaFB{D7I=n3tDpE7Qt}?6(*VCqDWI07K&kng9R* From 7dbc0ff82fc5f3f8c2d1d928718be35757ebe4e1 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 30 Nov 2020 20:21:08 +0530 Subject: [PATCH 11/33] changes in version --- SmartApi/version.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SmartApi/version.py b/SmartApi/version.py index 5d371db..df813ff 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.3" +__version__ = "1.0.3.1" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/setup.py b/setup.py index bac95ef..a4eeb3a 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.3", + version="1.0.3.1", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", From 42b4c25953d7380dbc1dd91b46aaa3dba602d063 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 30 Nov 2020 20:30:56 +0530 Subject: [PATCH 12/33] bugs resolved --- SmartApi/smartConnect.py | 8 -------- SmartApi/version.py | 2 +- setup.py | 2 +- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/SmartApi/smartConnect.py b/SmartApi/smartConnect.py index 61aa61b..2900dd4 100644 --- a/SmartApi/smartConnect.py +++ b/SmartApi/smartConnect.py @@ -274,15 +274,7 @@ def renewAccessToken(self): if "jwtToken" in response: tokenSet['jwtToken']=response['data']['jwtToken'] -<<<<<<< HEAD -<<<<<<< HEAD tokenSet['clientcode']=self. userId -======= - tokenSet['clientcode']=self.userId ->>>>>>> d8cd1ced0e9e79452791072bec4213ec85e370b1 -======= - tokenSet['clientcode']=self. userId ->>>>>>> develop tokenSet['refreshToken']=response['data']["refreshToken"] return tokenSet diff --git a/SmartApi/version.py b/SmartApi/version.py index df813ff..9dac5cd 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.3.1" +__version__ = "1.0.3.2" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/setup.py b/setup.py index a4eeb3a..3035b70 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.3.1", + version="1.0.3.2", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", From 064faf6ddf31f9e7920b97f0c02408af983a50ca Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 30 Nov 2020 20:35:31 +0530 Subject: [PATCH 13/33] bugs resolved --- SmartApi/smartConnect.py | 2 +- SmartApi/version.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SmartApi/smartConnect.py b/SmartApi/smartConnect.py index 2900dd4..de9fed1 100644 --- a/SmartApi/smartConnect.py +++ b/SmartApi/smartConnect.py @@ -94,7 +94,7 @@ def __init__(self, api_key=None, access_token=None, refresh_token=None, userId=N self.refresh_token = refresh_token self.userId = userId self.proxies = proxies if proxies else {} - self.root = root or self._loginUrl + self.root = root or self._login_url self.timeout = timeout or self._default_timeout if pool: diff --git a/SmartApi/version.py b/SmartApi/version.py index 9dac5cd..b5098a7 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.3.2" +__version__ = "1.0.3.3" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/setup.py b/setup.py index 3035b70..863bf49 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.3.2", + version="1.0.3.3", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", From 75447d4039182f5715c0f902af443a4ba7674152 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 30 Nov 2020 21:00:43 +0530 Subject: [PATCH 14/33] changes in root variable --- .../__pycache__/smartConnect.cpython-36.pyc | Bin 10823 -> 10665 bytes SmartApi/smartConnect.py | 2 +- SmartApi/version.py | 2 +- setup.py | 2 +- test/test.py | 4 ++-- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/SmartApi/__pycache__/smartConnect.cpython-36.pyc b/SmartApi/__pycache__/smartConnect.cpython-36.pyc index 87d7f6cf32a2cff265de5513bc7f0d91c811bc0f..0c5a599335c27382a8335818536f07de4a9b7e6e 100644 GIT binary patch delta 822 zcmYk)U2IEX9LMqVZ@c!`+P&yz?Z#-kv2JwOtG%-^n|Is1JVtf>)wE7qnF^UijdA6M zzr>Ar2^YBSt|cx+A|Y{0BHk{DM7-R|g1^IslRVGooAW%+$;ruiJaTV1+vsxT|8zYH z_cUqRJMF*ACfzIJ*j<^RfebB4is(;U42!auT9wt*rfjBp%5LgV4pUv}rt{Q1)BHq% za+>8*E^*vyxRQmc@ZV#LRFSz@tcp!bREcOa<|p0Coh((Qq{Z|^S!}^MQso00@?f9Q zV2^puS(O)-VJ+zRD6gvp>4oF?q>)I+Q(IZ5R=UEybl#37@WIDV$&G?)Cz3Gpqvb02%E%g12$ue#7b<%HgOfUV~4mJJ25OaVg#dN6Lw*@*o-~c zE4DykpV*2q>=)Z`0AX)Y7@tfZiKiw)(R4C*$a*2qu7@Yn=}hjsKA&h0+w*@= znyKIk%!r&j_v4nOcT~R86x> zjdz>u9xsd`CPux`-Mj8TU}9q8#U@^v5ED^@iF)Uy(apY0G}%k%WZvJCIp^e@yvaO> zKN&CfR#&^{mLDe$^eM_4<$sTz^Dw_Ne{+EX(v&O-qLpmZY{I76G8Gv+D(1g^s}z;i zT$QM@bO@)VOSmlE!fojh9!qbgS`=4V(IxVu~B5O8^gSFBQ9bDKXBRv4STSc zQzwd9jA9?hF6h{gA31g701ooj7=FSbb~6rRjNO7GILh|m7>={Oh+~}X!wH;Zx8f9j zX1C!q1lx}@m|zER7U$UQNMMp3L=xxO9Y_I14nt6Jf!&EIOtZTXdg_Dz^mch#az~ z`6&hNerYCZmH)0=qE7j;NqGhXT?F73esp zKj@^q+V+`*EQIe-O0JI#({4E#3A=?ekv9zUL|!YGBI7n+!^-b Date: Tue, 1 Dec 2020 11:17:56 +0530 Subject: [PATCH 15/33] Updated code --- README.md | 6 +++--- .../__pycache__/smartConnect.cpython-36.pyc | Bin 10665 -> 10666 bytes SmartApi/smartConnect.py | 2 +- example/sample.py | 2 +- test/test.py | 12 ++++++------ 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c8d39ef..0e07ded 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,11 @@ pip install smartapi-python from smartapi.smartConnect import SmartConnect #create object of call -obj=SmartConnect() +obj=SmartConnect(api_key="your api key") #login api call -data = obj.generateSession("D88311","Angel@444") +data = obj.generateSession("Your Client ID","Your Password") refreshToken= data['data']['refreshToken'] #fetch User Profile @@ -57,7 +57,7 @@ except Exception as e: #websocket from smartapi.smartSocket import SmartSocket FEED_TOKEN= "your feed token" -CLIENT_CODE="your client code" +CLIENT_CODE="your client Id" token="channel you want the information of" #"nse_cm|2885&nse_cm|1594&nse_cm|11536" ss = SmartSocket(FEED_TOKEN, CLIENT_CODE) diff --git a/SmartApi/__pycache__/smartConnect.cpython-36.pyc b/SmartApi/__pycache__/smartConnect.cpython-36.pyc index 0c5a599335c27382a8335818536f07de4a9b7e6e..cc8f43153212531ee550407f62b3ee31d0fca763 100644 GIT binary patch delta 568 zcmY+9&2G~`6ov1d1`{W7?AT6PH)-pnZ3JwA4X{OGgM{RYrfg89o6T5?gfZ%mW*RA$ z*ttT=h6OJGI~0irK)@654s3Y>#2se?vh4Akd*+;PJ|>?M`>x|O?gigpKK^W9J2+Xs zch2Stq^Fy7L$}D%4&Bsk)lzk3s|K%4<)}8*Kh(9$zE1YVe6>fm6v``5xzuuq)jH?ihxl>HooXF%&sxWJ&Fn}PzPLhhwI|1?gxT-@}V5jb`{sB ze#yQCo~#Q4Y15!UP8%`)K9~P7rL>cZ>OY`C1hkvZ*ITv}Ch#C1s%pg1hsA~tRml6j z2&%(zDHf=L1ZemV?gImwtYJnBQ(eSpv~MoAKynkfJ-+NdJx!tz{soyqk}m)N delta 570 zcmY+9%We}f6ozeg7&4Q%^<0v6(x#oZDYpd@V#5N&mJJfpMD(&jl}-r8Ev>x&WE;2MA&}s{ zfh&Ww2~4C`psORtVfOQk`O* zXT)9JZP=XZq#&^O5AGccT3o>FBaC~9)nM2#iv*$|*RM{y4^PW+emcn?j7E?0YW(#1 l_?fynU2rk Date: Tue, 1 Dec 2020 18:20:57 +0530 Subject: [PATCH 16/33] updated Readme file --- README.md | 2 +- SmartApi/version.py | 2 +- example/sample.py | 2 +- setup.py | 2 +- test/test.py | 19 ++++++------------- 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 0e07ded..080f2f4 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ except Exception as e: #logout try: - logout=obj.terminateSession('D88311') + logout=obj.terminateSession('Your Client Id') print("Logout Successfull") except Exception as e: print("Logout failed: {}".format(e.message)) diff --git a/SmartApi/version.py b/SmartApi/version.py index 899adde..0d3b5d4 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.3.4" +__version__ = "1.0.4" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/example/sample.py b/example/sample.py index 182f99d..1b9f704 100644 --- a/example/sample.py +++ b/example/sample.py @@ -33,7 +33,7 @@ #logout try: - logout=obj.terminateSession('D88311') + logout=obj.terminateSession('Your Client Id') print("Logout Successfull") except Exception as e: print("Logout failed: {}".format(e.message)) \ No newline at end of file diff --git a/setup.py b/setup.py index af44515..0b29e51 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.3.4", + version="1.0.4", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", diff --git a/test/test.py b/test/test.py index 15daa61..1f7279a 100644 --- a/test/test.py +++ b/test/test.py @@ -1,22 +1,15 @@ import sys import os -dir = os.getcwd() -#print(dir) -#paths=dir.split("\") - -sys.path.append(dir + "\SmartApi") -#print(sys.path) - from smartConnect import SmartConnect -smartApi =SmartConnect(api_key="smartapi_key") +smartApi =SmartConnect(api_key="Your Api Key") -login = smartApi.generateSession('Your client id', 'Password') +login = smartApi.generateSession('Your Client Id', 'Your Password') print(login) refreshToken = login['data']['refreshToken'] smartApi.getProfile(refreshToken) -#smartApi.generateToken(refreshToken) +smartApi.generateToken(refreshToken) orderparams = { "variety": "NORMAL", "tradingsymbol": "SBIN-EQ", @@ -70,11 +63,11 @@ } smartApi.convertPosition(params) -smartApi.terminateSession('Your client code') +smartApi.terminateSession("Your Client Id") from smartapi.smartSocket import SmartSocket -FEED_TOKEN='feedToken' #'1731759952' -CLIENT_CODE='Your client id' #'S212741' +FEED_TOKEN="Your Feed Token" +CLIENT_CODE="Your Client Id" token=None ss = SmartSocket(FEED_TOKEN, CLIENT_CODE) def on_tick(ws, tick): From e5e1457137da59ed7959eb90269e94bbca0c9c01 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Thu, 3 Dec 2020 11:53:43 +0530 Subject: [PATCH 17/33] changes in init.py file and readme file --- README.md | 7 ++++--- SmartApi/__init__.py | 3 +-- SmartApi/version.py | 2 +- example/sample.py | 2 +- requirements_dev.txt | 2 +- setup.py | 2 +- test/test.py | 15 ++++++++++----- 7 files changed, 19 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 080f2f4..3805a8c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ pip install smartapi-python ```python # package import statement -from smartapi.smartConnect import SmartConnect +from smartapi import SmartConnect #or from smartapi.smartConnect import SmartConnect +#import smartapi.smartExceptions(for smartExceptions) #create object of call obj=SmartConnect(api_key="your api key") @@ -54,8 +55,8 @@ try: except Exception as e: print("Logout failed: {}".format(e.message)) -#websocket -from smartapi.smartSocket import SmartSocket +##------websocket------ +from smartapi import SmartSocket #or from smartapi.smartSocket import SmartSocket FEED_TOKEN= "your feed token" CLIENT_CODE="your client Id" token="channel you want the information of" #"nse_cm|2885&nse_cm|1594&nse_cm|11536" diff --git a/SmartApi/__init__.py b/SmartApi/__init__.py index f5955af..ab3c672 100644 --- a/SmartApi/__init__.py +++ b/SmartApi/__init__.py @@ -1,10 +1,9 @@ from __future__ import unicode_literals,absolute_import -from smartapi import smartExceptions from smartapi.smartConnect import SmartConnect from smartapi.smartSocket import SmartSocket -__all__ = ["smartExceptions","SmartConnect","SmartSocket"] +__all__ = ["SmartConnect","SmartSocket"] diff --git a/SmartApi/version.py b/SmartApi/version.py index 0d3b5d4..bb1956b 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.4" +__version__ = "1.0.5" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/example/sample.py b/example/sample.py index 1b9f704..7764fd6 100644 --- a/example/sample.py +++ b/example/sample.py @@ -1,5 +1,5 @@ # package import statement -from smartapi.smartConnect import SmartConnect +from smartapi.smartConnect import SmartConnect #from smartapi import SmartConnect obj=SmartConnect() #login api call diff --git a/requirements_dev.txt b/requirements_dev.txt index c1693f2..84c6643 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,2 +1,2 @@ requests>=2.24.0 -twine>=1.13.0 \ No newline at end of file +twine>=1.13.0 diff --git a/setup.py b/setup.py index 0b29e51..01cf503 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.4", + version="1.0.5", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", diff --git a/test/test.py b/test/test.py index 1f7279a..b536a0e 100644 --- a/test/test.py +++ b/test/test.py @@ -1,7 +1,10 @@ -import sys -import os -from smartConnect import SmartConnect +from smartapi import SmartConnect + +#---------for smartExceptions--------- +#import smartapi.smartExceptions +#or +#from smartapi import smartExceptions smartApi =SmartConnect(api_key="Your Api Key") @@ -63,9 +66,11 @@ } smartApi.convertPosition(params) -smartApi.terminateSession("Your Client Id") +smartApi.terminateSession('S212741') + +## Websocket Programming -from smartapi.smartSocket import SmartSocket +from smartapi import SmartSocket FEED_TOKEN="Your Feed Token" CLIENT_CODE="Your Client Id" token=None From 260fc762ccfbf82f00944f199733bc757d1ed6e6 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Tue, 8 Dec 2020 16:53:49 +0530 Subject: [PATCH 18/33] getFeedToken() function added, Changes in import statement for websocket --- README.md | 8 +- SmartApi/__init__.py | 4 +- .../__pycache__/smartConnect.cpython-36.pyc | Bin 10666 -> 10666 bytes SmartApi/smartConnect.py | 19 +++- SmartApi/version.py | 4 +- SmartApi/{smartSocket.py => webSocket.py} | 95 ++++++++++++++++-- setup.py | 3 +- test/test.py | 10 +- 8 files changed, 115 insertions(+), 28 deletions(-) rename SmartApi/{smartSocket.py => webSocket.py} (77%) diff --git a/README.md b/README.md index 3805a8c..fe16cc4 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,9 @@ obj=SmartConnect(api_key="your api key") data = obj.generateSession("Your Client ID","Your Password") refreshToken= data['data']['refreshToken'] +#fetch the feedtoken +feedToken=obj.getFeedToken() + #fetch User Profile userProfile= obj.getProfile(refreshToken) #place order @@ -56,7 +59,7 @@ except Exception as e: print("Logout failed: {}".format(e.message)) ##------websocket------ -from smartapi import SmartSocket #or from smartapi.smartSocket import SmartSocket +from smartapi import WebSocket #or from smartapi.smartSocket import SmartSocket FEED_TOKEN= "your feed token" CLIENT_CODE="your client Id" token="channel you want the information of" #"nse_cm|2885&nse_cm|1594&nse_cm|11536" @@ -80,7 +83,6 @@ ss.on_close = on_close ss.connect( ) -License -MIT + diff --git a/SmartApi/__init__.py b/SmartApi/__init__.py index ab3c672..4ddea18 100644 --- a/SmartApi/__init__.py +++ b/SmartApi/__init__.py @@ -1,9 +1,9 @@ from __future__ import unicode_literals,absolute_import from smartapi.smartConnect import SmartConnect -from smartapi.smartSocket import SmartSocket +from smartapi.webSocket import WebSocket -__all__ = ["SmartConnect","SmartSocket"] +__all__ = ["SmartConnect","WebSocket"] diff --git a/SmartApi/__pycache__/smartConnect.cpython-36.pyc b/SmartApi/__pycache__/smartConnect.cpython-36.pyc index cc8f43153212531ee550407f62b3ee31d0fca763..7a7be233af39fa670bae0a86f2d1555df0d14b7d 100644 GIT binary patch delta 16 XcmZ1#yegR8n3tDpLd}Vd?29!4FXRQW delta 16 XcmZ1#yegR8n3tE!MEK}N_Qje2D%%9< diff --git a/SmartApi/smartConnect.py b/SmartApi/smartConnect.py index 10d3dbc..b08a3a4 100644 --- a/SmartApi/smartConnect.py +++ b/SmartApi/smartConnect.py @@ -85,13 +85,14 @@ class SmartConnect(object): "api.convert.position": "/rest/secure/angelbroking/order/v1/convertPosition" } - def __init__(self, api_key=None, access_token=None, refresh_token=None, userId=None, root=None, debug=False, timeout=None, proxies=None, pool=None, disable_ssl=False): + def __init__(self, api_key=None, access_token=None, refresh_token=None,feed_token=None, userId=None, root=None, debug=False, timeout=None, proxies=None, pool=None, disable_ssl=False): self.debug = debug self.api_key = api_key self.session_expiry_hook = None self.disable_ssl = disable_ssl self.access_token = access_token self.refresh_token = refresh_token + self.feed_token = feed_token self.userId = userId self.proxies = proxies if proxies else {} self.root = root or self._rootUrl @@ -126,6 +127,14 @@ def setAccessToken(self, access_token): def setRefreshToken(self, refresh_token): self.refresh_token = refresh_token + + def setFeedToken(self,feedToken): + + self.feed_token=feedToken + + def getfeedToken(self): + return self.feed_token + def login_url(self): """Get the remote login url to which a user should be redirected to initiate the login flow.""" @@ -236,16 +245,17 @@ def generateSession(self,clientCode,password): jwtToken=loginResultObject['data']['jwtToken'] self.setAccessToken(jwtToken) refreshToken=loginResultObject['data']['refreshToken'] + feedToken=loginResultObject['data']['feedToken'] self.setRefreshToken(refreshToken) + self.setFeedToken(feedToken) user=self.getProfile(refreshToken) id=user['data']['clientcode'] #id='D88311' - print(id) - self.setUserId(id) user['data']['jwtToken']="Bearer "+jwtToken user['data']['refreshToken']=refreshToken + print("USER",user) return user @@ -256,7 +266,10 @@ def terminateSession(self,clientCode): def generateToken(self,refresh_token): response=self._postRequest('api.token',{"refreshToken":refresh_token}) jwtToken=response['data']['jwtToken'] + feedToken=response['data']['feedToken'] + self.setFeedToken(feedToken) self.setAccessToken(jwtToken) + return response def renewAccessToken(self): diff --git a/SmartApi/version.py b/SmartApi/version.py index bb1956b..ec95919 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,11 +2,11 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.5" +__version__ = "1.0.5.1" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" -__license__ = "MIT" + # [pypi] # username = __token__ diff --git a/SmartApi/smartSocket.py b/SmartApi/webSocket.py similarity index 77% rename from SmartApi/smartSocket.py rename to SmartApi/webSocket.py index 5044463..14e40ca 100644 --- a/SmartApi/smartSocket.py +++ b/SmartApi/webSocket.py @@ -7,6 +7,7 @@ import logging import threading import base64 +import zlib from datetime import datetime from twisted.internet import reactor, ssl from twisted.python import log as twisted_log @@ -15,6 +16,15 @@ class SmartSocketClientProtocol(WebSocketClientProtocol): + PING_INTERVAL = 2.5 + KEEPALIVE_INTERVAL = 5 + + _ping_message = "" + _next_ping = None + _next_pong_check = None + _last_pong_time = None + _last_ping_time = None + def __init__(self, *args, **kwargs): super(SmartSocketClientProtocol,self).__init__(*args,**kwargs) @@ -26,13 +36,20 @@ def onConnect(self, response): # noqa self.factory.on_connect(self, response) def onOpen(self): + # send ping + self._loop_ping() + # init last pong check after X seconds + self._loop_pong_check() + if self.factory.on_open: self.factory.on_open(self) + def onMessage(self, payload, is_binary): # noqa #print("""Called when text or binary message is received.""",payload,is_binary) if self.factory.on_message: self.factory.on_message(self, payload, is_binary) + def onClose(self, was_clean, code, reason): # noqa """Called when connection is closed.""" @@ -42,6 +59,61 @@ def onClose(self, was_clean, code, reason): # noqa if self.factory.on_close: self.factory.on_close(self, code, reason) + # Cancel next ping and timer + self._last_ping_time = None + self._last_pong_time = None + + if self._next_ping: + self._next_ping.cancel() + + if self._next_pong_check: + self._next_pong_check.cancel() + + def onPong(self, response): # noqa + """Called when pong message is received.""" + if self._last_pong_time and self.factory.debug: + log.debug("last pong was {} seconds back.".format(time.time() - self._last_pong_time)) + + self._last_pong_time = time.time() + + if self.factory.debug: + log.debug("pong => {}".format(response)) + + """ + Custom helper and exposed methods. + """ + def _loop_ping(self): # noqa + """Start a ping loop where it sends ping message every X seconds.""" + if self.factory.debug: + log.debug("ping => {}".format(self._ping_message)) + if self._last_ping_time: + log.debug("last ping was {} seconds back.".format(time.time() - self._last_ping_time)) + + # Set current time as last ping time + self._last_ping_time = time.time() + # Send a ping message to server + self.sendPing(self._ping_message) + + # Call self after X seconds + self._next_ping = self.factory.reactor.callLater(self.PING_INTERVAL, self._loop_ping) + + def _loop_pong_check(self): + """ + Timer sortof to check if connection is still there. + Checks last pong message time and disconnects the existing connection to make sure it doesn't become a ghost connection. + """ + if self._last_pong_time: + # No pong message since long time, so init reconnect + last_pong_diff = time.time() - self._last_pong_time + if last_pong_diff > (2 * self.PING_INTERVAL): + if self.factory.debug: + log.debug("Last pong was {} seconds ago. So dropping connection to reconnect.".format( + last_pong_diff)) + # drop existing connection to avoid ghost connection + self.dropConnection(abort=True) + + # Call self after X seconds + self._next_pong_check = self.factory.reactor.callLater(self.PING_INTERVAL, self._loop_pong_check) class SmartSocketClientFactory(WebSocketClientFactory): protocol = SmartSocketClientProtocol @@ -141,6 +213,7 @@ def is_connected(self): return True else: return False + def _close(self, code=None, reason=None): #print("Close the WebSocket connection.") if self.ws: @@ -158,9 +231,8 @@ def stop(self): reactor.stop() def send_request(self,token): - #print('Request Send') - strwatchlistscrips = token # "nse_cm|2885&nse_cm|1594&nse_cm|11536" - #token_scripts= token //dynamic call + strwatchlistscrips = token #dynamic call + try: #print("Inside") request={"task":"cn","channel":"","token":self.feed_token,"user":self.client_code,"acctid":self.client_code} @@ -168,7 +240,7 @@ def send_request(self,token): six.b(json.dumps(request)) ) #print(request) - request={"task":"cn","channel":strwatchlistscrips,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} + request={"task":"mw","channel":strwatchlistscrips,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} #print(request) #request={"task":"cn","channel":token_scripts,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} //dynamic call self.ws.sendMessage( @@ -187,14 +259,14 @@ def _on_connect(self, ws, response): def _on_close(self, ws, code, reason): """Call `on_close` callback when connection is closed.""" - print("Connection closed: {} - {}".format(code, str(reason))) + log.debug("Connection closed: {} - {}".format(code, str(reason))) if self.on_close: self.on_close(self, code, reason) def _on_error(self, ws, code, reason): """Call `on_error` callback when connection throws an error.""" - print("Connection error: {} - {}".format(code, str(reason))) + log.debug("Connection error: {} - {}".format(code, str(reason))) if self.on_error: self.on_error(self, code, reason) @@ -221,13 +293,16 @@ def _parse_text_message(self, payload): # Decode unicode data if not six.PY2 and type(payload) == bytes: payload = payload.decode("utf-8") - print("PAYLOAD",payload) + data =base64.b64decode(payload) - print("DATA",data) + + try: - data = json.loads(payload) - print("DATA",data) + data=zlib.decompress(data) + print(data.decode("utf-8")) + except ValueError: + return def _parse_binary(self, bin): diff --git a/setup.py b/setup.py index 01cf503..d60474f 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.5", + version="1.0.5.1", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", @@ -28,7 +28,6 @@ "Intended Audience :: Financial and Insurance Industry", "Programming Language :: Python", "Natural Language :: English", - "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", diff --git a/test/test.py b/test/test.py index b536a0e..2698a59 100644 --- a/test/test.py +++ b/test/test.py @@ -1,4 +1,3 @@ - from smartapi import SmartConnect #---------for smartExceptions--------- @@ -11,6 +10,7 @@ login = smartApi.generateSession('Your Client Id', 'Your Password') print(login) refreshToken = login['data']['refreshToken'] +feedToken = smartApi.getfeedToken() smartApi.getProfile(refreshToken) smartApi.generateToken(refreshToken) orderparams = { @@ -66,11 +66,11 @@ } smartApi.convertPosition(params) -smartApi.terminateSession('S212741') +smartApi.terminateSession('Your Client Id') ## Websocket Programming -from smartapi import SmartSocket +from smartapi import WebSocket FEED_TOKEN="Your Feed Token" CLIENT_CODE="Your Client Id" token=None @@ -88,6 +88,4 @@ def on_close(ws, code, reason): ss.on_connect = on_connect ss.on_close = on_close -ss.connect( ) - - +ss.connect( ) \ No newline at end of file From ea49f8ba177d99f84e450b7523b0e24373ab3df8 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Tue, 8 Dec 2020 17:01:06 +0530 Subject: [PATCH 19/33] getFeedToken() function added, Changes in import statement for websocket --- SmartApi/version.py | 2 +- SmartApi/webSocket.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SmartApi/version.py b/SmartApi/version.py index ec95919..4cb9a7b 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.5.1" +__version__ = "1.0.5.2" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/SmartApi/webSocket.py b/SmartApi/webSocket.py index 14e40ca..68ffc5b 100644 --- a/SmartApi/webSocket.py +++ b/SmartApi/webSocket.py @@ -132,7 +132,7 @@ def __init__(self, *args, **kwargs): super(SmartSocketClientFactory, self).__init__(*args, **kwargs) -class SmartSocket(object): +class WebSocket(object): EXCHANGE_MAP = { "nse": 1, "nfo": 2, diff --git a/setup.py b/setup.py index d60474f..3d2bc62 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.5.1", + version="1.0.5.2", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", From 8fecc004e01e903c1bff295114f04ac971a82af4 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Wed, 9 Dec 2020 19:18:58 +0530 Subject: [PATCH 20/33] Changes in import statement for websocket --- README.md | 4 ++-- SmartApi/version.py | 2 +- setup.py | 2 +- test/test.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fe16cc4..037b33f 100644 --- a/README.md +++ b/README.md @@ -59,12 +59,12 @@ except Exception as e: print("Logout failed: {}".format(e.message)) ##------websocket------ -from smartapi import WebSocket #or from smartapi.smartSocket import SmartSocket +from smartapi import WebSocket FEED_TOKEN= "your feed token" CLIENT_CODE="your client Id" token="channel you want the information of" #"nse_cm|2885&nse_cm|1594&nse_cm|11536" -ss = SmartSocket(FEED_TOKEN, CLIENT_CODE) +ss = WebSocket(FEED_TOKEN, CLIENT_CODE) def on_tick(ws, tick): print("Ticks: {}".format(tick)) diff --git a/SmartApi/version.py b/SmartApi/version.py index 4cb9a7b..4aa5bd2 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.5.2" +__version__ = "1.0.5.3" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/setup.py b/setup.py index 3d2bc62..efb5061 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.5.2", + version="1.0.5.3", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", diff --git a/test/test.py b/test/test.py index 2698a59..6cef4ec 100644 --- a/test/test.py +++ b/test/test.py @@ -74,7 +74,7 @@ FEED_TOKEN="Your Feed Token" CLIENT_CODE="Your Client Id" token=None -ss = SmartSocket(FEED_TOKEN, CLIENT_CODE) +ss = WebSocket(FEED_TOKEN, CLIENT_CODE) def on_tick(ws, tick): print("Ticks: {}".format(tick)) def on_connect(ws, response): From 9765bcba2eb9f3d71489e7a3d9ff7205ba5d81e6 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Thu, 10 Dec 2020 13:24:10 +0530 Subject: [PATCH 21/33] getfeedToken() --- README.md | 2 +- SmartApi/version.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 037b33f..a05e03d 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ data = obj.generateSession("Your Client ID","Your Password") refreshToken= data['data']['refreshToken'] #fetch the feedtoken -feedToken=obj.getFeedToken() +feedToken=obj.getfeedToken() #fetch User Profile userProfile= obj.getProfile(refreshToken) diff --git a/SmartApi/version.py b/SmartApi/version.py index 4aa5bd2..062b65e 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.5.3" +__version__ = "1.0.5.4" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/setup.py b/setup.py index efb5061..4e5489e 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.5.3", + version="1.0.5.4", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", From a9617cee63b0b3b634de4d62348666ddbb6d6eb9 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Thu, 10 Dec 2020 14:48:14 +0530 Subject: [PATCH 22/33] bugs rectified --- SmartApi/version.py | 2 +- SmartApi/webSocket.py | 1 + setup.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/SmartApi/version.py b/SmartApi/version.py index 062b65e..07f66c0 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.5.4" +__version__ = "1.0.5.5" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/SmartApi/webSocket.py b/SmartApi/webSocket.py index 68ffc5b..b048246 100644 --- a/SmartApi/webSocket.py +++ b/SmartApi/webSocket.py @@ -14,6 +14,7 @@ from autobahn.twisted.websocket import WebSocketClientProtocol, \ WebSocketClientFactory, connectWS +log = logging.getLogger(__name__) class SmartSocketClientProtocol(WebSocketClientProtocol): PING_INTERVAL = 2.5 diff --git a/setup.py b/setup.py index 4e5489e..7ed8684 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.5.4", + version="1.0.5.5", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", From bd11f8a4b54216b72d94cb849fd8a8c1ccf6afea Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Fri, 11 Dec 2020 12:12:37 +0530 Subject: [PATCH 23/33] heartbeats added in websocket --- README.md | 2 +- SmartApi/version.py | 2 +- SmartApi/webSocket.py | 195 +++++++++++++++--------------------------- setup.py | 2 +- test/test.py | 20 ++++- 5 files changed, 88 insertions(+), 133 deletions(-) diff --git a/README.md b/README.md index a05e03d..df17c6f 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ try: except Exception as e: print("Logout failed: {}".format(e.message)) -##------websocket------ +## WebSocket from smartapi import WebSocket FEED_TOKEN= "your feed token" CLIENT_CODE="your client Id" diff --git a/SmartApi/version.py b/SmartApi/version.py index 07f66c0..5038776 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.5.5" +__version__ = "1.0.6" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/SmartApi/webSocket.py b/SmartApi/webSocket.py index b048246..adc9aff 100644 --- a/SmartApi/webSocket.py +++ b/SmartApi/webSocket.py @@ -17,14 +17,6 @@ log = logging.getLogger(__name__) class SmartSocketClientProtocol(WebSocketClientProtocol): - PING_INTERVAL = 2.5 - KEEPALIVE_INTERVAL = 5 - - _ping_message = "" - _next_ping = None - _next_pong_check = None - _last_pong_time = None - _last_ping_time = None def __init__(self, *args, **kwargs): super(SmartSocketClientProtocol,self).__init__(*args,**kwargs) @@ -37,11 +29,6 @@ def onConnect(self, response): # noqa self.factory.on_connect(self, response) def onOpen(self): - # send ping - self._loop_ping() - # init last pong check after X seconds - self._loop_pong_check() - if self.factory.on_open: self.factory.on_open(self) @@ -60,61 +47,7 @@ def onClose(self, was_clean, code, reason): # noqa if self.factory.on_close: self.factory.on_close(self, code, reason) - # Cancel next ping and timer - self._last_ping_time = None - self._last_pong_time = None - - if self._next_ping: - self._next_ping.cancel() - - if self._next_pong_check: - self._next_pong_check.cancel() - - def onPong(self, response): # noqa - """Called when pong message is received.""" - if self._last_pong_time and self.factory.debug: - log.debug("last pong was {} seconds back.".format(time.time() - self._last_pong_time)) - - self._last_pong_time = time.time() - - if self.factory.debug: - log.debug("pong => {}".format(response)) - - """ - Custom helper and exposed methods. - """ - def _loop_ping(self): # noqa - """Start a ping loop where it sends ping message every X seconds.""" - if self.factory.debug: - log.debug("ping => {}".format(self._ping_message)) - if self._last_ping_time: - log.debug("last ping was {} seconds back.".format(time.time() - self._last_ping_time)) - - # Set current time as last ping time - self._last_ping_time = time.time() - # Send a ping message to server - self.sendPing(self._ping_message) - - # Call self after X seconds - self._next_ping = self.factory.reactor.callLater(self.PING_INTERVAL, self._loop_ping) - - def _loop_pong_check(self): - """ - Timer sortof to check if connection is still there. - Checks last pong message time and disconnects the existing connection to make sure it doesn't become a ghost connection. - """ - if self._last_pong_time: - # No pong message since long time, so init reconnect - last_pong_diff = time.time() - self._last_pong_time - if last_pong_diff > (2 * self.PING_INTERVAL): - if self.factory.debug: - log.debug("Last pong was {} seconds ago. So dropping connection to reconnect.".format( - last_pong_diff)) - # drop existing connection to avoid ghost connection - self.dropConnection(abort=True) - - # Call self after X seconds - self._next_pong_check = self.factory.reactor.callLater(self.PING_INTERVAL, self._loop_pong_check) + class SmartSocketClientFactory(WebSocketClientFactory): protocol = SmartSocketClientProtocol @@ -225,9 +158,7 @@ def close(self, code=None, reason=None): self._close(code, reason) def stop(self): - """Stop the event loop. Should be used if main thread has to be closed in `on_close` method. - Reconnection mechanism cannot happen past this method - """ + """Stop the event loop. Should be used if main thread has to be closed in `on_close` method.""" #print("stop") reactor.stop() @@ -242,11 +173,11 @@ def send_request(self,token): ) #print(request) request={"task":"mw","channel":strwatchlistscrips,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} - #print(request) - #request={"task":"cn","channel":token_scripts,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} //dynamic call + self.ws.sendMessage( six.b(json.dumps(request)) ) + threading.Thread(target=self.heartBeat,daemon=True).start() #print(request) return True except Exception as e: @@ -289,6 +220,18 @@ def _on_open(self, ws): if self.on_open: return self.on_open(self) + def heartBeat(self): + while True: + try: + request={"task":"hb","channel":"","token":self.feed_token,"user":self.client_code,"acctid":self.client_code} + self.ws.sendMessage( + six.b(json.dumps(request)) + ) + + except: + print("HeartBeats Failed") + time.sleep(60) + def _parse_text_message(self, payload): """Parse text message.""" # Decode unicode data @@ -297,63 +240,63 @@ def _parse_text_message(self, payload): data =base64.b64decode(payload) - try: - data=zlib.decompress(data) - print(data.decode("utf-8")) - + data = bytes((zlib.decompress(data)).decode("utf-8"), 'utf-8') + data = json.loads(data.decode('utf8').replace("'", '"')) + data = json.loads(json.dumps(data, indent=4, sort_keys=True)) except ValueError: - return - def _parse_binary(self, bin): - #print("""Parse binary data to a (list of) ticks structure.""") - packets = self._split_packets(bin) # split data to individual ticks packet - data = [] - - for packet in packets: - instrument_token = self._unpack_int(packet, 0, 4) - segment = instrument_token & 0xff # Retrive segment constant from instrument_token - - divisor = 10000000.0 if segment == self.EXCHANGE_MAP["cds"] else 100.0 - - # All indices are not tradable - tradable = False if segment == self.EXCHANGE_MAP["indices"] else True - try: - last_trade_time = datetime.fromtimestamp(self._unpack_int(packet, 44, 48)) - except Exception: - last_trade_time = None - - try: - timestamp = datetime.fromtimestamp(self._unpack_int(packet, 60, 64)) - except Exception: - timestamp = None - - d["last_trade_time"] = last_trade_time - d["oi"] = self._unpack_int(packet, 48, 52) - d["oi_day_high"] = self._unpack_int(packet, 52, 56) - d["oi_day_low"] = self._unpack_int(packet, 56, 60) - d["timestamp"] = timestamp - - # Market depth entries. - depth = { - "buy": [], - "sell": [] - } - - # Compile the market depth lists. - for i, p in enumerate(range(64, len(packet), 12)): - depth["sell" if i >= 5 else "buy"].append({ - "quantity": self._unpack_int(packet, p, p + 4), - "price": self._unpack_int(packet, p + 4, p + 8) / divisor, - "orders": self._unpack_int(packet, p + 8, p + 10, byte_format="H") - }) - - d["depth"] = depth - - data.append(d) - - return data + self.on_ticks(self, data) + + def _parse_binary(self, bin): + #print("""Parse binary data to a (list of) ticks structure.""") + packets = self._split_packets(bin) # split data to individual ticks packet + data = [] + + for packet in packets: + instrument_token = self._unpack_int(packet, 0, 4) + segment = instrument_token & 0xff # Retrive segment constant from instrument_token + + divisor = 10000000.0 if segment == self.EXCHANGE_MAP["cds"] else 100.0 + + # All indices are not tradable + tradable = False if segment == self.EXCHANGE_MAP["indices"] else True + try: + last_trade_time = datetime.fromtimestamp(self._unpack_int(packet, 44, 48)) + except Exception: + last_trade_time = None + + try: + timestamp = datetime.fromtimestamp(self._unpack_int(packet, 60, 64)) + except Exception: + timestamp = None + + d["last_trade_time"] = last_trade_time + d["oi"] = self._unpack_int(packet, 48, 52) + d["oi_day_high"] = self._unpack_int(packet, 52, 56) + d["oi_day_low"] = self._unpack_int(packet, 56, 60) + d["timestamp"] = timestamp + + # Market depth entries. + depth = { + "buy": [], + "sell": [] + } + + # Compile the market depth lists. + for i, p in enumerate(range(64, len(packet), 12)): + depth["sell" if i >= 5 else "buy"].append({ + "quantity": self._unpack_int(packet, p, p + 4), + "price": self._unpack_int(packet, p + 4, p + 8) / divisor, + "orders": self._unpack_int(packet, p + 8, p + 10, byte_format="H") + }) + + d["depth"] = depth + + data.append(d) + + return data def _unpack_int(self, bin, start, end, byte_format="I"): """Unpack binary data as unsgined interger.""" diff --git a/setup.py b/setup.py index 7ed8684..56def31 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.5.5", + version="1.0.6", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", diff --git a/test/test.py b/test/test.py index 6cef4ec..6e84202 100644 --- a/test/test.py +++ b/test/test.py @@ -8,11 +8,15 @@ smartApi =SmartConnect(api_key="Your Api Key") login = smartApi.generateSession('Your Client Id', 'Your Password') -print(login) + refreshToken = login['data']['refreshToken'] + feedToken = smartApi.getfeedToken() + smartApi.getProfile(refreshToken) + smartApi.generateToken(refreshToken) + orderparams = { "variety": "NORMAL", "tradingsymbol": "SBIN-EQ", @@ -46,14 +50,20 @@ smartApi.cancelOrder(orderid, "NORMAL") smartApi.orderBook() + smartApi.tradeBook() + smartApi.rmsLimit() + smartApi.position() + smartApi.holding() + exchange = "NSE" tradingsymbol = "SBIN-EQ" symboltoken = 3045 smartApi.ltpData("NSE", "SBIN-EQ", "3045") + params={ "exchange": "NSE", "oldproducttype":"DELIVERY", @@ -66,20 +76,22 @@ } smartApi.convertPosition(params) + smartApi.terminateSession('Your Client Id') ## Websocket Programming from smartapi import WebSocket -FEED_TOKEN="Your Feed Token" +FEED_TOKEN=feedToken CLIENT_CODE="Your Client Id" token=None ss = WebSocket(FEED_TOKEN, CLIENT_CODE) def on_tick(ws, tick): print("Ticks: {}".format(tick)) + def on_connect(ws, response): - a=ws.send_request(token) - print("Back to Function",a) + ws.send_request(token) + def on_close(ws, code, reason): ws.stop() From 8b0f85d37040e4406d89b267b070e64c9b05d980 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Tue, 29 Dec 2020 10:54:09 +0530 Subject: [PATCH 24/33] removed unnecessary print statements --- SmartApi/smartConnect.py | 41 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/SmartApi/smartConnect.py b/SmartApi/smartConnect.py index b08a3a4..b0f506a 100644 --- a/SmartApi/smartConnect.py +++ b/SmartApi/smartConnect.py @@ -145,9 +145,7 @@ def _request(self, route, method, parameters=None): params = parameters.copy() if parameters else {} uri =self._routes[route].format(**params) - print(uri) url = urljoin(self.root, uri) - print(url) hostname = socket.gethostname() clientLocalIP=socket.gethostbyname(hostname) clientPublicIP=get('https://api.ipify.org').text @@ -191,7 +189,7 @@ def _request(self, route, method, parameters=None): allow_redirects=True, timeout=self.timeout, proxies=self.proxies) - print("The Response Content",r.content) + #print("The Response Content",r.content) except Exception as e: raise e @@ -242,23 +240,26 @@ def generateSession(self,clientCode,password): params={"clientcode":clientCode,"password":password} loginResultObject=self._postRequest("api.login",params) - jwtToken=loginResultObject['data']['jwtToken'] - self.setAccessToken(jwtToken) - refreshToken=loginResultObject['data']['refreshToken'] - feedToken=loginResultObject['data']['feedToken'] - self.setRefreshToken(refreshToken) - self.setFeedToken(feedToken) - user=self.getProfile(refreshToken) - - id=user['data']['clientcode'] - #id='D88311' - self.setUserId(id) - user['data']['jwtToken']="Bearer "+jwtToken - user['data']['refreshToken']=refreshToken - print("USER",user) - return user - + if loginResultObject['status']==True or true: + jwtToken=loginResultObject['data']['jwtToken'] + self.setAccessToken(jwtToken) + refreshToken=loginResultObject['data']['refreshToken'] + feedToken=loginResultObject['data']['feedToken'] + self.setRefreshToken(refreshToken) + self.setFeedToken(feedToken) + user=self.getProfile(refreshToken) + + id=user['data']['clientcode'] + #id='D88311' + self.setUserId(id) + user['data']['jwtToken']="Bearer "+jwtToken + user['data']['refreshToken']=refreshToken + + #print("USER",user) + return user + else: + return def terminateSession(self,clientCode): logoutResponseObject=self._postRequest("api.logout",{"clientcode":clientCode}) return logoutResponseObject @@ -294,7 +295,7 @@ def renewAccessToken(self): def getProfile(self,refreshToken): user=self._getRequest("api.user.profile",{"refreshToken":refreshToken}) - print("USER PROFILE",user) + #print("USER PROFILE",user) return user def placeOrder(self,orderparams): From 15165d4cd48da76354ea15271cc6147846aa1327 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Tue, 29 Dec 2020 10:55:25 +0530 Subject: [PATCH 25/33] removed unnecessary print statements --- SmartApi/version.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SmartApi/version.py b/SmartApi/version.py index 5038776..845006f 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.0.6" +__version__ = "1.1.0" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/setup.py b/setup.py index 56def31..1bafb88 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.0.6", + version="1.1.0", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", From 5e7d323583a91366a896ecc14fbfedbfda659260 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Tue, 19 Jan 2021 10:37:37 +0530 Subject: [PATCH 26/33] Nameerror resolved --- SmartApi/smartConnect.py | 4 ++-- SmartApi/version.py | 2 +- setup.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SmartApi/smartConnect.py b/SmartApi/smartConnect.py index b0f506a..52ee1af 100644 --- a/SmartApi/smartConnect.py +++ b/SmartApi/smartConnect.py @@ -16,7 +16,6 @@ log = logging.getLogger(__name__) - class SmartConnect(object): #_rootUrl = "https://openapisuat.angelbroking.com" _rootUrl="https://apiconnect.angelbroking.com" #prod endpoint @@ -241,7 +240,7 @@ def generateSession(self,clientCode,password): params={"clientcode":clientCode,"password":password} loginResultObject=self._postRequest("api.login",params) - if loginResultObject['status']==True or true: + if loginResultObject['status']==True : jwtToken=loginResultObject['data']['jwtToken'] self.setAccessToken(jwtToken) refreshToken=loginResultObject['data']['refreshToken'] @@ -260,6 +259,7 @@ def generateSession(self,clientCode,password): return user else: return + def terminateSession(self,clientCode): logoutResponseObject=self._postRequest("api.logout",{"clientcode":clientCode}) return logoutResponseObject diff --git a/SmartApi/version.py b/SmartApi/version.py index 845006f..b44ac8e 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.1.0" +__version__ = "1.1.1" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/setup.py b/setup.py index 1bafb88..98431f7 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.1.0", + version="1.1.1", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", From 10ed69815bdaf79e1b5cb456ec43f0528705ee7e Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Wed, 3 Mar 2021 13:21:58 +0530 Subject: [PATCH 27/33] Gtt services added --- README.md | 30 ++++- SmartApi/smartConnect.py | 147 +++++++++++++++++------- SmartApi/version.py | 2 +- SmartApi/webSocket.py | 235 ++++++++++++++++++++++++++++++++++----- setup.py | 2 +- test/test.py | 37 ++++++ 6 files changed, 384 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index df17c6f..290eb1c 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,33 @@ try: print("The order id is: {}".format(orderId)) except Exception as e: print("Order placement failed: {}".format(e.message)) - +#gtt rule creation +try: + gttCreateParams={ + "tradingsymbol" : "SBIN-EQ", + "symboltoken" : "3045", + "exchange" : "NSE", + "producttype" : "MARGIN", + "transactiontype" : "BUY", + "price" : 100000, + "qty" : 10, + "disclosedqty": 10, + "triggerprice" : 200000, + "timeperiod" : 365 + } + rule_id=gtt.gttCreateRule(gttCreateParams) + print("The GTT rule id is: {}".format(rule_id)) +except Exception as e: + print("GTT Rule creation failed: {}".format(e.message)) + +#gtt rule list +try: + status=["FORALL"] #should be a list + page=1 + count=10 + lists=smartApi.gttLists(status,page,count) +except Exception as e: + print("GTT Rule List failed: {}".format(e.message)) #logout try: logout=obj.terminateSession('Your Client Id') @@ -58,6 +84,8 @@ try: except Exception as e: print("Logout failed: {}".format(e.message)) + + ## WebSocket from smartapi import WebSocket FEED_TOKEN= "your feed token" diff --git a/SmartApi/smartConnect.py b/SmartApi/smartConnect.py index 52ee1af..cc1db99 100644 --- a/SmartApi/smartConnect.py +++ b/SmartApi/smartConnect.py @@ -11,10 +11,12 @@ from requests import get import re, uuid import socket - +import platform from smartapi.version import __version__, __title__ log = logging.getLogger(__name__) +#user_sys=platform.system() +#print("the system",user_sys) class SmartConnect(object): #_rootUrl = "https://openapisuat.angelbroking.com" @@ -81,10 +83,32 @@ class SmartConnect(object): "api.rms.limit": "/rest/secure/angelbroking/user/v1/getRMS", "api.holding": "/rest/secure/angelbroking/portfolio/v1/getHolding", "api.position": "/rest/secure/angelbroking/order/v1/getPosition", - "api.convert.position": "/rest/secure/angelbroking/order/v1/convertPosition" + "api.convert.position": "/rest/secure/angelbroking/order/v1/convertPosition", + + "api.gtt.create":"/gtt-service/rest/secure/angelbroking/gtt/v1/createRule", + "api.gtt.modify":"/gtt-service/rest/secure/angelbroking/gtt/v1/modifyRule", + "api.gtt.cancel":"/gtt-service/rest/secure/angelbroking/gtt/v1/cancelRule", + "api.gtt.details":"/rest/secure/angelbroking/gtt/v1/ruleDetails", + "api.gtt.list":"/rest/secure/angelbroking/gtt/v1/ruleList" } - def __init__(self, api_key=None, access_token=None, refresh_token=None,feed_token=None, userId=None, root=None, debug=False, timeout=None, proxies=None, pool=None, disable_ssl=False): + + try: + clientPublicIp= get('https://api.ipify.org').text + hostname = socket.gethostname() + clientLocalIp=socket.gethostbyname(hostname) + except Exception as e: + print("Exception while retriving IP Address,using local host IP address",e) + finally: + clientPublicIp="106.193.147.98" + clientLocalIp="127.0.0.1" + clientMacAddress=':'.join(re.findall('..', '%012x' % uuid.getnode())) + accept = "application/json" + userType = "USER" + sourceID = "WEB" + + + def __init__(self, api_key=None, access_token=None, refresh_token=None,feed_token=None, userId=None, root=None, debug=False, timeout=None, proxies=None, pool=None, disable_ssl=False,accept=None,userType=None,sourceID=None,Authorization=None,clientPublicIP=None,clientMacAddress=None,clientLocalIP=None,privateKey=None): self.debug = debug self.api_key = api_key self.session_expiry_hook = None @@ -96,6 +120,14 @@ def __init__(self, api_key=None, access_token=None, refresh_token=None,feed_toke self.proxies = proxies if proxies else {} self.root = root or self._rootUrl self.timeout = timeout or self._default_timeout + self.Authorization= None + self.clientLocalIP=self.clientLocalIp + self.clientPublicIP=self.clientPublicIp + self.clientMacAddress=self.clientMacAddress + self.privateKey=api_key + self.accept=self.accept + self.userType=self.userType + self.sourceID=self.sourceID if pool: self.reqsession = requests.Session() @@ -107,6 +139,17 @@ def __init__(self, api_key=None, access_token=None, refresh_token=None,feed_toke # disable requests SSL warning requests.packages.urllib3.disable_warnings() + def requestHeaders(self): + return{ + "Content-type":self.accept, + "X-ClientLocalIP": self.clientLocalIp, + "X-ClientPublicIP": self.clientPublicIp, + "X-MACAddress": self.clientMacAddress, + "Accept": self.accept, + "X-PrivateKey": self.privateKey, + "X-UserType": self.userType, + "X-SourceID": self.sourceID + } def setSessionExpiryHook(self, method): if not callable(method): @@ -145,30 +188,11 @@ def _request(self, route, method, parameters=None): uri =self._routes[route].format(**params) url = urljoin(self.root, uri) - hostname = socket.gethostname() - clientLocalIP=socket.gethostbyname(hostname) - clientPublicIP=get('https://api.ipify.org').text - macAddress = ':'.join(re.findall('..', '%012x' % uuid.getnode())) - privateKey = self.api_key - accept = "application/json" - userType = "USER" - sourceID = "WEB" + # Custom headers - headers = { - #"X-SmartApi-Version": "", - #"User-Agent": self._user_agent() - "Content-type":accept, - "X-ClientLocalIP": clientLocalIP, - "X-ClientPublicIP": clientPublicIP, - "X-MACAddress": macAddress, - "Accept": accept, - "X-PrivateKey": privateKey, - "X-UserType": userType, - "X-SourceID": sourceID - } + headers = self.requestHeaders() - #if self.api_key and self.access_token: if self.access_token: # set authorization header @@ -188,7 +212,7 @@ def _request(self, route, method, parameters=None): allow_redirects=True, timeout=self.timeout, proxies=self.proxies) - #print("The Response Content",r.content) + except Exception as e: raise e @@ -239,8 +263,8 @@ def generateSession(self,clientCode,password): params={"clientcode":clientCode,"password":password} loginResultObject=self._postRequest("api.login",params) - - if loginResultObject['status']==True : + + if loginResultObject['status']==True: jwtToken=loginResultObject['data']['jwtToken'] self.setAccessToken(jwtToken) refreshToken=loginResultObject['data']['refreshToken'] @@ -255,11 +279,10 @@ def generateSession(self,clientCode,password): user['data']['jwtToken']="Bearer "+jwtToken user['data']['refreshToken']=refreshToken - #print("USER",user) + return user else: - return - + return loginResultObject def terminateSession(self,clientCode): logoutResponseObject=self._postRequest("api.logout",{"clientcode":clientCode}) return logoutResponseObject @@ -274,14 +297,10 @@ def generateToken(self,refresh_token): return response def renewAccessToken(self): - - # h = hashlib.sha256(self.api_key.encode("utf-8") + refresh_token.encode("utf-8") + access_token.encode("utf-8")) - # checksum = h.hexdigest() - response =self._postRequest('api.refresh', { "jwtToken": self.access_token, "refreshToken": self.refresh_token, - #"checksum": checksum + }) tokenSet={} @@ -295,11 +314,10 @@ def renewAccessToken(self): def getProfile(self,refreshToken): user=self._getRequest("api.user.profile",{"refreshToken":refreshToken}) - #print("USER PROFILE",user) return user def placeOrder(self,orderparams): - #params = {"exchange":orderparams.exchange,"symbolToken":orderparams.symboltoken,"transactionType":orderparams.transactionType,"quantity":orderparams.quantity,"price":orderparams.price,"productType":orderparams.producttype,"orderType":orderparams.ordertype,"duration":orderparams.duration,"variety":orderparams.variety,"tradingSymbol":orderparams.tradingsymbol,"triggerPrice":orderparams.trigger_price,"squareoff":orderparams.squareoff,"stoploss":orderparams.stoploss,"trailingStoploss":orderparams.trailing_stoploss,"tag":orderparams.tag} + params=orderparams for k in list(params.keys()): @@ -307,7 +325,7 @@ def placeOrder(self,orderparams): del(params[k]) orderResponse= self._postRequest("api.order.place", params)['data']['orderid'] - + return orderResponse def modifyOrder(self,orderparams): @@ -318,8 +336,6 @@ def modifyOrder(self,orderparams): del(params[k]) orderResponse= self._postRequest("api.order.modify", params) - #order=Order(orderResponse) - #order['orderId']=orderResponse['data']['orderid'] return orderResponse def cancelOrder(self, order_id,variety): @@ -365,6 +381,57 @@ def convertPosition(self,positionParams): return convertPositionResponse + def gttCreateRule(self,createRuleParams): + params=createRuleParams + for k in list(params.keys()): + if params[k] is None: + del(params[k]) + + createGttRuleResponse=self._postRequest("api.gtt.create",params) + print(createGttRuleResponse) + return createGttRuleResponse['data']['id'] + + def gttModifyRule(self,modifyRuleParams): + params=modifyRuleParams + for k in list(params.keys()): + if params[k] is None: + del(params[k]) + modifyGttRuleResponse=self._postRequest("api.gtt.modify",params) + print(modifyGttRuleResponse) + return modifyGttRuleResponse['data']['id'] + + def gttCancelRule(self,gttCancelParams): + params=gttCancelParams + for k in list(params.keys()): + if params[k] is None: + del(params[k]) + + print(params) + cancelGttRuleResponse=self._postRequest("api.gtt.cancel",params) + print(cancelGttRuleResponse) + return cancelGttRuleResponse + + def gttDetails(self,id): + params={ + "id":id + } + gttDetailsResponse=self._postRequest("api.gtt.details",params) + return gttDetailsResponse + + def gttLists(self,status,page,count): + if type(status)== list: + params={ + "status":status, + "page":page, + "count":count + } + gttListResponse=self._postRequest("api.gtt.list",params) + print(gttListResponse) + return gttListResponse + else: + message="The status param is entered as" +str(type(status))+". Please enter status param as a list i.e., status=['CANCELLED']" + return message + def _user_agent(self): return (__title__ + "-python/").capitalize() + __version__ diff --git a/SmartApi/version.py b/SmartApi/version.py index b44ac8e..817b16a 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.1.1" +__version__ = "1.2.0" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/SmartApi/webSocket.py b/SmartApi/webSocket.py index adc9aff..7d93035 100644 --- a/SmartApi/webSocket.py +++ b/SmartApi/webSocket.py @@ -11,12 +11,21 @@ from datetime import datetime from twisted.internet import reactor, ssl from twisted.python import log as twisted_log +from twisted.internet.protocol import ReconnectingClientFactory from autobahn.twisted.websocket import WebSocketClientProtocol, \ WebSocketClientFactory, connectWS log = logging.getLogger(__name__) class SmartSocketClientProtocol(WebSocketClientProtocol): + PING_INTERVAL = 2.5 + KEEPALIVE_INTERVAL = 5 + + _ping_message = "" + _next_ping = None + _next_pong_check = None + _last_pong_time = None + _last_ping_time = None def __init__(self, *args, **kwargs): super(SmartSocketClientProtocol,self).__init__(*args,**kwargs) @@ -29,6 +38,11 @@ def onConnect(self, response): # noqa self.factory.on_connect(self, response) def onOpen(self): + # send ping + self._loop_ping() + # init last pong check after X seconds + self._loop_pong_check() + if self.factory.on_open: self.factory.on_open(self) @@ -48,9 +62,70 @@ def onClose(self, was_clean, code, reason): # noqa if self.factory.on_close: self.factory.on_close(self, code, reason) - -class SmartSocketClientFactory(WebSocketClientFactory): + + # Cancel next ping and timer + self._last_ping_time = None + self._last_pong_time = None + + if self._next_ping: + self._next_ping.cancel() + + if self._next_pong_check: + self._next_pong_check.cancel() + + def onPong(self, response): # noqa + """Called when pong message is received.""" + if self._last_pong_time and self.factory.debug: + log.debug("last pong was {} seconds back.".format(time.time() - self._last_pong_time)) + + self._last_pong_time = time.time() + + if self.factory.debug: + log.debug("pong => {}".format(response)) + + """ + Custom helper and exposed methods. + """ + def _loop_ping(self): # noqa + """Start a ping loop where it sends ping message every X seconds.""" + if self.factory.debug: + log.debug("ping => {}".format(self._ping_message)) + if self._last_ping_time: + log.debug("last ping was {} seconds back.".format(time.time() - self._last_ping_time)) + + # Set current time as last ping time + self._last_ping_time = time.time() + # Send a ping message to server + self.sendPing(self._ping_message) + + # Call self after X seconds + self._next_ping = self.factory.reactor.callLater(self.PING_INTERVAL, self._loop_ping) + + def _loop_pong_check(self): + """ + Timer sortof to check if connection is still there. + Checks last pong message time and disconnects the existing connection to make sure it doesn't become a ghost connection. + """ + if self._last_pong_time: + # No pong message since long time, so init reconnect + last_pong_diff = time.time() - self._last_pong_time + if last_pong_diff > (2 * self.PING_INTERVAL): + if self.factory.debug: + log.debug("Last pong was {} seconds ago. So dropping connection to reconnect.".format( + last_pong_diff)) + # drop existing connection to avoid ghost connection + self.dropConnection(abort=True) + + # Call self after X seconds + self._next_pong_check = self.factory.reactor.callLater(self.PING_INTERVAL, self._loop_pong_check) + +class SmartSocketClientFactory(WebSocketClientFactory,ReconnectingClientFactory): protocol = SmartSocketClientProtocol + + maxDelay = 5 + maxRetries = 10 + + _last_connection_time = None def __init__(self, *args, **kwargs): """Initialize with default callback method values.""" @@ -61,10 +136,52 @@ def __init__(self, *args, **kwargs): self.on_close = None self.on_message = None self.on_connect = None + self.on_reconnect = None + self.on_noreconnect = None super(SmartSocketClientFactory, self).__init__(*args, **kwargs) + def startedConnecting(self, connector): # noqa + """On connecting start or reconnection.""" + if not self._last_connection_time and self.debug: + log.debug("Start WebSocket connection.") + + self._last_connection_time = time.time() + + def clientConnectionFailed(self, connector, reason): # noqa + """On connection failure (When connect request fails)""" + if self.retries > 0: + log.error("Retrying connection. Retry attempt count: {}. Next retry in around: {} seconds".format(self.retries, int(round(self.delay)))) + + # on reconnect callback + if self.on_reconnect: + self.on_reconnect(self.retries) + + # Retry the connection + self.retry(connector) + self.send_noreconnect() + + def clientConnectionLost(self, connector, reason): # noqa + """On connection lost (When ongoing connection got disconnected).""" + if self.retries > 0: + # on reconnect callback + if self.on_reconnect: + self.on_reconnect(self.retries) + + # Retry the connection + self.retry(connector) + self.send_noreconnect() + + def send_noreconnect(self): + """Callback `no_reconnect` if max retries are exhausted.""" + if self.maxRetries is not None and (self.retries > self.maxRetries): + if self.debug: + log.debug("Maximum retries ({}) exhausted.".format(self.maxRetries)) + + if self.on_noreconnect: + self.on_noreconnect() + class WebSocket(object): EXCHANGE_MAP = { @@ -78,15 +195,50 @@ class WebSocket(object): "mcxsx": 8, "indices": 9 } + + # Default connection timeout + CONNECT_TIMEOUT = 30 + # Default Reconnect max delay. + RECONNECT_MAX_DELAY = 60 + # Default reconnect attempts + RECONNECT_MAX_TRIES = 50 + ROOT_URI='wss://omnefeeds.angelbroking.com/NestHtml5Mobile/socket/stream' + + # Flag to set if its first connect + _is_first_connect = True + + # Minimum delay which should be set between retries. User can't set less than this + _minimum_reconnect_max_delay = 5 + # Maximum number or retries user can set + _maximum_reconnect_max_tries = 300 feed_token=None client_code=None - def __init__(self, FEED_TOKEN, CLIENT_CODE, debug=False, root=None): + def __init__(self, FEED_TOKEN, CLIENT_CODE,task,debug=False, root=None,reconnect=True, reconnect_max_tries=RECONNECT_MAX_TRIES, reconnect_max_delay=RECONNECT_MAX_DELAY,connect_timeout=CONNECT_TIMEOUT): + + self.root = root or self.ROOT_URI self.feed_token= FEED_TOKEN self.client_code= CLIENT_CODE + self.task=task - + # Set max reconnect tries + if reconnect_max_tries > self._maximum_reconnect_max_tries: + log.warning("`reconnect_max_tries` can not be more than {val}. Setting to highest possible value - {val}.".format( + val=self._maximum_reconnect_max_tries)) + self.reconnect_max_tries = self._maximum_reconnect_max_tries + else: + self.reconnect_max_tries = reconnect_max_tries + + # Set max reconnect delay + if reconnect_max_delay < self._minimum_reconnect_max_delay: + log.warning("`reconnect_max_delay` can not be less than {val}. Setting to lowest possible value - {val}.".format( + val=self._minimum_reconnect_max_delay)) + self.reconnect_max_delay = self._minimum_reconnect_max_delay + else: + self.reconnect_max_delay = reconnect_max_delay + + self.connect_timeout = connect_timeout # Debug enables logs self.debug = debug @@ -97,6 +249,8 @@ def __init__(self, FEED_TOKEN, CLIENT_CODE, debug=False, root=None): self.on_error = None self.on_connect = None self.on_message = None + self.on_reconnect = None + self.on_noreconnect = None def _create_connection(self, url, **kwargs): """Create a WebSocket client connection.""" @@ -113,6 +267,12 @@ def _create_connection(self, url, **kwargs): self.factory.on_close = self._on_close self.factory.on_message = self._on_message self.factory.on_connect = self._on_connect + self.factory.on_reconnect = self._on_reconnect + self.factory.on_noreconnect = self._on_noreconnect + + + self.factory.maxDelay = self.reconnect_max_delay + self.factory.maxRetries = self.reconnect_max_tries def connect(self, threaded=False, disable_ssl_verification=False, proxy=None): @@ -155,35 +315,45 @@ def _close(self, code=None, reason=None): def close(self, code=None, reason=None): """Close the WebSocket connection.""" + self.stop_retry() self._close(code, reason) def stop(self): """Stop the event loop. Should be used if main thread has to be closed in `on_close` method.""" #print("stop") + reactor.stop() + def stop_retry(self): + """Stop auto retry when it is in progress.""" + if self.factory: + self.factory.stopTrying() + def send_request(self,token): - strwatchlistscrips = token #dynamic call - - try: - #print("Inside") - request={"task":"cn","channel":"","token":self.feed_token,"user":self.client_code,"acctid":self.client_code} - self.ws.sendMessage( - six.b(json.dumps(request)) - ) - #print(request) - request={"task":"mw","channel":strwatchlistscrips,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} + if self.task in ("mw","sfi","dp"): + strwatchlistscrips = token #dynamic call - self.ws.sendMessage( - six.b(json.dumps(request)) - ) - threading.Thread(target=self.heartBeat,daemon=True).start() - #print(request) - return True - except Exception as e: - self._close(reason="Error while request sending: {}".format(str(e))) - raise - + try: + #print("Inside") + request={"task":"cn","channel":"","token":self.feed_token,"user":self.client_code,"acctid":self.client_code} + self.ws.sendMessage( + six.b(json.dumps(request)) + ) + #print(request) + request={"task":self.task,"channel":strwatchlistscrips,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} + + self.ws.sendMessage( + six.b(json.dumps(request)) + ) + threading.Thread(target=self.heartBeat,daemon=True).start() + #print(request) + return True + except Exception as e: + self._close(reason="Error while request sending: {}".format(str(e))) + raise + else: + print("The task entered is invalid, Please enter correct task(mw,sfi,dp) ") + def _on_connect(self, ws, response): self.ws = ws if self.on_connect: @@ -217,9 +387,23 @@ def _on_message(self, ws, payload, is_binary): self._parse_text_message(payload) def _on_open(self, ws): + + if not self._is_first_connect: + self.connect() + + self._is_first_connect = False + if self.on_open: return self.on_open(self) + def _on_reconnect(self, attempts_count): + if self.on_reconnect: + return self.on_reconnect(self, attempts_count) + + def _on_noreconnect(self): + if self.on_noreconnect: + return self.on_noreconnect(self) + def heartBeat(self): while True: try: @@ -318,5 +502,4 @@ def _split_packets(self, bin): j = j + 2 + packet_length return packets - - + \ No newline at end of file diff --git a/setup.py b/setup.py index 98431f7..827dd5a 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.1.1", + version="1.2.0", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", diff --git a/test/test.py b/test/test.py index 6e84202..3d9b596 100644 --- a/test/test.py +++ b/test/test.py @@ -76,6 +76,43 @@ } smartApi.convertPosition(params) +gttCreateParams={ + "tradingsymbol" : "SBIN-EQ", + "symboltoken" : "3045", + "exchange" : "NSE", + "producttype" : "MARGIN", + "transactiontype" : "BUY", + "price" : 100000, + "qty" : 10, + "disclosedqty": 10, + "triggerprice" : 200000, + "timeperiod" : 365 + } +rule_id=smartApi.gttCreateRule(gttCreateParams) + +gttModifyParams={ + "id": rule_id, + "symboltoken":"3045", + "exchange":"NSE", + "price":19500, + "quantity":10, + "triggerprice":200000, + "disclosedqty":10, + "timeperiod":365 + } +modified_id=smartApi.gttModifyRule(gttModifyParams) + +cancelParams={ + "id": rule_id, + "symboltoken":"3045", + "exchange":"NSE" + } + +cancelled_id=smartApi.gttCancelRule(cancelParams) + +smartApi.gttDetails(rule_id) + +smartApi.gttLists('List of status',,) smartApi.terminateSession('Your Client Id') From c361cd8fd8804bc92b1372c9c809dcb3eb0eacaf Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 8 Mar 2021 11:08:44 +0530 Subject: [PATCH 28/33] Condition added for Public Ip Header --- SmartApi/smartConnect.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SmartApi/smartConnect.py b/SmartApi/smartConnect.py index cc1db99..40fbf3e 100644 --- a/SmartApi/smartConnect.py +++ b/SmartApi/smartConnect.py @@ -94,7 +94,9 @@ class SmartConnect(object): try: - clientPublicIp= get('https://api.ipify.org').text + clientPublicIp= " " + get('https://api.ipify.org').text + if " " in clientPublicIp: + clientPublicIp=clientPublicIp.replace(" ","") hostname = socket.gethostname() clientLocalIp=socket.gethostbyname(hostname) except Exception as e: From 61e89172ccf1ea73d5c0d2fdb803a10c2c7b23b4 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 8 Mar 2021 11:18:14 +0530 Subject: [PATCH 29/33] Changes in Websocket.py as per main branch --- SmartApi/webSocket.py | 235 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 209 insertions(+), 26 deletions(-) diff --git a/SmartApi/webSocket.py b/SmartApi/webSocket.py index adc9aff..7d93035 100644 --- a/SmartApi/webSocket.py +++ b/SmartApi/webSocket.py @@ -11,12 +11,21 @@ from datetime import datetime from twisted.internet import reactor, ssl from twisted.python import log as twisted_log +from twisted.internet.protocol import ReconnectingClientFactory from autobahn.twisted.websocket import WebSocketClientProtocol, \ WebSocketClientFactory, connectWS log = logging.getLogger(__name__) class SmartSocketClientProtocol(WebSocketClientProtocol): + PING_INTERVAL = 2.5 + KEEPALIVE_INTERVAL = 5 + + _ping_message = "" + _next_ping = None + _next_pong_check = None + _last_pong_time = None + _last_ping_time = None def __init__(self, *args, **kwargs): super(SmartSocketClientProtocol,self).__init__(*args,**kwargs) @@ -29,6 +38,11 @@ def onConnect(self, response): # noqa self.factory.on_connect(self, response) def onOpen(self): + # send ping + self._loop_ping() + # init last pong check after X seconds + self._loop_pong_check() + if self.factory.on_open: self.factory.on_open(self) @@ -48,9 +62,70 @@ def onClose(self, was_clean, code, reason): # noqa if self.factory.on_close: self.factory.on_close(self, code, reason) - -class SmartSocketClientFactory(WebSocketClientFactory): + + # Cancel next ping and timer + self._last_ping_time = None + self._last_pong_time = None + + if self._next_ping: + self._next_ping.cancel() + + if self._next_pong_check: + self._next_pong_check.cancel() + + def onPong(self, response): # noqa + """Called when pong message is received.""" + if self._last_pong_time and self.factory.debug: + log.debug("last pong was {} seconds back.".format(time.time() - self._last_pong_time)) + + self._last_pong_time = time.time() + + if self.factory.debug: + log.debug("pong => {}".format(response)) + + """ + Custom helper and exposed methods. + """ + def _loop_ping(self): # noqa + """Start a ping loop where it sends ping message every X seconds.""" + if self.factory.debug: + log.debug("ping => {}".format(self._ping_message)) + if self._last_ping_time: + log.debug("last ping was {} seconds back.".format(time.time() - self._last_ping_time)) + + # Set current time as last ping time + self._last_ping_time = time.time() + # Send a ping message to server + self.sendPing(self._ping_message) + + # Call self after X seconds + self._next_ping = self.factory.reactor.callLater(self.PING_INTERVAL, self._loop_ping) + + def _loop_pong_check(self): + """ + Timer sortof to check if connection is still there. + Checks last pong message time and disconnects the existing connection to make sure it doesn't become a ghost connection. + """ + if self._last_pong_time: + # No pong message since long time, so init reconnect + last_pong_diff = time.time() - self._last_pong_time + if last_pong_diff > (2 * self.PING_INTERVAL): + if self.factory.debug: + log.debug("Last pong was {} seconds ago. So dropping connection to reconnect.".format( + last_pong_diff)) + # drop existing connection to avoid ghost connection + self.dropConnection(abort=True) + + # Call self after X seconds + self._next_pong_check = self.factory.reactor.callLater(self.PING_INTERVAL, self._loop_pong_check) + +class SmartSocketClientFactory(WebSocketClientFactory,ReconnectingClientFactory): protocol = SmartSocketClientProtocol + + maxDelay = 5 + maxRetries = 10 + + _last_connection_time = None def __init__(self, *args, **kwargs): """Initialize with default callback method values.""" @@ -61,10 +136,52 @@ def __init__(self, *args, **kwargs): self.on_close = None self.on_message = None self.on_connect = None + self.on_reconnect = None + self.on_noreconnect = None super(SmartSocketClientFactory, self).__init__(*args, **kwargs) + def startedConnecting(self, connector): # noqa + """On connecting start or reconnection.""" + if not self._last_connection_time and self.debug: + log.debug("Start WebSocket connection.") + + self._last_connection_time = time.time() + + def clientConnectionFailed(self, connector, reason): # noqa + """On connection failure (When connect request fails)""" + if self.retries > 0: + log.error("Retrying connection. Retry attempt count: {}. Next retry in around: {} seconds".format(self.retries, int(round(self.delay)))) + + # on reconnect callback + if self.on_reconnect: + self.on_reconnect(self.retries) + + # Retry the connection + self.retry(connector) + self.send_noreconnect() + + def clientConnectionLost(self, connector, reason): # noqa + """On connection lost (When ongoing connection got disconnected).""" + if self.retries > 0: + # on reconnect callback + if self.on_reconnect: + self.on_reconnect(self.retries) + + # Retry the connection + self.retry(connector) + self.send_noreconnect() + + def send_noreconnect(self): + """Callback `no_reconnect` if max retries are exhausted.""" + if self.maxRetries is not None and (self.retries > self.maxRetries): + if self.debug: + log.debug("Maximum retries ({}) exhausted.".format(self.maxRetries)) + + if self.on_noreconnect: + self.on_noreconnect() + class WebSocket(object): EXCHANGE_MAP = { @@ -78,15 +195,50 @@ class WebSocket(object): "mcxsx": 8, "indices": 9 } + + # Default connection timeout + CONNECT_TIMEOUT = 30 + # Default Reconnect max delay. + RECONNECT_MAX_DELAY = 60 + # Default reconnect attempts + RECONNECT_MAX_TRIES = 50 + ROOT_URI='wss://omnefeeds.angelbroking.com/NestHtml5Mobile/socket/stream' + + # Flag to set if its first connect + _is_first_connect = True + + # Minimum delay which should be set between retries. User can't set less than this + _minimum_reconnect_max_delay = 5 + # Maximum number or retries user can set + _maximum_reconnect_max_tries = 300 feed_token=None client_code=None - def __init__(self, FEED_TOKEN, CLIENT_CODE, debug=False, root=None): + def __init__(self, FEED_TOKEN, CLIENT_CODE,task,debug=False, root=None,reconnect=True, reconnect_max_tries=RECONNECT_MAX_TRIES, reconnect_max_delay=RECONNECT_MAX_DELAY,connect_timeout=CONNECT_TIMEOUT): + + self.root = root or self.ROOT_URI self.feed_token= FEED_TOKEN self.client_code= CLIENT_CODE + self.task=task - + # Set max reconnect tries + if reconnect_max_tries > self._maximum_reconnect_max_tries: + log.warning("`reconnect_max_tries` can not be more than {val}. Setting to highest possible value - {val}.".format( + val=self._maximum_reconnect_max_tries)) + self.reconnect_max_tries = self._maximum_reconnect_max_tries + else: + self.reconnect_max_tries = reconnect_max_tries + + # Set max reconnect delay + if reconnect_max_delay < self._minimum_reconnect_max_delay: + log.warning("`reconnect_max_delay` can not be less than {val}. Setting to lowest possible value - {val}.".format( + val=self._minimum_reconnect_max_delay)) + self.reconnect_max_delay = self._minimum_reconnect_max_delay + else: + self.reconnect_max_delay = reconnect_max_delay + + self.connect_timeout = connect_timeout # Debug enables logs self.debug = debug @@ -97,6 +249,8 @@ def __init__(self, FEED_TOKEN, CLIENT_CODE, debug=False, root=None): self.on_error = None self.on_connect = None self.on_message = None + self.on_reconnect = None + self.on_noreconnect = None def _create_connection(self, url, **kwargs): """Create a WebSocket client connection.""" @@ -113,6 +267,12 @@ def _create_connection(self, url, **kwargs): self.factory.on_close = self._on_close self.factory.on_message = self._on_message self.factory.on_connect = self._on_connect + self.factory.on_reconnect = self._on_reconnect + self.factory.on_noreconnect = self._on_noreconnect + + + self.factory.maxDelay = self.reconnect_max_delay + self.factory.maxRetries = self.reconnect_max_tries def connect(self, threaded=False, disable_ssl_verification=False, proxy=None): @@ -155,35 +315,45 @@ def _close(self, code=None, reason=None): def close(self, code=None, reason=None): """Close the WebSocket connection.""" + self.stop_retry() self._close(code, reason) def stop(self): """Stop the event loop. Should be used if main thread has to be closed in `on_close` method.""" #print("stop") + reactor.stop() + def stop_retry(self): + """Stop auto retry when it is in progress.""" + if self.factory: + self.factory.stopTrying() + def send_request(self,token): - strwatchlistscrips = token #dynamic call - - try: - #print("Inside") - request={"task":"cn","channel":"","token":self.feed_token,"user":self.client_code,"acctid":self.client_code} - self.ws.sendMessage( - six.b(json.dumps(request)) - ) - #print(request) - request={"task":"mw","channel":strwatchlistscrips,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} + if self.task in ("mw","sfi","dp"): + strwatchlistscrips = token #dynamic call - self.ws.sendMessage( - six.b(json.dumps(request)) - ) - threading.Thread(target=self.heartBeat,daemon=True).start() - #print(request) - return True - except Exception as e: - self._close(reason="Error while request sending: {}".format(str(e))) - raise - + try: + #print("Inside") + request={"task":"cn","channel":"","token":self.feed_token,"user":self.client_code,"acctid":self.client_code} + self.ws.sendMessage( + six.b(json.dumps(request)) + ) + #print(request) + request={"task":self.task,"channel":strwatchlistscrips,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} + + self.ws.sendMessage( + six.b(json.dumps(request)) + ) + threading.Thread(target=self.heartBeat,daemon=True).start() + #print(request) + return True + except Exception as e: + self._close(reason="Error while request sending: {}".format(str(e))) + raise + else: + print("The task entered is invalid, Please enter correct task(mw,sfi,dp) ") + def _on_connect(self, ws, response): self.ws = ws if self.on_connect: @@ -217,9 +387,23 @@ def _on_message(self, ws, payload, is_binary): self._parse_text_message(payload) def _on_open(self, ws): + + if not self._is_first_connect: + self.connect() + + self._is_first_connect = False + if self.on_open: return self.on_open(self) + def _on_reconnect(self, attempts_count): + if self.on_reconnect: + return self.on_reconnect(self, attempts_count) + + def _on_noreconnect(self): + if self.on_noreconnect: + return self.on_noreconnect(self) + def heartBeat(self): while True: try: @@ -318,5 +502,4 @@ def _split_packets(self, bin): j = j + 2 + packet_length return packets - - + \ No newline at end of file From e885ea8d29dd367b5e5f6918d2d5e1f82241247a Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 8 Mar 2021 11:20:31 +0530 Subject: [PATCH 30/33] Changes in smartConnect.py as per main branch --- SmartApi/smartConnect.py | 149 ++++++++++++++++++++++++++++----------- 1 file changed, 109 insertions(+), 40 deletions(-) diff --git a/SmartApi/smartConnect.py b/SmartApi/smartConnect.py index 52ee1af..40fbf3e 100644 --- a/SmartApi/smartConnect.py +++ b/SmartApi/smartConnect.py @@ -11,10 +11,12 @@ from requests import get import re, uuid import socket - +import platform from smartapi.version import __version__, __title__ log = logging.getLogger(__name__) +#user_sys=platform.system() +#print("the system",user_sys) class SmartConnect(object): #_rootUrl = "https://openapisuat.angelbroking.com" @@ -81,10 +83,34 @@ class SmartConnect(object): "api.rms.limit": "/rest/secure/angelbroking/user/v1/getRMS", "api.holding": "/rest/secure/angelbroking/portfolio/v1/getHolding", "api.position": "/rest/secure/angelbroking/order/v1/getPosition", - "api.convert.position": "/rest/secure/angelbroking/order/v1/convertPosition" + "api.convert.position": "/rest/secure/angelbroking/order/v1/convertPosition", + + "api.gtt.create":"/gtt-service/rest/secure/angelbroking/gtt/v1/createRule", + "api.gtt.modify":"/gtt-service/rest/secure/angelbroking/gtt/v1/modifyRule", + "api.gtt.cancel":"/gtt-service/rest/secure/angelbroking/gtt/v1/cancelRule", + "api.gtt.details":"/rest/secure/angelbroking/gtt/v1/ruleDetails", + "api.gtt.list":"/rest/secure/angelbroking/gtt/v1/ruleList" } - def __init__(self, api_key=None, access_token=None, refresh_token=None,feed_token=None, userId=None, root=None, debug=False, timeout=None, proxies=None, pool=None, disable_ssl=False): + + try: + clientPublicIp= " " + get('https://api.ipify.org').text + if " " in clientPublicIp: + clientPublicIp=clientPublicIp.replace(" ","") + hostname = socket.gethostname() + clientLocalIp=socket.gethostbyname(hostname) + except Exception as e: + print("Exception while retriving IP Address,using local host IP address",e) + finally: + clientPublicIp="106.193.147.98" + clientLocalIp="127.0.0.1" + clientMacAddress=':'.join(re.findall('..', '%012x' % uuid.getnode())) + accept = "application/json" + userType = "USER" + sourceID = "WEB" + + + def __init__(self, api_key=None, access_token=None, refresh_token=None,feed_token=None, userId=None, root=None, debug=False, timeout=None, proxies=None, pool=None, disable_ssl=False,accept=None,userType=None,sourceID=None,Authorization=None,clientPublicIP=None,clientMacAddress=None,clientLocalIP=None,privateKey=None): self.debug = debug self.api_key = api_key self.session_expiry_hook = None @@ -96,6 +122,14 @@ def __init__(self, api_key=None, access_token=None, refresh_token=None,feed_toke self.proxies = proxies if proxies else {} self.root = root or self._rootUrl self.timeout = timeout or self._default_timeout + self.Authorization= None + self.clientLocalIP=self.clientLocalIp + self.clientPublicIP=self.clientPublicIp + self.clientMacAddress=self.clientMacAddress + self.privateKey=api_key + self.accept=self.accept + self.userType=self.userType + self.sourceID=self.sourceID if pool: self.reqsession = requests.Session() @@ -107,6 +141,17 @@ def __init__(self, api_key=None, access_token=None, refresh_token=None,feed_toke # disable requests SSL warning requests.packages.urllib3.disable_warnings() + def requestHeaders(self): + return{ + "Content-type":self.accept, + "X-ClientLocalIP": self.clientLocalIp, + "X-ClientPublicIP": self.clientPublicIp, + "X-MACAddress": self.clientMacAddress, + "Accept": self.accept, + "X-PrivateKey": self.privateKey, + "X-UserType": self.userType, + "X-SourceID": self.sourceID + } def setSessionExpiryHook(self, method): if not callable(method): @@ -145,30 +190,11 @@ def _request(self, route, method, parameters=None): uri =self._routes[route].format(**params) url = urljoin(self.root, uri) - hostname = socket.gethostname() - clientLocalIP=socket.gethostbyname(hostname) - clientPublicIP=get('https://api.ipify.org').text - macAddress = ':'.join(re.findall('..', '%012x' % uuid.getnode())) - privateKey = self.api_key - accept = "application/json" - userType = "USER" - sourceID = "WEB" + # Custom headers - headers = { - #"X-SmartApi-Version": "", - #"User-Agent": self._user_agent() - "Content-type":accept, - "X-ClientLocalIP": clientLocalIP, - "X-ClientPublicIP": clientPublicIP, - "X-MACAddress": macAddress, - "Accept": accept, - "X-PrivateKey": privateKey, - "X-UserType": userType, - "X-SourceID": sourceID - } + headers = self.requestHeaders() - #if self.api_key and self.access_token: if self.access_token: # set authorization header @@ -188,7 +214,7 @@ def _request(self, route, method, parameters=None): allow_redirects=True, timeout=self.timeout, proxies=self.proxies) - #print("The Response Content",r.content) + except Exception as e: raise e @@ -239,8 +265,8 @@ def generateSession(self,clientCode,password): params={"clientcode":clientCode,"password":password} loginResultObject=self._postRequest("api.login",params) - - if loginResultObject['status']==True : + + if loginResultObject['status']==True: jwtToken=loginResultObject['data']['jwtToken'] self.setAccessToken(jwtToken) refreshToken=loginResultObject['data']['refreshToken'] @@ -255,11 +281,10 @@ def generateSession(self,clientCode,password): user['data']['jwtToken']="Bearer "+jwtToken user['data']['refreshToken']=refreshToken - #print("USER",user) + return user else: - return - + return loginResultObject def terminateSession(self,clientCode): logoutResponseObject=self._postRequest("api.logout",{"clientcode":clientCode}) return logoutResponseObject @@ -274,14 +299,10 @@ def generateToken(self,refresh_token): return response def renewAccessToken(self): - - # h = hashlib.sha256(self.api_key.encode("utf-8") + refresh_token.encode("utf-8") + access_token.encode("utf-8")) - # checksum = h.hexdigest() - response =self._postRequest('api.refresh', { "jwtToken": self.access_token, "refreshToken": self.refresh_token, - #"checksum": checksum + }) tokenSet={} @@ -295,11 +316,10 @@ def renewAccessToken(self): def getProfile(self,refreshToken): user=self._getRequest("api.user.profile",{"refreshToken":refreshToken}) - #print("USER PROFILE",user) return user def placeOrder(self,orderparams): - #params = {"exchange":orderparams.exchange,"symbolToken":orderparams.symboltoken,"transactionType":orderparams.transactionType,"quantity":orderparams.quantity,"price":orderparams.price,"productType":orderparams.producttype,"orderType":orderparams.ordertype,"duration":orderparams.duration,"variety":orderparams.variety,"tradingSymbol":orderparams.tradingsymbol,"triggerPrice":orderparams.trigger_price,"squareoff":orderparams.squareoff,"stoploss":orderparams.stoploss,"trailingStoploss":orderparams.trailing_stoploss,"tag":orderparams.tag} + params=orderparams for k in list(params.keys()): @@ -307,7 +327,7 @@ def placeOrder(self,orderparams): del(params[k]) orderResponse= self._postRequest("api.order.place", params)['data']['orderid'] - + return orderResponse def modifyOrder(self,orderparams): @@ -318,8 +338,6 @@ def modifyOrder(self,orderparams): del(params[k]) orderResponse= self._postRequest("api.order.modify", params) - #order=Order(orderResponse) - #order['orderId']=orderResponse['data']['orderid'] return orderResponse def cancelOrder(self, order_id,variety): @@ -365,6 +383,57 @@ def convertPosition(self,positionParams): return convertPositionResponse + def gttCreateRule(self,createRuleParams): + params=createRuleParams + for k in list(params.keys()): + if params[k] is None: + del(params[k]) + + createGttRuleResponse=self._postRequest("api.gtt.create",params) + print(createGttRuleResponse) + return createGttRuleResponse['data']['id'] + + def gttModifyRule(self,modifyRuleParams): + params=modifyRuleParams + for k in list(params.keys()): + if params[k] is None: + del(params[k]) + modifyGttRuleResponse=self._postRequest("api.gtt.modify",params) + print(modifyGttRuleResponse) + return modifyGttRuleResponse['data']['id'] + + def gttCancelRule(self,gttCancelParams): + params=gttCancelParams + for k in list(params.keys()): + if params[k] is None: + del(params[k]) + + print(params) + cancelGttRuleResponse=self._postRequest("api.gtt.cancel",params) + print(cancelGttRuleResponse) + return cancelGttRuleResponse + + def gttDetails(self,id): + params={ + "id":id + } + gttDetailsResponse=self._postRequest("api.gtt.details",params) + return gttDetailsResponse + + def gttLists(self,status,page,count): + if type(status)== list: + params={ + "status":status, + "page":page, + "count":count + } + gttListResponse=self._postRequest("api.gtt.list",params) + print(gttListResponse) + return gttListResponse + else: + message="The status param is entered as" +str(type(status))+". Please enter status param as a list i.e., status=['CANCELLED']" + return message + def _user_agent(self): return (__title__ + "-python/").capitalize() + __version__ From 28ee960c866635eaab2b6c1dabd61b04cc991bc5 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 8 Mar 2021 15:47:13 +0530 Subject: [PATCH 31/33] Changes in websocket-sendRequest(token,task) --- README.md | 4 ++-- SmartApi/version.py | 2 +- SmartApi/webSocket.py | 10 +++++----- setup.py | 2 +- test/test.py | 3 ++- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 290eb1c..c5111e1 100644 --- a/README.md +++ b/README.md @@ -91,14 +91,14 @@ from smartapi import WebSocket FEED_TOKEN= "your feed token" CLIENT_CODE="your client Id" token="channel you want the information of" #"nse_cm|2885&nse_cm|1594&nse_cm|11536" - +task="task" #'mw'|'sfi'|'dp' ss = WebSocket(FEED_TOKEN, CLIENT_CODE) def on_tick(ws, tick): print("Ticks: {}".format(tick)) def on_connect(ws, response): - ws.send_request(token) + ws.send_request(token,task) def on_close(ws, code, reason): ws.stop() diff --git a/SmartApi/version.py b/SmartApi/version.py index 817b16a..457ec5c 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.2.0" +__version__ = "1.2.2" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/SmartApi/webSocket.py b/SmartApi/webSocket.py index 7d93035..18778ec 100644 --- a/SmartApi/webSocket.py +++ b/SmartApi/webSocket.py @@ -214,13 +214,13 @@ class WebSocket(object): _maximum_reconnect_max_tries = 300 feed_token=None client_code=None - def __init__(self, FEED_TOKEN, CLIENT_CODE,task,debug=False, root=None,reconnect=True, reconnect_max_tries=RECONNECT_MAX_TRIES, reconnect_max_delay=RECONNECT_MAX_DELAY,connect_timeout=CONNECT_TIMEOUT): + def __init__(self, FEED_TOKEN, CLIENT_CODE,debug=False, root=None,reconnect=True,reconnect_max_tries=RECONNECT_MAX_TRIES, reconnect_max_delay=RECONNECT_MAX_DELAY,connect_timeout=CONNECT_TIMEOUT): self.root = root or self.ROOT_URI self.feed_token= FEED_TOKEN self.client_code= CLIENT_CODE - self.task=task + # Set max reconnect tries if reconnect_max_tries > self._maximum_reconnect_max_tries: @@ -329,8 +329,8 @@ def stop_retry(self): if self.factory: self.factory.stopTrying() - def send_request(self,token): - if self.task in ("mw","sfi","dp"): + def send_request(self,token,task): + if task in ("mw","sfi","dp"): strwatchlistscrips = token #dynamic call try: @@ -340,7 +340,7 @@ def send_request(self,token): six.b(json.dumps(request)) ) #print(request) - request={"task":self.task,"channel":strwatchlistscrips,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} + request={"task":task,"channel":strwatchlistscrips,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} self.ws.sendMessage( six.b(json.dumps(request)) diff --git a/setup.py b/setup.py index 827dd5a..e6d0d5a 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.2.0", + version="1.2.2", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", diff --git a/test/test.py b/test/test.py index 3d9b596..2f6f8c1 100644 --- a/test/test.py +++ b/test/test.py @@ -122,12 +122,13 @@ FEED_TOKEN=feedToken CLIENT_CODE="Your Client Id" token=None +task=None ss = WebSocket(FEED_TOKEN, CLIENT_CODE) def on_tick(ws, tick): print("Ticks: {}".format(tick)) def on_connect(ws, response): - ws.send_request(token) + ws.send_request(token,task) def on_close(ws, code, reason): ws.stop() From 0fdd1b94bb9187c051fce5b7f53c8d8e070d0e42 Mon Sep 17 00:00:00 2001 From: abhijeetbote Date: Fri, 26 Mar 2021 11:14:21 +0530 Subject: [PATCH 32/33] Historic api added and Websocket Open Forum Issues Resolved --- README.md | 20 +++++- SmartApi/smartConnect.py | 65 +++++------------- SmartApi/version.py | 2 +- SmartApi/webSocket.py | 143 ++++++++++++--------------------------- setup.py | 2 +- 5 files changed, 79 insertions(+), 153 deletions(-) diff --git a/README.md b/README.md index 290eb1c..601923a 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,19 @@ try: lists=smartApi.gttLists(status,page,count) except Exception as e: print("GTT Rule List failed: {}".format(e.message)) + +#Historic api +try: + historicParam={ + "exchange": "NSE", + "symboltoken": "3045", + "interval": "MINUTE", + "fromdate": "2021-02-08 09:00", + "todate": "2021-02-08 09:16" + } + smartApi.getCandleData(historicParam) +except Exception as e: + print("Historic Api failed: {}".format(e.message)) #logout try: logout=obj.terminateSession('Your Client Id') @@ -91,15 +104,16 @@ from smartapi import WebSocket FEED_TOKEN= "your feed token" CLIENT_CODE="your client Id" token="channel you want the information of" #"nse_cm|2885&nse_cm|1594&nse_cm|11536" - +task="task" #"mw"|"sfi"|"dp" ss = WebSocket(FEED_TOKEN, CLIENT_CODE) def on_tick(ws, tick): print("Ticks: {}".format(tick)) def on_connect(ws, response): - ws.send_request(token) - + ws.websocket_connection() # Websocket connection + ws.send_request(token,task) + def on_close(ws, code, reason): ws.stop() diff --git a/SmartApi/smartConnect.py b/SmartApi/smartConnect.py index 40fbf3e..c8f65a8 100644 --- a/SmartApi/smartConnect.py +++ b/SmartApi/smartConnect.py @@ -24,47 +24,6 @@ class SmartConnect(object): #_login_url ="https://smartapi.angelbroking.com/login" _login_url="https://smartapi.angelbroking.com/publisher-login" #prod endpoint _default_timeout = 7 # In seconds - # Products - PRODUCT_MIS = "MIS" - - PRODUCT_CNC = "CNC" - PRODUCT_NRML = "NRML" - PRODUCT_CO = "CO" - PRODUCT_BO = "BO" - - # Order types - ORDER_TYPE_MARKET = "MARKET" - ORDER_TYPE_LIMIT = "LIMIT" - ORDER_TYPE_SLM = "SL-M" - ORDER_TYPE_SL = "SL" - - # Varities - VARIETY_REGULAR = "regular" - VARIETY_BO = "bo" - VARIETY_CO = "co" - VARIETY_AMO = "amo" - - # Transaction type - TRANSACTION_TYPE_BUY = "BUY" - TRANSACTION_TYPE_SELL = "SELL" - - # Validity - VALIDITY_DAY = "DAY" - VALIDITY_IOC = "IOC" - - # Exchanges - EXCHANGE_NSE = "NSE" - EXCHANGE_BSE = "BSE" - EXCHANGE_NFO = "NFO" - EXCHANGE_CDS = "CDS" - EXCHANGE_BFO = "BFO" - EXCHANGE_MCX = "MCX" - EXCHANGE_NCDEX="NCDEX" - - # Status constants - STATUS_COMPLETE = "COMPLETE" - STATUS_REJECTED = "REJECTED" - STATUS_CANCELLED = "CANCELLED" _routes = { "api.login":"/rest/auth/angelbroking/user/v1/loginByPassword", @@ -89,7 +48,9 @@ class SmartConnect(object): "api.gtt.modify":"/gtt-service/rest/secure/angelbroking/gtt/v1/modifyRule", "api.gtt.cancel":"/gtt-service/rest/secure/angelbroking/gtt/v1/cancelRule", "api.gtt.details":"/rest/secure/angelbroking/gtt/v1/ruleDetails", - "api.gtt.list":"/rest/secure/angelbroking/gtt/v1/ruleList" + "api.gtt.list":"/rest/secure/angelbroking/gtt/v1/ruleList", + + "api.candle.data":"/rest/secure/angelbroking/historical/v1/getCandleData" } @@ -159,7 +120,7 @@ def setSessionExpiryHook(self, method): self.session_expiry_hook = method def getUserId(): - return userId; + return userId def setUserId(self,id): self.userId=id @@ -390,7 +351,7 @@ def gttCreateRule(self,createRuleParams): del(params[k]) createGttRuleResponse=self._postRequest("api.gtt.create",params) - print(createGttRuleResponse) + #print(createGttRuleResponse) return createGttRuleResponse['data']['id'] def gttModifyRule(self,modifyRuleParams): @@ -399,7 +360,7 @@ def gttModifyRule(self,modifyRuleParams): if params[k] is None: del(params[k]) modifyGttRuleResponse=self._postRequest("api.gtt.modify",params) - print(modifyGttRuleResponse) + #print(modifyGttRuleResponse) return modifyGttRuleResponse['data']['id'] def gttCancelRule(self,gttCancelParams): @@ -408,9 +369,9 @@ def gttCancelRule(self,gttCancelParams): if params[k] is None: del(params[k]) - print(params) + #print(params) cancelGttRuleResponse=self._postRequest("api.gtt.cancel",params) - print(cancelGttRuleResponse) + #print(cancelGttRuleResponse) return cancelGttRuleResponse def gttDetails(self,id): @@ -428,12 +389,20 @@ def gttLists(self,status,page,count): "count":count } gttListResponse=self._postRequest("api.gtt.list",params) - print(gttListResponse) + #print(gttListResponse) return gttListResponse else: message="The status param is entered as" +str(type(status))+". Please enter status param as a list i.e., status=['CANCELLED']" return message + def getCandleData(self,historicDataParams): + params=historicDataParams + for k in list(params.keys()): + if params[k] is None: + del(params[k]) + getCandleDataResponse=self._postRequest("api.candle.data",historicDataParams) + return getCandleDataResponse + def _user_agent(self): return (__title__ + "-python/").capitalize() + __version__ diff --git a/SmartApi/version.py b/SmartApi/version.py index 817b16a..40c5528 100644 --- a/SmartApi/version.py +++ b/SmartApi/version.py @@ -2,7 +2,7 @@ __description__ = "Angel Broking openApi integration" __url__ = "https://www.angelbroking.com/" __download_url__ = "https://github.com/angelbroking-github/smartapi-python" -__version__ = "1.2.0" +__version__ = "1.2.3" __author__ = "ab-smartapi" __token__ = "ab-smartapi" __author_email__ = "smartapi.sdk@gmail.com" diff --git a/SmartApi/webSocket.py b/SmartApi/webSocket.py index 7d93035..2538d97 100644 --- a/SmartApi/webSocket.py +++ b/SmartApi/webSocket.py @@ -18,14 +18,6 @@ log = logging.getLogger(__name__) class SmartSocketClientProtocol(WebSocketClientProtocol): - PING_INTERVAL = 2.5 - KEEPALIVE_INTERVAL = 5 - - _ping_message = "" - _next_ping = None - _next_pong_check = None - _last_pong_time = None - _last_ping_time = None def __init__(self, *args, **kwargs): super(SmartSocketClientProtocol,self).__init__(*args,**kwargs) @@ -38,17 +30,13 @@ def onConnect(self, response): # noqa self.factory.on_connect(self, response) def onOpen(self): - # send ping - self._loop_ping() - # init last pong check after X seconds - self._loop_pong_check() - if self.factory.on_open: self.factory.on_open(self) + def onMessage(self, payload, is_binary): # noqa - #print("""Called when text or binary message is received.""",payload,is_binary) + """Called when text or binary message is received.""" if self.factory.on_message: self.factory.on_message(self, payload, is_binary) @@ -63,65 +51,9 @@ def onClose(self, was_clean, code, reason): # noqa self.factory.on_close(self, code, reason) - # Cancel next ping and timer - self._last_ping_time = None - self._last_pong_time = None - - if self._next_ping: - self._next_ping.cancel() - - if self._next_pong_check: - self._next_pong_check.cancel() - - def onPong(self, response): # noqa - """Called when pong message is received.""" - if self._last_pong_time and self.factory.debug: - log.debug("last pong was {} seconds back.".format(time.time() - self._last_pong_time)) - - self._last_pong_time = time.time() - - if self.factory.debug: - log.debug("pong => {}".format(response)) - - """ - Custom helper and exposed methods. - """ - def _loop_ping(self): # noqa - """Start a ping loop where it sends ping message every X seconds.""" - if self.factory.debug: - log.debug("ping => {}".format(self._ping_message)) - if self._last_ping_time: - log.debug("last ping was {} seconds back.".format(time.time() - self._last_ping_time)) - - # Set current time as last ping time - self._last_ping_time = time.time() - # Send a ping message to server - self.sendPing(self._ping_message) - - # Call self after X seconds - self._next_ping = self.factory.reactor.callLater(self.PING_INTERVAL, self._loop_ping) - - def _loop_pong_check(self): - """ - Timer sortof to check if connection is still there. - Checks last pong message time and disconnects the existing connection to make sure it doesn't become a ghost connection. - """ - if self._last_pong_time: - # No pong message since long time, so init reconnect - last_pong_diff = time.time() - self._last_pong_time - if last_pong_diff > (2 * self.PING_INTERVAL): - if self.factory.debug: - log.debug("Last pong was {} seconds ago. So dropping connection to reconnect.".format( - last_pong_diff)) - # drop existing connection to avoid ghost connection - self.dropConnection(abort=True) - - # Call self after X seconds - self._next_pong_check = self.factory.reactor.callLater(self.PING_INTERVAL, self._loop_pong_check) - class SmartSocketClientFactory(WebSocketClientFactory,ReconnectingClientFactory): protocol = SmartSocketClientProtocol - + maxDelay = 5 maxRetries = 10 @@ -152,7 +84,7 @@ def startedConnecting(self, connector): # noqa def clientConnectionFailed(self, connector, reason): # noqa """On connection failure (When connect request fails)""" if self.retries > 0: - log.error("Retrying connection. Retry attempt count: {}. Next retry in around: {} seconds".format(self.retries, int(round(self.delay)))) + print("Retrying connection. Retry attempt count: {}. Next retry in around: {} seconds".format(self.retries, int(round(self.delay)))) # on reconnect callback if self.on_reconnect: @@ -182,7 +114,6 @@ def send_noreconnect(self): if self.on_noreconnect: self.on_noreconnect() - class WebSocket(object): EXCHANGE_MAP = { "nse": 1, @@ -195,7 +126,6 @@ class WebSocket(object): "mcxsx": 8, "indices": 9 } - # Default connection timeout CONNECT_TIMEOUT = 30 # Default Reconnect max delay. @@ -212,16 +142,16 @@ class WebSocket(object): _minimum_reconnect_max_delay = 5 # Maximum number or retries user can set _maximum_reconnect_max_tries = 300 + feed_token=None client_code=None - def __init__(self, FEED_TOKEN, CLIENT_CODE,task,debug=False, root=None,reconnect=True, reconnect_max_tries=RECONNECT_MAX_TRIES, reconnect_max_delay=RECONNECT_MAX_DELAY,connect_timeout=CONNECT_TIMEOUT): + def __init__(self, FEED_TOKEN, CLIENT_CODE,debug=False, root=None,reconnect=True,reconnect_max_tries=RECONNECT_MAX_TRIES, reconnect_max_delay=RECONNECT_MAX_DELAY,connect_timeout=CONNECT_TIMEOUT): self.root = root or self.ROOT_URI self.feed_token= FEED_TOKEN self.client_code= CLIENT_CODE - self.task=task - + # Set max reconnect tries if reconnect_max_tries > self._maximum_reconnect_max_tries: log.warning("`reconnect_max_tries` can not be more than {val}. Setting to highest possible value - {val}.".format( @@ -238,7 +168,8 @@ def __init__(self, FEED_TOKEN, CLIENT_CODE,task,debug=False, root=None,reconnect else: self.reconnect_max_delay = reconnect_max_delay - self.connect_timeout = connect_timeout + self.connect_timeout = connect_timeout + # Debug enables logs self.debug = debug @@ -252,6 +183,7 @@ def __init__(self, FEED_TOKEN, CLIENT_CODE,task,debug=False, root=None,reconnect self.on_reconnect = None self.on_noreconnect = None + def _create_connection(self, url, **kwargs): """Create a WebSocket client connection.""" self.factory = SmartSocketClientFactory(url, **kwargs) @@ -274,7 +206,6 @@ def _create_connection(self, url, **kwargs): self.factory.maxDelay = self.reconnect_max_delay self.factory.maxRetries = self.reconnect_max_tries - def connect(self, threaded=False, disable_ssl_verification=False, proxy=None): #print("Connect") self._create_connection(self.ROOT_URI) @@ -301,6 +232,7 @@ def connect(self, threaded=False, disable_ssl_verification=False, proxy=None): else: reactor.run(**opts) + def is_connected(self): #print("Check if WebSocket connection is established.") if self.ws and self.ws.state == self.ws.STATE_OPEN: @@ -327,26 +259,38 @@ def stop(self): def stop_retry(self): """Stop auto retry when it is in progress.""" if self.factory: - self.factory.stopTrying() + self.factory.stopTrying() + + def _on_reconnect(self, attempts_count): + if self.on_reconnect: + return self.on_reconnect(self, attempts_count) - def send_request(self,token): - if self.task in ("mw","sfi","dp"): + def _on_noreconnect(self): + if self.on_noreconnect: + return self.on_noreconnect(self) + + def websocket_connection(self): + if self.client_code == None or self.feed_token == None: + return "client_code or feed_token or task is missing" + + request={"task":"cn","channel":"","token":self.feed_token,"user":self.client_code,"acctid":self.client_code} + self.ws.sendMessage( + six.b(json.dumps(request)) + ) + print(request) + + threading.Thread(target=self.heartBeat,daemon=True).start() + + def send_request(self,token,task): + if task in ("mw","sfi","dp"): strwatchlistscrips = token #dynamic call try: - #print("Inside") - request={"task":"cn","channel":"","token":self.feed_token,"user":self.client_code,"acctid":self.client_code} - self.ws.sendMessage( - six.b(json.dumps(request)) - ) - #print(request) - request={"task":self.task,"channel":strwatchlistscrips,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} + request={"task":task,"channel":strwatchlistscrips,"token":self.feed_token,"user":self.client_code,"acctid":self.client_code} self.ws.sendMessage( six.b(json.dumps(request)) ) - threading.Thread(target=self.heartBeat,daemon=True).start() - #print(request) return True except Exception as e: self._close(reason="Error while request sending: {}".format(str(e))) @@ -355,9 +299,13 @@ def send_request(self,token): print("The task entered is invalid, Please enter correct task(mw,sfi,dp) ") def _on_connect(self, ws, response): + #print("-----_on_connect-------") self.ws = ws if self.on_connect: + + print(self.on_connect) self.on_connect(self, response) + #self.websocket_connection def _on_close(self, ws, code, reason): """Call `on_close` callback when connection is closed.""" @@ -373,6 +321,8 @@ def _on_error(self, ws, code, reason): if self.on_error: self.on_error(self, code, reason) + + def _on_message(self, ws, payload, is_binary): """Call `on_message` callback when text message is received.""" if self.on_message: @@ -387,7 +337,6 @@ def _on_message(self, ws, payload, is_binary): self._parse_text_message(payload) def _on_open(self, ws): - if not self._is_first_connect: self.connect() @@ -396,13 +345,6 @@ def _on_open(self, ws): if self.on_open: return self.on_open(self) - def _on_reconnect(self, attempts_count): - if self.on_reconnect: - return self.on_reconnect(self, attempts_count) - - def _on_noreconnect(self): - if self.on_noreconnect: - return self.on_noreconnect(self) def heartBeat(self): while True: @@ -416,6 +358,7 @@ def heartBeat(self): print("HeartBeats Failed") time.sleep(60) + def _parse_text_message(self, payload): """Parse text message.""" # Decode unicode data @@ -434,7 +377,7 @@ def _parse_text_message(self, payload): self.on_ticks(self, data) def _parse_binary(self, bin): - #print("""Parse binary data to a (list of) ticks structure.""") + """Parse binary data to a (list of) ticks structure.""" packets = self._split_packets(bin) # split data to individual ticks packet data = [] diff --git a/setup.py b/setup.py index 827dd5a..c737358 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name="smartapi-python", - version="1.2.0", + version="1.2.3", author="ab-smartapi", author_email="smartapi.sdk@gmail.com", description="Angel Broking openApi integration", From 7f0db4f7323c140ef4e60d622535ef8e99376d42 Mon Sep 17 00:00:00 2001 From: Vrushali Kapse Date: Mon, 12 Apr 2021 10:18:30 +0530 Subject: [PATCH 33/33] new websocket code added --- SmartApi/smartWebsocket.py | 455 +++++++++++++++++++++++++++++++++++++ 1 file changed, 455 insertions(+) create mode 100644 SmartApi/smartWebsocket.py diff --git a/SmartApi/smartWebsocket.py b/SmartApi/smartWebsocket.py new file mode 100644 index 0000000..8894a80 --- /dev/null +++ b/SmartApi/smartWebsocket.py @@ -0,0 +1,455 @@ + +import six +import sys +import time +import json +import struct +import logging +import threading +import base64 +import zlib +from datetime import datetime +from twisted.internet import reactor, ssl +from twisted.python import log as twisted_log +from twisted.internet.protocol import ReconnectingClientFactory +from autobahn.twisted.websocket import WebSocketClientProtocol, \ + WebSocketClientFactory, connectWS + +log = logging.getLogger(__name__) + +class SmartSocketClientProtocol(WebSocketClientProtocol): + + def __init__(self, *args, **kwargs): + super(SmartSocketClientProtocol,self).__init__(*args,**kwargs) + + def onConnect(self, response): # noqa + """Called when WebSocket server connection was established""" + self.factory.ws = self + + if self.factory.on_connect: + self.factory.on_connect(self, response) + + def onOpen(self): + if self.factory.on_open: + self.factory.on_open(self) + + + + def onMessage(self, payload, is_binary): # noqa + """Called when text or binary message is received.""" + if self.factory.on_message: + self.factory.on_message(self, payload, is_binary) + + + def onClose(self, was_clean, code, reason): # noqa + """Called when connection is closed.""" + if not was_clean: + if self.factory.on_error: + self.factory.on_error(self, code, reason) + + if self.factory.on_close: + self.factory.on_close(self, code, reason) + + +class SmartSocketClientFactory(WebSocketClientFactory,ReconnectingClientFactory): + protocol = SmartSocketClientProtocol + + maxDelay = 5 + maxRetries = 10 + + _last_connection_time = None + + def __init__(self, *args, **kwargs): + """Initialize with default callback method values.""" + self.debug = False + self.ws = None + self.on_open = None + self.on_error = None + self.on_close = None + self.on_message = None + self.on_connect = None + self.on_reconnect = None + self.on_noreconnect = None + + + super(SmartSocketClientFactory, self).__init__(*args, **kwargs) + + def startedConnecting(self, connector): # noqa + """On connecting start or reconnection.""" + if not self._last_connection_time and self.debug: + log.debug("Start WebSocket connection.") + + self._last_connection_time = time.time() + + def clientConnectionFailed(self, connector, reason): # noqa + """On connection failure (When connect request fails)""" + if self.retries > 0: + print("Retrying connection. Retry attempt count: {}. Next retry in around: {} seconds".format(self.retries, int(round(self.delay)))) + + # on reconnect callback + if self.on_reconnect: + self.on_reconnect(self.retries) + + # Retry the connection + self.retry(connector) + self.send_noreconnect() + + def clientConnectionLost(self, connector, reason): # noqa + """On connection lost (When ongoing connection got disconnected).""" + if self.retries > 0: + # on reconnect callback + if self.on_reconnect: + self.on_reconnect(self.retries) + + # Retry the connection + self.retry(connector) + self.send_noreconnect() + + def send_noreconnect(self): + """Callback `no_reconnect` if max retries are exhausted.""" + if self.maxRetries is not None and (self.retries > self.maxRetries): + if self.debug: + log.debug("Maximum retries ({}) exhausted.".format(self.maxRetries)) + + if self.on_noreconnect: + self.on_noreconnect() + +class SimpleWebSocket(object): + EXCHANGE_MAP = { + "nse": 1, + "nfo": 2, + "cds": 3, + "bse": 4, + "bfo": 5, + "bsecds": 6, + "mcx": 7, + "mcxsx": 8, + "indices": 9 + } + # Default connection timeout + CONNECT_TIMEOUT = 30 + # Default Reconnect max delay. + RECONNECT_MAX_DELAY = 60 + # Default reconnect attempts + RECONNECT_MAX_TRIES = 50 + + # ROOT_URI='wss://omnefeeds.angelbroking.com/NestHtml5Mobile/socket/stream' + ROOT_URI='wss://smartapisocket.angelbroking.com/websocket' + + # Flag to set if its first connect + _is_first_connect = True + + # Minimum delay which should be set between retries. User can't set less than this + _minimum_reconnect_max_delay = 5 + # Maximum number or retries user can set + _maximum_reconnect_max_tries = 300 + + feed_token=None + client_code=None + def __init__(self, JWT_TOKEN, CLIENT_CODE,API_KEY,debug=False, root=None,reconnect=True,reconnect_max_tries=RECONNECT_MAX_TRIES, reconnect_max_delay=RECONNECT_MAX_DELAY,connect_timeout=CONNECT_TIMEOUT): + + + self.root = root or self.ROOT_URI+"?jwttoken="+JWT_TOKEN+"&&clientcode="+CLIENT_CODE+"&&apikey="+API_KEY + self.jwt_token= JWT_TOKEN + self.client_code= CLIENT_CODE + self.api_key=API_KEY + + # Set max reconnect tries + if reconnect_max_tries > self._maximum_reconnect_max_tries: + log.warning("`reconnect_max_tries` can not be more than {val}. Setting to highest possible value - {val}.".format( + val=self._maximum_reconnect_max_tries)) + self.reconnect_max_tries = self._maximum_reconnect_max_tries + else: + self.reconnect_max_tries = reconnect_max_tries + + # Set max reconnect delay + if reconnect_max_delay < self._minimum_reconnect_max_delay: + log.warning("`reconnect_max_delay` can not be less than {val}. Setting to lowest possible value - {val}.".format( + val=self._minimum_reconnect_max_delay)) + self.reconnect_max_delay = self._minimum_reconnect_max_delay + else: + self.reconnect_max_delay = reconnect_max_delay + + self.connect_timeout = connect_timeout + + # Debug enables logs + self.debug = debug + + # Placeholders for callbacks. + self.on_ticks = None + self.on_open = None + self.on_close = None + self.on_error = None + self.on_connect = None + self.on_message = None + self.on_reconnect = None + self.on_noreconnect = None + + + def _create_connection(self, url, **kwargs): + """Create a WebSocket client connection.""" + self.factory = SmartSocketClientFactory(url, **kwargs) + + # Alias for current websocket connection + self.ws = self.factory.ws + + self.factory.debug = self.debug + + # Register private callbacks + self.factory.on_open = self._on_open + self.factory.on_error = self._on_error + self.factory.on_close = self._on_close + self.factory.on_message = self._on_message + self.factory.on_connect = self._on_connect + self.factory.on_reconnect = self._on_reconnect + self.factory.on_noreconnect = self._on_noreconnect + + + self.factory.maxDelay = self.reconnect_max_delay + self.factory.maxRetries = self.reconnect_max_tries + + def connect(self, threaded=False, disable_ssl_verification=False, proxy=None): + #print("Connect") + self._create_connection(self.ROOT_URI) + + context_factory = None + #print(self.factory.isSecure,disable_ssl_verification) + if self.factory.isSecure and not disable_ssl_verification: + context_factory = ssl.ClientContextFactory() + #print("context_factory",context_factory) + connectWS(self.factory, contextFactory=context_factory, timeout=30) + + # Run in seperate thread of blocking + opts = {} + + # Run when reactor is not running + if not reactor.running: + if threaded: + #print("inside threaded") + # Signals are not allowed in non main thread by twisted so suppress it. + opts["installSignalHandlers"] = False + self.websocket_thread = threading.Thread(target=reactor.run, kwargs=opts) + self.websocket_thread.daemon = True + self.websocket_thread.start() + else: + reactor.run(**opts) + + + def is_connected(self): + #print("Check if WebSocket connection is established.") + if self.ws and self.ws.state == self.ws.STATE_OPEN: + return True + else: + return False + + def _close(self, code=None, reason=None): + #print("Close the WebSocket connection.") + if self.ws: + self.ws.sendClose(code, reason) + + def close(self, code=None, reason=None): + """Close the WebSocket connection.""" + self.stop_retry() + self._close(code, reason) + + def stop(self): + """Stop the event loop. Should be used if main thread has to be closed in `on_close` method.""" + #print("stop") + + reactor.stop() + + def stop_retry(self): + """Stop auto retry when it is in progress.""" + if self.factory: + self.factory.stopTrying() + + def _on_reconnect(self, attempts_count): + if self.on_reconnect: + return self.on_reconnect(self, attempts_count) + + def _on_noreconnect(self): + if self.on_noreconnect: + return self.on_noreconnect(self) + + def websocket_connection(self): + # if self.client_code == None or self.feed_token == None: + # return "client_code or feed_token or task is missing" + + # request={"task":"cn","channel":"","token":self.feed_token,"user":self.client_code,"acctid":self.client_code} + # self.ws.sendMessage( + # six.b(json.dumps(request)) + # ) + # print(request) + + threading.Thread(target=self.heartBeat,daemon=True).start() + + def send_request(self,actiontype,feedtype): + if actiontype in ("subscribe","unsubscribe "): + try: + request={"actiontype":actiontype,"feedtype":feedtype,"jwttoken":self.jwt_token,"clientcode":self.client_code,"apikey":self.api_key} + + self.ws.sendMessage( + six.b(json.dumps(request)) + ) + return True + # threading.Thread(target=self.heartBeat,daemon=True).start() + except Exception as e: + self._close(reason="Error while request sending: {}".format(str(e))) + raise + else: + print("The actiontype entered is invalid, Please enter correct task(subscribe,unsubscribe) ") + + def _on_connect(self, ws, response): + #print("-----_on_connect-------") + self.ws = ws + if self.on_connect: + + print(self.on_connect) + self.on_connect(self, response) + #self.websocket_connection + + def _on_close(self, ws, code, reason): + """Call `on_close` callback when connection is closed.""" + log.debug("Connection closed: {} - {}".format(code, str(reason))) + + if self.on_close: + self.on_close(self, code, reason) + + def _on_error(self, ws, code, reason): + """Call `on_error` callback when connection throws an error.""" + log.debug("Connection error: {} - {}".format(code, str(reason))) + + if self.on_error: + self.on_error(self, code, reason) + + + + def _on_message(self, ws, payload, is_binary): + """Call `on_message` callback when text message is received.""" + if self.on_message: + self.on_message(self, payload, is_binary) + + # If the message is binary, parse it and send it to the callback. + if self.on_ticks and is_binary and len(payload) > 4: + self.on_ticks(self, self._parse_binary(payload)) + + # Parse text messages + if not is_binary: + self._parse_text_message(payload) + + def _on_open(self, ws): + if not self._is_first_connect: + self.connect() + + self._is_first_connect = False + + if self.on_open: + return self.on_open(self) + + + def heartBeat(self): + while True: + try: + request={ + "actiontype":"heartbeat", + "feedtype":feedtype, + "jwttoken":self.jwt_token, + "clientcode":self.client_code, + "apikey":self.api_key + } + self.ws.sendMessage( + six.b(json.dumps(request)) + ) + + except: + print("HeartBeats Failed") + time.sleep(60) + + + def _parse_text_message(self, payload): + """Parse text message.""" + # Decode unicode data + if not six.PY2 and type(payload) == bytes: + payload = payload.decode("utf-8") + + data =base64.b64decode(payload) + + try: + data = bytes((zlib.decompress(data)).decode("utf-8"), 'utf-8') + data = json.loads(data.decode('utf8').replace("'", '"')) + data = json.loads(json.dumps(data, indent=4, sort_keys=True)) + except ValueError: + return + + self.on_ticks(self, data) + + def _parse_binary(self, bin): + """Parse binary data to a (list of) ticks structure.""" + packets = self._split_packets(bin) # split data to individual ticks packet + data = [] + + for packet in packets: + instrument_token = self._unpack_int(packet, 0, 4) + segment = instrument_token & 0xff # Retrive segment constant from instrument_token + + divisor = 10000000.0 if segment == self.EXCHANGE_MAP["cds"] else 100.0 + + # All indices are not tradable + tradable = False if segment == self.EXCHANGE_MAP["indices"] else True + try: + last_trade_time = datetime.fromtimestamp(self._unpack_int(packet, 44, 48)) + except Exception: + last_trade_time = None + + try: + timestamp = datetime.fromtimestamp(self._unpack_int(packet, 60, 64)) + except Exception: + timestamp = None + + d["last_trade_time"] = last_trade_time + d["oi"] = self._unpack_int(packet, 48, 52) + d["oi_day_high"] = self._unpack_int(packet, 52, 56) + d["oi_day_low"] = self._unpack_int(packet, 56, 60) + d["timestamp"] = timestamp + + # Market depth entries. + depth = { + "buy": [], + "sell": [] + } + + # Compile the market depth lists. + for i, p in enumerate(range(64, len(packet), 12)): + depth["sell" if i >= 5 else "buy"].append({ + "quantity": self._unpack_int(packet, p, p + 4), + "price": self._unpack_int(packet, p + 4, p + 8) / divisor, + "orders": self._unpack_int(packet, p + 8, p + 10, byte_format="H") + }) + + d["depth"] = depth + + data.append(d) + + return data + + def _unpack_int(self, bin, start, end, byte_format="I"): + """Unpack binary data as unsgined interger.""" + return struct.unpack(">" + byte_format, bin[start:end])[0] + + def _split_packets(self, bin): + """Split the data to individual packets of ticks.""" + # Ignore heartbeat data. + if len(bin) < 2: + return [] + + number_of_packets = self._unpack_int(bin, 0, 2, byte_format="H") + packets = [] + + j = 2 + for i in range(number_of_packets): + packet_length = self._unpack_int(bin, j, j + 2, byte_format="H") + packets.append(bin[j + 2: j + 2 + packet_length]) + j = j + 2 + packet_length + + return packets + \ No newline at end of file