SmartAPI, provided by Angel Broking, offers a robust solution for traders and developers looking to integrate real-time stock market data into their applications. Utilizing WebSocket technology, SmartAPI ensures seamless and efficient streaming of live financial data.
Step1 : Install the Python Library
use the following pip commands to install the python library
pip install smartapi-python
pip install websocket-client
pip install pyotp
pip install pytz
pip install logzero
Step 2: Generate the Token
1) Visit smartapi.angelbroking.com/enable-totp
2) Enter your Angel One client id and trading terminal password or MPIN
3) Enter OTP sent to the Registered email & mobile. Once OTP is entered, you will see a QR code on the screen and a token number on the screen.
Step 3 : Generate the API Key
1)Login to SmartAPI Developer Portal
2)Click on Create an App button
3)Select the Market Feeds APIs option and enter the app name, enter the redirect url and postback url as shown below ,enter your Angel Client ID, and click the Create App button
4)Copy the API Key and keep it seperately.
Step 4 : Preparing the config.py file
apikey = '9bmmTPjj'
username = 'R464999'
pwd = '1111'
token = '4YYB6RA2LXXXEKEZZ3BS7SJ3Y'
The config.py
file is a Python configuration script containing sensitive information required for authenticating and connecting to a SmartAPI
Step 5 : Authentication
First to get authenticated one should learn how to Autogenerate TOTP for Angel Broking
Here is the following block of code which lets the trader auto-authenticated
# package import statement
from SmartApi import SmartConnect #or from smartapi.smartConnect import SmartConnect
import pyotp,time, pytz
from datetime import datetime
import threading
from config import *
#create object of call
obj=SmartConnect(api_key=apikey)
#login api call
data = obj.generateSession(username,pwd,pyotp.TOTP(token).now())
#cls
# print (data)
refreshToken= data['data']['refreshToken']
AUTH_TOKEN = data['data']['jwtToken']
#fetch the feedtoken
FEED_TOKEN =obj.getfeedToken()
#print ("Feed Token: "+FEED_TOKEN)
#fetch User Profile
res= obj.getProfile(refreshToken)
print(res['data']['exchanges'])
Fetching Tokens: After authentication, it retrieves refreshToken
and AUTH_TOKEN
for maintaining the session, and FEED_TOKEN
for fetching data feeds.
Features of Smart Websocket 2.0
As per the latest documentation of SmartAPI here are the following features of AngelOne Smart WebsocketV2
The SmartAPI offers a streamlined and uniform structure for both JSON requests and binary responses. It also provides a straightforward heartbeat mechanism for message exchanges.
Clients, each identified by their unique Angel One trading account ID, can maintain up to three simultaneous WebSocket connections. There’s no necessity to disconnect and reconnect for modifying subscriptions; the existing connection can be effectively utilized for real-time subscription adjustments.
Failures in modifying subscriptions won’t affect current subscriptions, ensuring uninterrupted data feeds. Unsubscription requests for non-subscribed tokens are seamlessly handled without disturbing the data flow of active subscriptions.
Each WebSocket session supports a maximum of 1,000 token subscriptions. For instance, subscribing to different modes (like LTP, Quote, and SnapQuote) for a single entity such as Infosys NSE counts as separate subscriptions.
Redundant subscriptions to the same token and mode are efficiently managed, not affecting the subscription limit. Clients receive a distinct data update (tick) for each combination of token and mode. In the case of multiple modes subscribed for a single entity, like Infosys NSE, a separate tick is sent for each mode with relevant information.
Step 6. Running the Websocket to Fetch LTP Quotes
Complete Python Code to Fetch the Realtime LTP quotes
# package import statement
from SmartApi import SmartConnect #or from smartapi.smartConnect import SmartConnect
import pyotp,time, pytz
from datetime import datetime
import threading
from config import *
#create object of call
obj=SmartConnect(api_key=apikey)
#login api call
data = obj.generateSession(username,pwd,pyotp.TOTP(token).now())
#cls
# print (data)
refreshToken= data['data']['refreshToken']
AUTH_TOKEN = data['data']['jwtToken']
#fetch the feedtoken
FEED_TOKEN =obj.getfeedToken()
#print ("Feed Token: "+FEED_TOKEN)
#fetch User Profile
res= obj.getProfile(refreshToken)
print(res['data']['exchanges'])
from SmartApi.smartWebSocketV2 import SmartWebSocketV2
from logzero import logger
correlation_id = "ws_test"
action = 1 #action = 1, subscribe to the feeds action = 2 - unsubscribe
mode = 1 #mode = 1 , Fetches LTP quotes
token_list = [
{
"exchangeType": 2,
"tokens": ["57920","57919"]
}
]
token_list1 = [
{
"exchangeType": 1,
"tokens": ["26000","26009"]
}
]
sws = SmartWebSocketV2(AUTH_TOKEN, apikey, username, FEED_TOKEN,max_retry_attempt=5)
#row_format = "Exchange Type: {exchange_type}, Token: {token}, Last Traded Price: {last_traded_price}"
def on_data(wsapp, message):
# Convert timestamp from milliseconds to seconds
timestamp = message['exchange_timestamp'] / 1000 # Convert to seconds
utc_time = datetime.utcfromtimestamp(timestamp)
# Define the timezone for UTC +05:30
timezone = pytz.timezone('Asia/Kolkata') # 'Asia/Kolkata' is the timezone for UTC +05:30
# Convert UTC time to UTC +05:30
local_time = utc_time.replace(tzinfo=pytz.utc).astimezone(timezone)
formatted_timestamp = local_time.strftime('%Y-%m-%d %H:%M:%S')
# Define the format for the output with two decimal places for Last Traded Price
row_format = "Exchange Type: {exchange_type}, Token: {token}, Last Traded Price: {last_traded_price:.2f}, Timestamp: {timestamp}"
# Format the message data
formatted_row = row_format.format(
exchange_type=message['exchange_type'],
token=message['token'],
last_traded_price=message['last_traded_price'] / 100, # Assuming this division by 100 is required for your specific case
timestamp=formatted_timestamp
)
# Print the formatted data
logger.info(formatted_row)
def on_open(wsapp):
logger.info("on open")
sws.subscribe(correlation_id, mode, token_list)
sws.subscribe(correlation_id, mode, token_list1)
# sws.unsubscribe(correlation_id, mode, token_list1)
def on_error(wsapp, error):
logger.info(error)
def on_close(wsapp):
logger.info("Close")
def close_connection():
sws.close_connection()
# Assign the callbacks.
sws.on_open = on_open
sws.on_data = on_data
sws.on_error = on_error
sws.on_close = on_close
threading.Thread(target=sws.connect).start()
The above code uses a separate thread is started for the WebSocket connection to run asynchronously. The tokens “57920”, “57919” correspond to Nifty and Bank Nifty Nov 23 Futures contracts, and “26000”, “26009” correspond to Nifty and Bank Nifty Index Data.
Sample Output
[I 231120 12:24:35 smartwebsocket:79] Exchange Type: 1, Token: 26000, Last Traded Price: 19698.10, Timestamp: 2023-11-20 12:24:35
[I 231120 12:24:35 smartwebsocket:79] Exchange Type: 1, Token: 26009, Last Traded Price: 43629.95, Timestamp: 2023-11-20 12:24:35
[I 231120 12:24:35 smartwebsocket:79] Exchange Type: 1, Token: 26000, Last Traded Price: 19696.75, Timestamp: 2023-11-20 12:24:36
[I 231120 12:24:35 smartwebsocket:79] Exchange Type: 1, Token: 26009, Last Traded Price: 43628.00, Timestamp: 2023-11-20 12:24:36
[I 231120 12:24:36 smartwebsocket:79] Exchange Type: 2, Token: 57919, Last Traded Price: 43765.00, Timestamp: 2023-11-20 12:24:36
[I 231120 12:24:36 smartwebsocket:79] Exchange Type: 2, Token: 57920, Last Traded Price: 19750.00, Timestamp: 2023-11-20 12:24:36
[I 231120 12:24:36 smartwebsocket:79] Exchange Type: 2, Token: 57920, Last Traded Price: 19750.00, Timestamp: 2023-11-20 12:24:36
[I 231120 12:24:36 smartwebsocket:79] Exchange Type: 1, Token: 26000, Last Traded Price: 19696.70, Timestamp: 2023-11-20 12:24:37
[I 231120 12:24:36 smartwebsocket:79] Exchange Type: 1, Token: 26009, Last Traded Price: 43631.30, Timestamp: 2023-11-20 12:24:37
[I 231120 12:24:37 smartwebsocket:79] Exchange Type: 2, Token: 57919, Last Traded Price: 43769.35, Timestamp: 2023-11-20 12:24:37
[I 231120 12:24:37 smartwebsocket:79] Exchange Type: 2, Token: 57919, Last Traded Price: 43769.35, Timestamp: 2023-11-20 12:24:37
[I 231120 12:24:37 smartwebsocket:79] Exchange Type: 2, Token: 57920, Last Traded Price: 19750.00, Timestamp: 2023-11-20 12:24:37
[I 231120 12:24:37 smartwebsocket:79] Exchange Type: 1, Token: 26000, Last Traded Price: 19698.25, Timestamp: 2023-11-20 12:24:38
[I 231120 12:24:37 smartwebsocket:79] Exchange Type: 1, Token: 26009, Last Traded Price: 43631.10, Timestamp: 2023-11-20 12:24:38
[I 231120 12:24:38 smartwebsocket:79] Exchange Type: 2, Token: 57919, Last Traded Price: 43769.35, Timestamp: 2023-11-20 12:24:38
[I 231120 12:24:38 smartwebsocket:79] Exchange Type: 2, Token: 57919, Last Traded Price: 43769.35, Timestamp: 2023-11-20 12:24:38
[I 231120 12:24:38 smartwebsocket:79] Exchange Type: 1, Token: 26000, Last Traded Price: 19696.00, Timestamp: 2023-11-20 12:24:39
[I 231120 12:24:38 smartwebsocket:79] Exchange Type: 1, Token: 26009, Last Traded Price: 43627.85, Timestamp: 2023-11-20 12:24:39
[I 231120 12:24:38 smartwebsocket:79] Exchange Type: 2, Token: 57920, Last Traded Price: 19750.00, Timestamp: 2023-11-20 12:24:39
[I 231120 12:24:39 smartwebsocket:79] Exchange Type: 2, Token: 57919, Last Traded Price: 43765.00, Timestamp: 2023-11-20 12:24:39
[I 231120 12:24:39 smartwebsocket:79] Exchange Type: 2, Token: 57919, Last Traded Price: 43765.00, Timestamp: 2023-11-20 12:24:39
Step 7 : Fetching Open, High, Close, LTP, Volume Data
Here is the python code smartwebsocketquotes.py which fetches the realtime stock market price quotes along with volume data
# package import statement
from SmartApi import SmartConnect #or from smartapi.smartConnect import SmartConnect
import pyotp,time, pytz
from datetime import datetime
import threading
from config import *
#create object of call
obj=SmartConnect(api_key=apikey)
#login api call
data = obj.generateSession(username,pwd,pyotp.TOTP(token).now())
#cls
# print (data)
refreshToken= data['data']['refreshToken']
AUTH_TOKEN = data['data']['jwtToken']
#fetch the feedtoken
FEED_TOKEN =obj.getfeedToken()
#print ("Feed Token: "+FEED_TOKEN)
#fetch User Profile
res= obj.getProfile(refreshToken)
print(res['data']['exchanges'])
from SmartApi.smartWebSocketV2 import SmartWebSocketV2
from logzero import logger
correlation_id = "ws_test"
action = 1 #action = 1, subscribe to the feeds action = 2 - unsubscribe
mode = 2 #mode = 2 , Fetches quotes
token_list = [
{
"exchangeType": 2,
"tokens": ["57920","57919"]
}
]
sws = SmartWebSocketV2(AUTH_TOKEN, apikey, username, FEED_TOKEN,max_retry_attempt=5)
def on_data(wsapp, message):
try:
# Assuming 'message' is a dictionary, not a list
item = message
# Converting and formatting the timestamp
timestamp = datetime.fromtimestamp(item['exchange_timestamp'] / 1000, pytz.timezone('Asia/Kolkata'))
# Formatting the data
formatted_item = {
'Exchange Type': item['exchange_type'],
'Token': item['token'],
'Timestamp (IST)': timestamp.strftime('%Y-%m-%d %H:%M:%S'),
'Open Price': f"{item['open_price_of_the_day'] / 100:.2f}",
'High Price': f"{item['high_price_of_the_day'] / 100:.2f}",
'Low Price': f"{item['low_price_of_the_day'] / 100:.2f}",
'Close Price': f"{item['closed_price'] / 100:.2f}",
'Last Traded Price': f"{item['last_traded_price'] / 100:.2f}",
}
# Logging the formatted data
logger.info(formatted_item)
except Exception as e:
logger.error(f"Error processing message: {e}")
def on_open(wsapp):
logger.info("on open")
sws.subscribe(correlation_id, mode, token_list)
# sws.unsubscribe(correlation_id, mode, token_list1)
def on_error(wsapp, error):
logger.info(error)
def on_close(wsapp):
logger.info("Close")
def close_connection():
sws.close_connection()
# Assign the callbacks.
sws.on_open = on_open
sws.on_data = on_data
sws.on_error = on_error
sws.on_close = on_close
threading.Thread(target=sws.connect).start()
Sample Output
[I 231120 14:48:04 smartwebsocket:68] {'Exchange Type': 2, 'Token': '57920', 'Timestamp (IST)': '2023-11-20 14:48:05', 'Open Price': '19798.90', 'High Price': '19848.00', 'Low Price': '19718.00', 'Close Price': '19806.50', 'Last Traded Price': '19771.20'}
[I 231120 14:48:05 smartwebsocket:68] {'Exchange Type': 2, 'Token': '57920', 'Timestamp (IST)': '2023-11-20 14:48:05', 'Open Price': '19798.90', 'High Price': '19848.00', 'Low Price': '19718.00', 'Close Price': '19806.50', 'Last Traded Price': '19771.20'}
[I 231120 14:48:05 smartwebsocket:68] {'Exchange Type': 2, 'Token': '57919', 'Timestamp (IST)': '2023-11-20 14:48:05', 'Open Price': '43724.60', 'High Price': '43900.00', 'Low Price': '43559.80', 'Close Price': '43715.45', 'Last Traded Price': '43800.90'}
[I 231120 14:48:06 smartwebsocket:68] {'Exchange Type': 2, 'Token': '57920', 'Timestamp (IST)': '2023-11-20 14:48:06', 'Open Price': '19798.90', 'High Price': '19848.00', 'Low Price': '19718.00', 'Close Price': '19806.50', 'Last Traded Price': '19771.20'}
[I 231120 14:48:06 smartwebsocket:68] {'Exchange Type': 2, 'Token': '57919', 'Timestamp (IST)': '2023-11-20 14:48:06', 'Open Price': '43724.60', 'High Price': '43900.00', 'Low Price': '43559.80', 'Close Price': '43715.45', 'Last Traded Price': '43800.90'}
[I 231120 14:48:07 smartwebsocket:68] {'Exchange Type': 2, 'Token': '57920', 'Timestamp (IST)': '2023-11-20 14:48:07', 'Open Price': '19798.90', 'High Price': '19848.00', 'Low Price': '19718.00', 'Close Price': '19806.50', 'Last Traded Price': '19771.20'}
[I 231120 14:48:07 smartwebsocket:68] {'Exchange Type': 2, 'Token': '57919', 'Timestamp (IST)': '2023-11-20 14:48:07', 'Open Price': '43724.60', 'High Price': '43900.00', 'Low Price': '43559.80', 'Close Price': '43715.45', 'Last Traded Price': '43800.90'}
[I 231120 14:48:07 smartwebsocket:68] {'Exchange Type': 2, 'Token': '57920', 'Timestamp (IST)': '2023-11-20 14:48:08', 'Open Price': '19798.90', 'High Price': '19848.00', 'Low Price': '19718.00', 'Close Price': '19806.50', 'Last Traded Price': '19771.30'}