thank you for your prompt reply. The web socket is created, authenticated subscribed and data received without any issues the only problem that is happening is at 3.30 pm when the market is closing i am seeing this being passed as parameters to the error_handler of the websocket. I am ready to share my code with you if thats possible.
import sqlite3
from datetime import datetime
from auth.secret import get_token_and_client_id
from config import (
DB_FILE,
DELETE_TSL_QUERY,
INSERT_TSL_QUERY,
SELECT_TSL_QUERY,
STOP_PERCENT,
UPDATE_TSL_QUERY,
WS_LOG_PATH,
log,
)
from fyers_apiv3.FyersWebsocket import data_ws as ws
from fyers_apiv3 import fyersModel
from orders.order import Order
from reporting import report
class Stoploss:
def __init__(self, fyers: fyersModel):
self.holdings = None
self.positions = None
self.fs = None
self.fyers = fyers
self.order = Order(self.fyers)
self.to_sub = list()
def setup_trailing_stoploss(self):
try:
client_id, token = get_token_and_client_id()
self.fs = ws.FyersDataSocket(access_token=f"{client_id}:{token}", litemode=True, log_path=WS_LOG_PATH,
on_connect=self.start, on_close=self.close_handler,
on_error=self.error_handler, on_message=self.quote_handler)
self.fs.connect()
log.debug("connected to fyers ws successfully.")
except Exception as e:
log.error(f"error setting up websocket connection to fyers : {e}")
def get_positions(self):
try:
# get the current positions
self.positions = self.fyers.positions()["netPositions"]
# check for positions that are long
if self.positions:
self.positions = [
i for i in self.positions if i["side"] != "" and i["side"] > 0
]
for position in self.positions:
self.to_sub.append(position["symbol"])
log.debug(f"after appending open positions, subscription list is: {self.to_sub}")
except Exception as e:
log.error(f"error getting positions from fyers : {e}")
try:
conn = sqlite3.connect(DB_FILE)
c = conn.cursor()
for i in self.positions:
try:
c.execute(
SELECT_TSL_QUERY,
(i["symbol"],),
)
result = c.fetchall()
if result:
i["stoploss"] = result[0][0]
else:
i["stoploss"] = i["buyAvg"] - (i["buyAvg"] * STOP_PERCENT / 100)
# add symbol to trailing_stoploss db:
c.execute(
INSERT_TSL_QUERY,
(i["symbol"], i["stoploss"]),
)
conn.commit()
log.debug(f"calculated and added stoploss = {i['stoploss']} for {i['symbol']}")
except Exception as e:
log.error(f"error calculating and added stoploss for {i['symbol']}, {e}")
c.close()
conn.close()
except Exception as e:
log.error(f"error setting default sl for position : {e}")
def get_holdings(self):
try:
# get the current holdings
self.holdings = self.fyers.holdings()["holdings"]
# check for holdings that are open
if self.holdings:
self.holdings = [i for i in self.holdings if i["remainingQuantity"] > 0]
for holding in self.holdings:
self.to_sub.append(holding["symbol"])
log.debug(f"after appending open positions, subscription list is: {self.to_sub}")
except Exception as e:
log.error(f"error getting positions from fyers : {e}")
try:
conn = sqlite3.connect(DB_FILE)
c = conn.cursor()
for i in self.holdings:
try:
c.execute(
SELECT_TSL_QUERY,
(i["symbol"],),
)
result = c.fetchall()
if result:
i["stoploss"] = result[0][0]
else:
i["stoploss"] = i["costPrice"] - (
i["costPrice"] * STOP_PERCENT / 100
)
# add symbol to trailing_stoploss db:
c.execute(
INSERT_TSL_QUERY,
(i["symbol"], i["stoploss"]),
)
conn.commit()
except Exception as e:
log.error(f"error calculating and added stoploss for {i['symbol']}, {e}")
c.close()
conn.close()
except Exception as e:
log.error(e)
def start(self):
# unsubscribe to any previous feeds
if self.to_sub:
self.fs.unsubscribe(self.to_sub)
self.to_sub = [symbol.replace('&', '%26') for symbol in self.to_sub]
self.fs.subscribe(symbols=self.to_sub, data_type="SymbolUpdate")
log.debug("Subscribed to live feed.")
self.fs.keep_running()
else:
log.debug("No holdings or positions. Nothing to subscribe.")
# empty the trailing_stoploss table
conn = sqlite3.connect(DB_FILE)
c = conn.cursor()
c.execute(DELETE_TSL_QUERY)
conn.commit()
c.close()
conn.close()
def quote_handler(self, quotes):
# log.info(f'quotes received as is : {quotes}, data type {type(quotes)}')
if quotes['type'] != 'sf':
return
if self.market_status() == "open":
try:
self.stoploss(quotes["symbol"], quotes["ltp"])
except Exception as e:
log.error(f"error in processing tick : {quotes}, {e}")
else:
self.complete()
def stoploss(self, symbol, ltp):
# holdings
if self.holdings:
for i in self.holdings:
if symbol == i["symbol"]:
# check if SL breach
if ltp i["stoploss"]:
i["stoploss"] = trailing_sl
conn = sqlite3.connect(DB_FILE)
c = conn.cursor()
c.execute(
UPDATE_TSL_QUERY,
(
trailing_sl,
i["symbol"],
),
)
conn.commit()
c.close()
conn.close()
# log.debug(f"quote received for {symbol} : {ltp}")
# positions
if self.positions:
for i in self.positions:
if symbol == i["symbol"]:
# check if SL breach
if ltp <= i["stoploss"]:
log.info(f'[POSITION] Stoploss Hit. for {i}, LTP is {ltp}, selling and unsubscribing to symbol')
# unsubscribe from the ticker
self.fs.unsubscribe([i["symbol"]])
# exit position
self.order.sell(position=i)
def market_status(self):
now = datetime.now()
nine15 = now.replace(hour=9, minute=15, second=0, microsecond=0)
three30 = now.replace(hour=15, minute=30, second=0, microsecond=0)
if nine15 < now < three30:
return "open"
else:
return "closed"
def error_handler(self, *args, **kwargs):
log.error(f"args: {args}")
log.error(f"args: {kwargs}")
def close_handler(self, *args, **kwargs):
log.error(f"args: {args}")
log.error(f"args: {kwargs}")
if self.market_status() == "open":
# get holdings again and start the ws
self.get_positions()
self.get_holdings()
self.start()
else:
self.complete()
report.push_report("🔵 Market is closed (close handler triggered).")
def complete(self):
if self.to_sub:
self.fs.unsubscribe(self.to_sub)
self.fs.close_connection()
self.fs = None
log.debug("trading completed for the day.")
report.push_report("Trading completed for the day.")