Skip to content

Commit

Permalink
modified connect.py and ticker.py
Browse files Browse the repository at this point in the history
  • Loading branch information
sangam committed Dec 13, 2024
1 parent 0a1d3b3 commit c9c8857
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 16 deletions.
96 changes: 86 additions & 10 deletions mykiteconnect/connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
:copyright: (c) 2024 by Sangam Chopade.
:license: see LICENSE for details.
"""
import urllib.parse
from six import StringIO, PY2
from six.moves.urllib.parse import urljoin
import csv
Expand All @@ -17,6 +18,8 @@
import datetime
import requests
import warnings
import urllib
import pyotp

from .__version__ import __version__, __title__
import mykiteconnect.exceptions as ex
Expand Down Expand Up @@ -107,7 +110,9 @@ class KiteConnect(object):

# URIs to various calls
_routes = {
"login": "api/login",
"connect": "connect/login?api_key={api_key}&v={version}",
"login": "connect/login",
"loginapi": "api/login",
"twofa": "api/twofa",
"api.token": "/session/token",
"api.token.invalidate": "/session/token",
Expand Down Expand Up @@ -230,9 +235,10 @@ def __init__(self,
"sec-ch-ua": '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "Windows",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"x-kite-version": self.kite_header_version
}
Expand Down Expand Up @@ -268,6 +274,9 @@ def set_access_token(self, access_token):
"""Set the `access_token` received after a successful authentication."""
self.access_token = access_token

def set_enctoken(self, enctoken):
self.enctoken = enctoken

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&v=%s" % (self._default_login_uri, self.api_key, self.kite_header_version)
Expand Down Expand Up @@ -350,9 +359,68 @@ def login_worklow(self):
"""Login workflow"""
if self.username and self.password and self.otp_seed:
if self.api_key and self.api_secret:
self.reqsession.get(
self.login_url(),

response = self._get(
"connect",
url_args={
"api_key": self.api_key,
"version": self.kite_header_version}
)
response = self._post(
"loginapi",
params = urllib.parse.urlencode(
{
'user_id': self.username,
'password': self.password,
'type': 'user_id'
}
)
)
response = self._post(
"twofa",
params = urllib.parse.urlencode(
{
'user_id': self.username,
'request_id': response["data"]["request_id"],
'twofa_value': pyotp.TOTP(self.otp_seed).now(),
'twofa_type': "totp",
'skip_session': 'true'
}
)
)
request_token = self._get(
"login",
params = {'skip_session': 'true'}
)
access_token = self.generate_session(request_token, self.api_secret)
self.set_access_token(access_token)
else:
response = self._get(
"login",
params = {
"skip_session": 'true',
}
)
response = self._post(
"login",
params = urllib.parse.urlencode(
{
'user_id': self.username,
'password': self.password,
'type': 'user_id'
}
)
)
response = self._post(
"twofa",
params = urllib.parse.urlencode(
{
'user_id': self.username,
'request_id': response["data"]["request_id"],
'twofa_value': pyotp.TOTP(self.otp_seed).now(),
'twofa_type': "totp",
'skip_session': 'true'
}
)
)

return 0
Expand Down Expand Up @@ -913,7 +981,7 @@ def _delete(self, route, url_args=None, params=None, is_json=False):

def _header(self):
"""Custom headers"""
self.headers["x-kite-userid"] = self.username,
self.headers["x-kite-userid"] = self.username

def _request(self, route, method, url_args=None, params=None, is_json=False, query_params=None):
"""Make an HTTP request."""
Expand All @@ -923,8 +991,11 @@ def _request(self, route, method, url_args=None, params=None, is_json=False, que
else:
uri = self._routes[route]

if uri in ["login", "twofa"]:
url = urljoin(self.base, uri)
if uri in ["login", "twofa", "connect"]:
if params['skip_session'] == 'true':
url = self.base + "?skip_session=true"
else:
url = urljoin(self.base, uri)
else:
url = urljoin(self.root, uri)

Expand Down Expand Up @@ -971,6 +1042,9 @@ def _request(self, route, method, url_args=None, params=None, is_json=False, que
raise ex.DataException("Couldn't parse the JSON response received from the server: {content}".format(
content=r.content))

if method == "twofa" and self.api_key == None:
self.set_enctoken(r.cookies.get('enctoken'))

# api error
if data.get("status") == "error" or data.get("error_type"):
# Call session hook if its registered and TokenException is raised
Expand All @@ -984,6 +1058,8 @@ def _request(self, route, method, url_args=None, params=None, is_json=False, que
return data["data"]
elif "csv" in r.headers["content-type"]:
return r.content
elif "html" in r.headers["content-type"]:
return r.content
else:
raise ex.DataException("Unknown Content-Type ({content_type}) with response: ({content})".format(
content_type=r.headers["content-type"],
Expand Down
53 changes: 47 additions & 6 deletions mykiteconnect/ticker.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,9 @@ def on_close(ws, code, reason):
# Default root API endpoint. It's possible to
# override this by passing the `root` parameter during initialisation.
ROOT_URI = "wss://ws.kite.trade"
BASE_URI = "wss://ws.zerodha.com"

kite_header_version = "3.0.0"

# Available streaming modes.
MODE_FULL = "full"
Expand All @@ -400,8 +403,8 @@ def on_close(ws, code, reason):
# Maximum number or retries user can set
_maximum_reconnect_max_tries = 300

def __init__(self, api_key, access_token, debug=False, root=None,
reconnect=True, reconnect_max_tries=RECONNECT_MAX_TRIES, reconnect_max_delay=RECONNECT_MAX_DELAY,
def __init__(self, username, enctoken=None, api_key=None, access_token=None, debug=False, root=None,
base=None, reconnect=True, reconnect_max_tries=RECONNECT_MAX_TRIES, reconnect_max_delay=RECONNECT_MAX_DELAY,
connect_timeout=CONNECT_TIMEOUT):
"""
Initialise websocket client instance.
Expand All @@ -421,6 +424,14 @@ def __init__(self, api_key, access_token, debug=False, root=None,
- `connect_timeout` in seconds is the maximum interval after which connection is considered as timeout. Defaults to 30s.
"""
self.root = root or self.ROOT_URI
self.base = base or self.BASE_URI
self.username = username
self.enctoken = enctoken
self.api_key = api_key
self.access_token = access_token

if not(self.enctoken or (self.api_key and self.access_token)):
log.error("enctoken or api_key ith access_token are mandatory")

# Set max reconnect tries
if reconnect_max_tries > self._maximum_reconnect_max_tries:
Expand All @@ -439,8 +450,24 @@ def __init__(self, api_key, access_token, debug=False, root=None,
self.reconnect_max_delay = reconnect_max_delay

self.connect_timeout = connect_timeout

self.socket_url = "{root}?api_key={api_key}"\

if self.enctoken:
self.socket_url = "{base}?api_key={api_key}"\
"&user_id={user_id}"\
"&enctoken={enctoken}"\
"&uid={uid}"\
"&user-agent={user_agent}"\
"&version={version}".format(
root=self.base,
user_id=self.username,
enctoken=self.enctoken,
uid=str(int(time.time()*1000)),
user_agent="kite3-web",
api_key="kitefront",
version=self.kite_header_version
)
else:
self.socket_url = "{root}?api_key={api_key}"\
"&access_token={access_token}".format(
root=self.root,
api_key=api_key,
Expand Down Expand Up @@ -491,7 +518,10 @@ def _create_connection(self, url, **kwargs):
self.factory.maxRetries = self.reconnect_max_tries

def _user_agent(self):
return (__title__ + "-python/").capitalize() + __version__
if self.api_key and self.access_token:
return (__title__ + "-python/").capitalize() + __version__
else:
return ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36")

def connect(self, threaded=False, disable_ssl_verification=False, proxy=None):
"""
Expand All @@ -503,7 +533,18 @@ def connect(self, threaded=False, disable_ssl_verification=False, proxy=None):
"""
# Custom headers
headers = {
"X-Kite-Version": "3", # For version 3
"accept-encoding": "gzip, deflate, br, zstd",
"accept-language": "en-US,en;q=0.9",
"cache-control": "no-cache",
"connection": "Upgrade",
"host": "ws.zerodha.com",
"origin": "https://kite.zerodha.com",
"pragma": "no-cache",
"sec-websocket-extensions": "permessage-deflate; client_max_window_bits",
"sec-websocket-key": "LXCqUuJ1KEgXM8VgNj63fA==",
"sec-websocket-version": "13",
"upgrade": "websocket",
"X-Kite-Version": "3.0.0", # For version 3
}

# Init WebSocket client factory
Expand Down

0 comments on commit c9c8857

Please sign in to comment.