(20241223) Trading Symbols Listing Started (Zerodha Kite).

This commit is contained in:
2024-12-23 12:42:27 +05:30
parent 1249841b05
commit 903a586cfe
14 changed files with 721 additions and 10 deletions
@@ -36,6 +36,7 @@ sys.path.append(".")
sys.path.append("..")
# My async utils:
from utils_v2.database.async_mysql_v2 import AsyncMySQL
from utils_v2.database.async_mongo_v2 import AsyncMongo
from utils_v2.cache.async_redis_cache_v2 import AsyncRedisCache
@@ -44,6 +45,7 @@ from controllers_v2.finstitutions.trading.base import TradingController
# Models:
from models.core.auth_token import CoreAuthTokenModel
from models.api.finstitutions.trading.symbols.list import TradingSymbolListRequestData, TradingSymbolListBrokerResponse
# To work with datatypes:
from typing import List, Any
@@ -131,7 +133,58 @@ class AllTradingController(TradingController):
# ┣┫┓┏╋┣┓
# ┛┗┗┻┗┛┗
pass
@staticmethod
async def get_authorization_url(
**kwargs
) -> str:
"""
To generate an authorization URL for this broker.
:param kwargs: Any no. of things needed by your broker to generate the URL.
:return: The authorization URL.
"""
raise NotImplementedError
async def handle_authorization_callback(
self,
sql_conn: AsyncMySQL,
mongo_data_conn: AsyncMongo,
inbound_data: dict
) -> bool:
"""
When the end user interacts with their broker's APIs, the broker's servers would usually issue a callback.
We've seen this in the case of Zerodha Kite and ICICI Breeze. Use this method to handle the callback loop to
complete the authorization.
:param sql_conn: The database connection to use to perform this activity.
:param mongo_data_conn: The database connection to use to perform this activity.
:param inbound_data: The data that came in from the broker. This could be in the JSON body, query params, etc.
:return: True if the callback loop was completed successfully, else False.
"""
raise NotImplementedError
# ┏┳┓ ┓• ┏┓ ┓ ┓
# ┃ ┏┓┏┓┏┫┓┏┓┏┓ ┗┓┓┏┏┳┓┣┓┏┓┃┏
# ┻ ┛ ┗┻┗┻┗┛┗┗┫ ┗┛┗┫┛┗┗┗┛┗┛┗┛
# ┛ ┛
async def list_symbols(
self,
mongo_data_conn: AsyncMongo,
auth_token: CoreAuthTokenModel,
inbound_data: TradingSymbolListRequestData
) -> TradingSymbolListBrokerResponse:
"""
To get the list of tradeable symbols offered by a broker.
:param mongo_data_conn: The database connection to use to perform this activity.
:param auth_token: The token that has to be used to fetch the data.
:param inbound_data: The data that came in with the APi call.
:return: The structured response form the broker.
"""
raise NotImplementedError
# *****************************************************************************************************************
+58 -1
View File
@@ -36,6 +36,7 @@ sys.path.append(".")
sys.path.append("..")
# My async utils:
from utils_v2.database.async_mysql_v2 import AsyncMySQL
from utils_v2.database.async_mongo_v2 import AsyncMongo
from utils_v2.cache.async_redis_cache_v2 import AsyncRedisCache
@@ -44,6 +45,7 @@ from controllers_v2.core.auth_token import CoreAuthTokenController
# Models:
from models.core.auth_token import CoreAuthTokenModel
from models.api.finstitutions.trading.symbols.list import TradingSymbolListRequestData, TradingSymbolListBrokerResponse
# To work with datatypes:
from typing import List, Any
@@ -149,7 +151,62 @@ class TradingController(CoreAuthTokenController, ABC):
# ┣┫┓┏╋┣┓
# ┛┗┗┻┗┛┗
pass
@staticmethod
@abstractmethod
async def get_authorization_url(
**kwargs
) -> str:
"""
To generate an authorization URL for this broker.
:param kwargs: Any no. of things needed by your broker to generate the URL.
:return: The authorization URL.
"""
pass
@abstractmethod
async def handle_authorization_callback(
self,
sql_conn: AsyncMySQL,
mongo_data_conn: AsyncMongo,
inbound_data: dict
) -> bool:
"""
When the end user interacts with their broker's APIs, the broker's servers would usually issue a callback.
We've seen this in the case of Zerodha Kite and ICICI Breeze. Use this method to handle the callback loop to
complete the authorization.
:param sql_conn: The database connection to use to perform this activity.
:param mongo_data_conn: The database connection to use to perform this activity.
:param inbound_data: The data that came in from the broker. This could be in the JSON body, query params, etc.
:return: True if the callback loop was completed successfully, else False.
"""
pass
# ┏┳┓ ┓• ┏┓ ┓ ┓
# ┃ ┏┓┏┓┏┫┓┏┓┏┓ ┗┓┓┏┏┳┓┣┓┏┓┃┏
# ┻ ┛ ┗┻┗┻┗┛┗┗┫ ┗┛┗┫┛┗┗┗┛┗┛┗┛
# ┛ ┛
@abstractmethod
async def list_symbols(
self,
mongo_data_conn: AsyncMongo,
auth_token: CoreAuthTokenModel,
inbound_data: TradingSymbolListRequestData
) -> TradingSymbolListBrokerResponse:
"""
To get the list of tradeable symbols offered by a broker.
:param mongo_data_conn: The database connection to use to perform this activity.
:param auth_token: The token that has to be used to fetch the data.
:param inbound_data: The data that came in with the APi call.
:return: The structured response form the broker.
"""
pass
# *****************************************************************************************************************
@@ -47,6 +47,11 @@ from controllers_v2.finstitutions.trading.base import TradingController
# Models:
from models.core.auth_token import CoreAuthTokenModel
from utils_v2.trading.zerodha_kite.models.auth_tokens import ZerodhaKiteAuthTokens
from models.api.finstitutions.trading.symbols.list import (
TradingSymbolListRequestData,
TradingSymbolListBrokerResponse,
TradingSymbol
)
# To work with MongoDB:
from bson.objectid import ObjectId
@@ -100,6 +105,12 @@ from kiteconnect import KiteConnect
class ZerodhaKiteTradingController(TradingController):
# ┏┓┓ ┓┏
# ┃ ┃┏┓┏┏ ┃┃┏┓┏┓┏
# ┗┛┗┗┻┛┛ ┗┛┗┻┛ ┛
CLIENT_NAME = "zerodhaKite"
# ┏┓
# ┃ ┏┓┏┓┏╋┏┓┓┏┏╋┏┓┏┓
# ┗┛┗┛┛┗┛┗┛ ┗┻┗┗┗┛┛
@@ -125,7 +136,7 @@ class ZerodhaKiteTradingController(TradingController):
"""
# Declare the client:
this_client = "zerodhaKite"
this_client = self.CLIENT_NAME
# Prepare base filter:
this_filter = {"client": this_client}
@@ -179,7 +190,7 @@ class ZerodhaKiteTradingController(TradingController):
:param sql_conn: The database connection to use to perform this activity.
:param mongo_data_conn: The database connection to use to perform this activity.
:param inbound_data: The data that came in from the broker. This could be in the JSON body, query params, etc.
:return: The model that hold the access tokens, or None if something failed.
:return: True if the callback loop was completed successfully, else False..
"""
# Start by assuming failure:
@@ -229,6 +240,55 @@ class ZerodhaKiteTradingController(TradingController):
# Done here:
return success
# ┏┳┓ ┓• ┏┓ ┓ ┓
# ┃ ┏┓┏┓┏┫┓┏┓┏┓ ┗┓┓┏┏┳┓┣┓┏┓┃┏
# ┻ ┛ ┗┻┗┻┗┛┗┗┫ ┗┛┗┫┛┗┗┗┛┗┛┗┛
# ┛ ┛
async def list_symbols(
self,
mongo_data_conn: AsyncMongo,
auth_token: CoreAuthTokenModel,
inbound_data: TradingSymbolListRequestData
) -> TradingSymbolListBrokerResponse:
"""
To get the list of tradeable symbols offered by Zerodha.
:param mongo_data_conn: The database connection to use to perform this activity.
:param auth_token: The token that has to be used to fetch the data.
:param inbound_data: The data that came in with the APi call.
:return: The structured response form the broker.
"""
# Start by assuming failure:
symbol_list = TradingSymbolListBrokerResponse()
try:
# Fit the token into the model:
zerodha_token = ZerodhaKiteAuthTokens(**auth_token.token)
# Now create an instance of the Kite:
kite = KiteConnect(api_key = auth_token.auth["apiKey"])
kite.set_access_token(zerodha_token.accessToken)
# Now we retrieve the list of symbols for every kind of exchange:
symbol_list.data = []
for exchange in inbound_data.exchanges:
symbols_subset = kite.instruments(exchange = exchange)
symbols_subset = [TradingSymbol.from_zerodha_kite(s) for s in symbols_subset[:10]]
symbol_list.data += symbols_subset
symbol_list.success = True
symbol_list.message = "Symbol list retrieved successfully."
# In case something goes wrong:
except Exception as exception:
symbol_list.exception = exception
symbol_list.message = str(exception)
# Done here:
return symbol_list
# *****************************************************************************************************************
# ***** ****