Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Changelog
All notable changes to this project will be documented in this file.

## v1.0.1-BETA (16-Sep-2021)
### Added :
- Support for multiple default hosts. [ Internal ]
- Support to update endpoint's host after generating session according to `redirect` response. [ Internal ]
- Methods to consume Streaming API: `subscribe()` and `unsubscribe()`. For more details, refer [documentation](docs/StreamingApi.md). [ Feature ]
- Method `get_margin()`, For more details, refer [documentation](docs/MarginApi.md#get_margins) [ Feature ]

### Updated:
- In method `session_2fa()`, the `access_code` is now an optional parameter. It is able to generate session token with OTT only. [ Feature ]
- Method `order_report()` now takes an additional boolean parameter `is_fno` whose default value is `False`. [ Feature ]
- The documentation.

### Fixed:

#### Minor:
- `__doc__` strings of few methods.

## v1.0.0-BETA (Unreleased)
### Initial commits.
- For more details, refer [documentation](README.md)
28 changes: 21 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ Python 2.7 and 3.4+
If the python package is hosted on a repository, you can install directly using:

```sh
pip install git+https://github.com/osparamatrix/ks-orderapi-python.git
pip install git+https://github.com/noddy09/ks-orderapi-python.git
```
(you may need to run `pip` with root permission: `sudo pip install git+https://github.com/osparamatrix/ks-orderapi-python.git`)
(you may need to run `pip` with root permission: `sudo pip install git+https://github.com/noddy09/ks-orderapi-python.git`)

Then import the package:
```python
Expand Down Expand Up @@ -48,10 +48,9 @@ from ks_api_client import ks_api
client = ks_api.KSTradeApi(access_token = "", userid = "", \
consumer_key = "", ip = "127.0.0.1", app_id = "")

#For using specific environment use hosts as ["https://tradeapi.kotaksecurities.com/apim","https://ctradeapi.kotaksecurities.com/apim"]
client = ks_api.KSTradeApi(access_token = "", userid = "", \
consumer_key = "", ip = "127.0.0.1", app_id = "",
hosts = ["https://tradeapi.kotaksecurities.com/apim","https://ctradeapi.kotaksecurities.com/apim"])
#For using specific environment use host="https://tradeapi.kotaksecurities.com/apim"
client = ks_api.KSTradeApi(access_token = "", userid = "", consumer_key = "",
ip = "127.0.0.1", app_id = "", host ="https://sbx.kotaksecurities.com/apim")

# Get session for user
client.login(password = "")
Expand Down Expand Up @@ -90,6 +89,9 @@ order_info = [
]
client.margin_required(transaction_type = "BUY",order_info = order_info)

# Get calculate margins
client.get_margins()

# Get Positions
client.positions(position_type = "TODAYS")

Expand All @@ -102,12 +104,21 @@ client.history("historicalprices-unadjusted",{"exchange":"bse","co_code":"476","
client.history("NSEFNO_HistoricalContinuousChart",{"symbol":"HDFC","expiry type": "near"})
client.history("LiveorEODHistorical",{"exchange":"BSE","co_code":"5400","period":"Y","cnt":"3"})

# Subscribe to instrument token's stream.
def callback_method(message):
print(message)
print("Your logic/computation will come here.")
client.subscribe(input_token="745,754", auth_token="", callback=callback_method)

# Unsubscribe from streaming service.
client.unsubscribe()

#Terminate user's Session
client.logout()
```
## Documentation for API Endpoints

All URIs are relative to *https://tradeapi.kotaksecurities.com/apim*
All URIs are relative to *https://tradeapi.kotaksecurities.com/apim* and *https://ctradeapi.kotaksecurities.com/apim*

Class | Method | Description
------------ | ------------- | -------------
Expand All @@ -120,9 +131,12 @@ Class | Method | Description
*ReportsApi* | [**order_report**](docs/ReportsApi.md#order_report) | Get order report
*ReportsApi* | [**trade_report**](docs/ReportsApi.md#trade_report) | Get trade report
*MarginApi* | [**margin_required**](docs/MarginApi.md#margin_required) | Get Margin Required for an order by amount or quantity.
*MarginApi* | [**get_margins**](docs/MarginApi.md#get_margins) | Get all calculated margins.
*PositionsApi* | [**positions**](docs/PositionsApi.md#positions) | Get's Open position.
*QuoteApi* | [**quote**](docs/QuoteApi.md#quote_details) | Get Quote details
*HistoricalApi* | [**history**](docs/HistoricalApi.md#history) | Get historical data.
*StreamingApi* | [**subscribe**](docs/StreamingApi.md#subscribe) | Subscribe to streaming api of specified instrument tokens.
*StreamingApi* | [**unsubscribe**](docs/StreamingApi.md#unsubscribe) | Unsubscribe from streaming api.
*SessionApi* | [**logout**](docs/SessionApi.md#logout) | Invalidate Session Token


Expand Down
2 changes: 1 addition & 1 deletion docs/SessionApi.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Name | Type | Description | Notes
**consumer_key** | **str**| |
**ip** | **str**| |
**app_id** | **str**| |
**host** | **list**| List of trade API host URLs | [optional]
**host** | **str**| API host URL| [optional]
**proxy_url** | **str**| Proxy url | [optional]
**proxy_user** | **str**| Proxy user's Username | [optional]
**proxy_pass** | **str**| Proxy user's Password | [optional]
Expand Down
78 changes: 78 additions & 0 deletions docs/StreamingApi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# ks_api_client.StreamingApi

All URIs are relative to *https://tradeapi.kotaksecurities.com/apim*

Method | Description
------------- | -------------
[**subscribe**](StreamingApi.md#subscribe) | Get Margin Required for an order by amount or quantity.
[**unsubscribe**](StreamingApi.md#unsubscribe) | Gives complete Margin Details of a Client from RMS.


# **subscribe**
> object subscribe(input_tokens, auth_token, callback, broadcast_host):

Get streaming service subscription for specified instruments inputs.

### Example


```python
from ks_api_client import ks_api

client = ks_api.KSTradeApi(access_token = "access_token", userid = "userid", \
consumer_key = "consumer_key", ip = "IP", app_id = "app_id")

#First initialize session and generate session token

try:
# Get Margin Required for an order by amount or quantity.
client.subscribe(input_tokens="", consumer_key="", consumer_secret="", callback=print, broadcast_host="https://wstreamer.kotaksecurities.com")
except Exception as e:
print("Exception when calling StreamingApi->subscribe: %s\n" % e)
```

### Parameters

Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**input_tokens** | **str** | Instrument tokens with comma seperated. | Example: "475,745"
**consumer_key** | **str** | Consumer Key | Mandatory field
**consumer_secret** | **str** | Consumer Secret | Mandatory field
**callback** | **obj** | Method object | method of function should have one mandatory parameter to accept message. Default method is print()
**broadcast_host** | **str** | String host URL | default value: "https://wstreamer.kotaksecurities.com"

### Return type

**object**


# **unsubscribe**
> object unsubscribe()

Request to unsubscribe from streaming service.

### Example


```python
from ks_api_client import ks_api

client = ks_api.KSTradeApi(access_token = "access_token", userid = "userid", \
consumer_key = "consumer_key", ip = "IP", app_id = "app_id")

#First initialize session and generate session token

try:
# Get Margin details.
client.unsubscribe()
except Exception as e:
print("Exception when calling StreamingApi->unsubscribe: %s\n" % e)
```

### Return type

**object**


[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

2 changes: 1 addition & 1 deletion ks_api_client/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def __init__(self, host=None,
"""Debug switch
"""

self.verify_ssl = False
self.verify_ssl = True
"""SSL/TLS verification
Set this to false to skip verifying SSL certificate when calling API
from https server.
Expand Down
83 changes: 50 additions & 33 deletions ks_api_client/ks_api.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from re import S
import ks_api_client
import base64
import json
import os
import socketio
import requests
import urllib.parse
from urllib3 import make_headers

from ks_api_client.exceptions import ApiException, ApiValueError
Expand All @@ -12,50 +15,65 @@
UserCredentials, UserDetails, NewMISOrder, InlineObject

class KSTradeApi():
def __init__(self, access_token, userid, consumer_key, ip, app_id,
hosts=["https://tradeapi.kotaksecurities.com/apim","https://sbx.kotaksecurities.com/apim"],
proxy_url = '', proxy_user = '', proxy_pass = ''):
def __init__(self, access_token, userid, consumer_key, ip, app_id, host = None,
proxy_url = '', proxy_user = '', proxy_pass = '', verify_ssl=True):
self.userid = userid
self.host = host
self.consumer_key = consumer_key
self.ip = ip
self.app_id = app_id
self.access_token = access_token
self._proxy_user = proxy_user
self._proxy_pass = proxy_pass
self._proxy_url = proxy_url
self._verify_ssl = verify_ssl
error = None
session_init = None
for host in hosts:
self.host = host
configuration = self.get_config(proxy_url, proxy_user, proxy_pass)
try:
self.api_client = ks_api_client.ApiClient(configuration)
session_init_res = ks_api_client.SessionApi(self.api_client).session_init(self.userid, \
self.consumer_key, self.ip, self.app_id)
except ApiException as ex:
error = ex
continue
self.__session_init = None

def init_session(self, session_init_res):
if(session_init_res.get("Success")):
session_init = session_init_res.get("Success")
self.__session_init = session_init_res.get("Success")
elif(session_init_res.get("success")):
session_init = session_init_res.get("success")
if self.host != session_init['redirect']['host']:
self.host = session_init['redirect']['host']
configuration = self.get_config(proxy_url, proxy_user, proxy_pass)
self.__session_init = session_init_res.get("success")
if self.host != self.__session_init['redirect']['host']:
self.host = self.__session_init['redirect']['host']
configuration = self.get_config(proxy_url, proxy_user, proxy_pass, verify_ssl)
self.api_client = ks_api_client.ApiClient(configuration)
session_init = ks_api_client.SessionApi(self.api_client).session_init(self.userid, \
self.__session_init = ks_api_client.SessionApi(self.api_client).session_init(self.userid, \
self.consumer_key, self.ip, self.app_id)
break
if not session_init and error:
if self.host:
configuration = self.get_config(proxy_url, proxy_user, proxy_pass, verify_ssl)
self.api_client = ks_api_client.ApiClient(configuration)
session_init_res = ks_api_client.SessionApi(self.api_client).session_init(self.userid, \
self.consumer_key, self.ip, self.app_id)
init_session(self, session_init_res)
else:
hosts = ["https://tradeapi.kotaksecurities.com/apim","https://sbx.kotaksecurities.com/apim"]
for host in hosts:
self.host = host
configuration = self.get_config(proxy_url, proxy_user, proxy_pass, verify_ssl)
try:
self.api_client = ks_api_client.ApiClient(configuration)
session_init_res = ks_api_client.SessionApi(self.api_client).session_init(self.userid, \
self.consumer_key, self.ip, self.app_id)
except ApiException as ex:
error = ex
continue
init_session(self, session_init_res)
break
if not self.__session_init and error:
raise error
del self.__session_init

def get_config(self, proxy_url = '', proxy_user = '', proxy_pass = ''):
def get_config(self, proxy_url = '', proxy_user = '', proxy_pass = '', verify_ssl=True):
configuration = ks_api_client.Configuration(self.host)
configuration.access_token = self.access_token
if proxy_url:
configuration.proxy = proxy_url
if proxy_user:
configuration.proxy_headers = make_headers(proxy_basic_auth = ':'.join((proxy_user,proxy_pass)))
if not verify_ssl:
configuration.verify_ssl = False
return configuration

def login(self, password):
Expand Down Expand Up @@ -234,7 +252,7 @@ def margin_required(self, transaction_type, order_info):
ReqMargin = req_margin)
return margin_required

def get_margins(self):
def margin(self):
margins = ks_api_client.MarginApi(self.api_client).get_margins(self.consumer_key,self.session_token)
return margins

Expand Down Expand Up @@ -293,7 +311,8 @@ def history(self, resource, json_input):
raise ApiValueError("exchange,co_code,period,cnt fields are required.")
encoded_json = base64.urlsafe_b64encode(json.dumps(json_input).encode()).decode()
data = ks_api_client.HistoricalApi(self.api_client).get_resource(resource,encoded_json)
return data
return data

#-------- Convert Array and object snake_case keys to camelCase -----------
def convertObject(self, object):
newObj={}
Expand All @@ -315,13 +334,12 @@ def convertArray(self, array):
return new_array


def subscribe(self, input_tokens, callback, auth_token, broadcast_host="https://wstreamer.kotaksecurities.com"):
def subscribe(self, input_tokens, consumer_key, consumer_secret, callback=print, broadcast_host="https://wstreamer.kotaksecurities.com"):
try:
auth_token = ":".join((consumer_key, consumer_secret))
proxy = ""
session = requests.session()
if self._proxy_pass or self._proxy_url or self._proxy_user:
import urllib.parse
import requests
session = requests.session()
scheme = ""
parsed = urllib.parse.urlparse(self._proxy_url)
if not parsed.scheme:
Expand All @@ -334,7 +352,7 @@ def subscribe(self, input_tokens, callback, auth_token, broadcast_host="https://
if parsed.port:
proxy += ":" + str(parsed.port)
session.proxies.update({'http':proxy, 'https':proxy})
session.verify = 's' in scheme
session.verify = self._verify_ssl
# Generating base64 encoding of consumer credentials
AUTH_BASE64 = base64.b64encode(auth_token.encode("UTF-8"))
PAYLOAD = {"authentication": AUTH_BASE64.decode("UTF-8")}
Expand All @@ -348,7 +366,7 @@ def subscribe(self, input_tokens, callback, auth_token, broadcast_host="https://
else:
self.sio = socketio.Client(
reconnection=True, request_timeout=20, reconnection_attempts=5, engineio_logger=True,
logger=True,http_session=session, ssl_verify=session.verify)
logger=True, http_session=session, ssl_verify=session.verify)

@self.sio.event
def connect():
Expand All @@ -365,8 +383,7 @@ def disconnect():
@self.sio.on('getdata')
def on_getdata(data, callback=callback):
callback(data)

# Do the connection using above access token

self.sio.connect(broadcast_host,
headers={'Authorization': 'Bearer ' + jsonResponse['result']['token']},
transports=["websocket"], socketio_path='/feed')
Expand Down
3 changes: 1 addition & 2 deletions ks_api_client/settings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
host = ["https://tradeapi.kotaksecurities.com/apim",
"https://sbx.kotaksecurities.com/apim"]
host = "https://sbx.kotaksecurities.com/apim"
access_token = ""
userid = ""
consumer_key = ""
Expand Down
4 changes: 1 addition & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
# prerequisite: setuptools
# http://pypi.python.org/pypi/setuptools

REQUIRES = ["certifi >= 14.05.14", "future; python_version<=2.7", "six >= 1.10",
"python_dateutil >= 2.5.3", "setuptools >= 21.0.0", "urllib3 >= 1.15.1",
"python-socketio[client]==5.3.0", "requests==2.26.0"]
REQUIRES = ["certifi>=14.05.14", "six >= 1.10", "python_dateutil >= 2.5.3", "urllib3 > 1.15", "python-socketio[client]==5.3.0", "requests==2.26.0"]

setup(
name=NAME,
Expand Down