From 205d3e4541d87483449613bbdcc01c57d937c267 Mon Sep 17 00:00:00 2001 From: prithviraj-gotepatil-algobulls Date: Mon, 24 Jul 2023 19:29:05 +0530 Subject: [PATCH 01/11] added some possible structure for generative AI --- pyalgotrading/algobulls/connection.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/pyalgotrading/algobulls/connection.py b/pyalgotrading/algobulls/connection.py index a8bfb45a..3c6d74f9 100644 --- a/pyalgotrading/algobulls/connection.py +++ b/pyalgotrading/algobulls/connection.py @@ -81,6 +81,31 @@ def set_access_token(self, access_token): assert isinstance(access_token, str), f'Argument "access_token" should be a string' self.api.set_access_token(access_token) + def set_generative_ai_keys(self, api_key, secret_key, token_key): + """ + Set the API keys of the generative AI took used + + Args: + api_key: api key name + # todo: learn about different generative AIs and how many and what keys are required ? + # also confirm with backend the format of API keys to be received + """ + + return 'SUCCESS' or 'FAILURE' + + def generate_strategy(self): + input_prompt = str(input()) + + # call the api + + return # strategy in strings + + def save_latest_generated_strategy(self): + pass + + def view_recent_chat_history(self): + pass + def create_strategy(self, strategy, overwrite=False, strategy_code=None, abc_version=None): """ Method to upload new strategy. From 3431c5860e1f79cb748d8b6667ea6cb56ece813d Mon Sep 17 00:00:00 2001 From: om-khade-algobulls Date: Tue, 15 Aug 2023 19:43:11 +0530 Subject: [PATCH 02/11] Add GenAI chat feature --- pyalgotrading/algobulls/api.py | 46 +++++++++++++++++++++++++ pyalgotrading/algobulls/connection.py | 49 ++++++++++++++++++++++++--- 2 files changed, 90 insertions(+), 5 deletions(-) diff --git a/pyalgotrading/algobulls/api.py b/pyalgotrading/algobulls/api.py index 48575489..7979d387 100644 --- a/pyalgotrading/algobulls/api.py +++ b/pyalgotrading/algobulls/api.py @@ -30,6 +30,8 @@ def __init__(self, connection): self.__key_papertrading = {} # strategy-cstc_id mapping self.__key_realtrading = {} # strategy-cstc_id mapping self.pattern = re.compile(r'(? 20: + self.continue_from_previous_session(page_no=page_no + 1) + elif user_input.isdigit() and 1 <= int(user_input) <= len(customer_genai_sessions): + selected_session_index = page_no + int(user_input) - 1 + selected_session_id = customer_genai_sessions[selected_session_index]["id"] + self.api.genai_api_key = selected_session_id + + def initiate_chat(self, start_fresh=None, chat_gpt_model=None): + if start_fresh: + # reset session + self.api.genai_api_key = None + elif start_fresh is not None: + self.continue_from_previous_session(page_no=1) + + self.start_chat(chat_gpt_model) def save_latest_generated_strategy(self): pass From d5bada52503fb0a0bf6dfe5297878497df9145eb Mon Sep 17 00:00:00 2001 From: om-khade-algobulls Date: Wed, 16 Aug 2023 13:53:35 +0530 Subject: [PATCH 03/11] update --- pyalgotrading/algobulls/api.py | 16 ++++---- pyalgotrading/algobulls/connection.py | 55 ++++++++++++++++----------- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/pyalgotrading/algobulls/api.py b/pyalgotrading/algobulls/api.py index 7979d387..31e58fa8 100644 --- a/pyalgotrading/algobulls/api.py +++ b/pyalgotrading/algobulls/api.py @@ -13,6 +13,8 @@ from ..constants import TradingType, TradingReportType from ..utils.func import get_raw_response +GENAI_SESSION_SIZE = 100 + class AlgoBullsAPI: """ @@ -476,13 +478,12 @@ def get_reports(self, strategy_code: str, trading_type: TradingType, report_type return response - def get_genai(self, user_prompt: str, session_id: int, chat_gpt_model: str = ''): + def get_genai_response(self, user_prompt: str, chat_gpt_model: str = ''): """ Fetch GenAI response. Args: user_prompt: User question - session_id: Session id of the GenAI session chat_gpt_model: Chat gpt model name Returns: GenAI response @@ -491,12 +492,13 @@ def get_genai(self, user_prompt: str, session_id: int, chat_gpt_model: str = '') `GET` v1/build/python/genai Get GenAI response """ endpoint = 'v1/build/python/genai' - params = {"userPrompt": user_prompt, 'sessionId': self.genai_session_id, 'openaiApiKey': self.genai_api_key, 'chat_gpt_model': chat_gpt_model} + params = {"userPrompt": user_prompt, 'sessionId': self.genai_session_id, 'openaiApiKey': self.genai_api_key, 'chatGPTModel': chat_gpt_model} response = self._send_request(endpoint=endpoint, params=params) - + if self.genai_session_id is None and 'session_id' in response: + self.genai_session_id = response['session_id'] return response - def get_genai_response(self): + def handle_genai_response_timeout(self): """ Fetch GenAI response. @@ -513,9 +515,9 @@ def get_genai_response(self): return response - def get_genai_sessions(self, page_no): + def get_genai_sessions(self): endpoint = 'v1/build/python/genai/sessions' - params = {'sessionId': self.genai_session_id} + params = {'sessionId': self.genai_session_id, 'pageSize': GENAI_SESSION_SIZE} response = self._send_request(endpoint=endpoint, params=params) return response diff --git a/pyalgotrading/algobulls/connection.py b/pyalgotrading/algobulls/connection.py index aa01ae5b..48c88c21 100644 --- a/pyalgotrading/algobulls/connection.py +++ b/pyalgotrading/algobulls/connection.py @@ -19,6 +19,8 @@ from ..strategy.strategy_base import StrategyBase from ..utils.func import get_valid_enum_names, get_datetime_with_tz +GENAI_RESPONSE_POOLING_LIMIT = 20 + class AlgoBullsConnection: """ @@ -94,48 +96,57 @@ def set_generative_ai_keys(self, api_key, secret_key, token_key): self.api.openai_key = api_key return 'SUCCESS' or 'FAILURE' + def get_genai_response_pooling(self, no_of_tries, user_prompt, chat_gpt_model): + if no_of_tries < GENAI_RESPONSE_POOLING_LIMIT: + try: + if no_of_tries > 1: + response = self.api.get_genai_response(user_prompt, chat_gpt_model) + else: + response = self.api.handle_genai_response_timeout() + + except AlgoBullsAPIGatewayTimeoutErrorException: + response = self.get_genai_response_pooling(no_of_tries + 1) + else: + response = {'message': 'Somthing went wrong please try again'} + return response + def start_chat(self, chat_gpt_model): while True: user_prompt = str(input()) if user_prompt.lower() == 'exit': print("Thanks for the chat") return - - response = self.api.get_genai(user_prompt, chat_gpt_model) - while response['status_code'] == 504: - response = self.api.get_genai_response() - + response = self.get_genai_response_pooling(1, user_prompt, chat_gpt_model) print(f"GenAI: {response['message']}") - def continue_from_previous_session(self, page_no): + def continue_from_previous_sessions(self): """ display previous sessions Returns: """ - customer_genai_sessions = self.api.get_genai_sessions(page_no) + customer_genai_sessions = self.api.get_genai_sessions() for i, session in enumerate(customer_genai_sessions): - print(f"Session {i}: ID: {session['id']}, Started: {session['last_user_prompt']}") - - if len(customer_genai_sessions) < 20: - print("End") - else: - print(f"Type 'next' to view the next 20 sessions.") + print(f"Session {i}: Started: {session['timestamp_created']}, Title: {session['first_user_prompt']}") - user_input = input("Enter session number or 'next': ") - if user_input.lower() == "next" and len(customer_genai_sessions) > 20: - self.continue_from_previous_session(page_no=page_no + 1) - elif user_input.isdigit() and 1 <= int(user_input) <= len(customer_genai_sessions): - selected_session_index = page_no + int(user_input) - 1 - selected_session_id = customer_genai_sessions[selected_session_index]["id"] - self.api.genai_api_key = selected_session_id + while True: + user_input = int(input("Enter session number")) + if not isinstance(user_input, int): + print('Argument "user_input" should be a int') + elif 1 <= int(user_input) <= len(customer_genai_sessions): + selected_session_index = int(user_input) - 1 + selected_session_id = customer_genai_sessions[selected_session_index]["id"] + self.api.genai_session_id = selected_session_id + break + else: + print("Please select a valid session number.") def initiate_chat(self, start_fresh=None, chat_gpt_model=None): if start_fresh: # reset session - self.api.genai_api_key = None + self.api.genai_session_id = None elif start_fresh is not None: - self.continue_from_previous_session(page_no=1) + self.continue_from_previous_sessions() self.start_chat(chat_gpt_model) From 08ea257435180e7c5359cc54e3c6283918880781 Mon Sep 17 00:00:00 2001 From: om-khade-algobulls Date: Thu, 17 Aug 2023 20:11:03 +0530 Subject: [PATCH 04/11] update --- pyalgotrading/algobulls/api.py | 16 ++++++- pyalgotrading/algobulls/connection.py | 61 ++++++++++++++++----------- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/pyalgotrading/algobulls/api.py b/pyalgotrading/algobulls/api.py index 31e58fa8..b9704378 100644 --- a/pyalgotrading/algobulls/api.py +++ b/pyalgotrading/algobulls/api.py @@ -14,6 +14,7 @@ from ..utils.func import get_raw_response GENAI_SESSION_SIZE = 100 +GENAI_SESSION_HISTORY_SIZE = 100 class AlgoBullsAPI: @@ -34,6 +35,7 @@ def __init__(self, connection): self.pattern = re.compile(r'(? 1: - response = self.api.get_genai_response(user_prompt, chat_gpt_model) - else: response = self.api.handle_genai_response_timeout() + else: + response = self.api.get_genai_response(user_prompt, chat_gpt_model) except AlgoBullsAPIGatewayTimeoutErrorException: response = self.get_genai_response_pooling(no_of_tries + 1) @@ -110,51 +109,65 @@ def get_genai_response_pooling(self, no_of_tries, user_prompt, chat_gpt_model): response = {'message': 'Somthing went wrong please try again'} return response - def start_chat(self, chat_gpt_model): - while True: - user_prompt = str(input()) - if user_prompt.lower() == 'exit': - print("Thanks for the chat") - return - response = self.get_genai_response_pooling(1, user_prompt, chat_gpt_model) - print(f"GenAI: {response['message']}") - - def continue_from_previous_sessions(self): + def display_genai_sessions(self): """ display previous sessions Returns: - + available sessions """ customer_genai_sessions = self.api.get_genai_sessions() for i, session in enumerate(customer_genai_sessions): - print(f"Session {i}: Started: {session['timestamp_created']}, Title: {session['first_user_prompt']}") + print(f"Session {i + 1}: Started: {session['timestamp_created']}, Title: {session['first_user_prompt']}") + return customer_genai_sessions + def continue_from_previous_sessions(self): + + customer_genai_sessions = self.display_genai_sessions() while True: user_input = int(input("Enter session number")) if not isinstance(user_input, int): print('Argument "user_input" should be a int') elif 1 <= int(user_input) <= len(customer_genai_sessions): selected_session_index = int(user_input) - 1 - selected_session_id = customer_genai_sessions[selected_session_index]["id"] + selected_session_id = customer_genai_sessions[selected_session_index][0] self.api.genai_session_id = selected_session_id break else: print("Please select a valid session number.") - def initiate_chat(self, start_fresh=None, chat_gpt_model=None): + def get_session_history(self, session_id): + if not self.api.genai_sessions_map: + self.api.get_genai_sessions() + + customer_genai_session_history = self.api.get_genai_session_history(session_id) + for chat in customer_genai_session_history: + print(f"User: {chat['user_prompt']}") + print(f"GenAI: {chat['genai_response']}") + + def start_chat(self, start_fresh=None, session_id=None, chat_gpt_model=None): + + # This will set the session_id if start_fresh: # reset session self.api.genai_session_id = None elif start_fresh is not None: - self.continue_from_previous_sessions() - - self.start_chat(chat_gpt_model) + if session_id: + if self.api.genai_sessions_map is not None: + self.api.get_genai_sessions() + assert session_id in self.api.genai_sessions_map, f'Please selecta valid session id.' + self.api.genai_session_id = self.api.genai_sessions_map[session_id - 1][0] + else: + self.continue_from_previous_sessions() - def save_latest_generated_strategy(self): - pass + print("Session Start") + while True: + user_prompt = str(input()) + if user_prompt.lower() == 'exit': + print("Session End") + return - def view_recent_chat_history(self): - pass + response = self.get_genai_response_pooling(1, user_prompt, chat_gpt_model) + print(f"GenAI: {response['message']}") def create_strategy(self, strategy, overwrite=False, strategy_code=None, abc_version=None): """ From 4fbff0dce466d50847565ab4221956e2fe3a1e65 Mon Sep 17 00:00:00 2001 From: om-khade-algobulls Date: Fri, 18 Aug 2023 00:09:23 +0530 Subject: [PATCH 05/11] cleanup --- pyalgotrading/algobulls/api.py | 9 +++-- pyalgotrading/algobulls/connection.py | 57 +++++++++++++++------------ 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/pyalgotrading/algobulls/api.py b/pyalgotrading/algobulls/api.py index b9704378..b0c405dd 100644 --- a/pyalgotrading/algobulls/api.py +++ b/pyalgotrading/algobulls/api.py @@ -21,7 +21,8 @@ class AlgoBullsAPI: """ AlgoBulls API """ - SERVER_ENDPOINT = 'https://api.algobulls.com/' + SERVER_ENDPOINT = 'http://localhost:7003/' + # SERVER_ENDPOINT = 'https://api.algobulls.com/' def __init__(self, connection): """ @@ -525,11 +526,11 @@ def get_genai_sessions(self): response = self._send_request(endpoint=endpoint, params=params) self.genai_sessions_map = response['data'] - return response + return response['data'] def get_genai_session_history(self, session_id): endpoint = 'v1/build/python/genai/session/history' - params = {'session_id': self.genai_sessions_map[session_id - 1], 'pageSize': GENAI_SESSION_HISTORY_SIZE} + params = {'sessionId': self.genai_sessions_map[session_id - 1]['id'], 'pageSize': GENAI_SESSION_HISTORY_SIZE} response = self._send_request(endpoint=endpoint, params=params) - return response + return response['data'] diff --git a/pyalgotrading/algobulls/connection.py b/pyalgotrading/algobulls/connection.py index 5e4f8c94..757ce51a 100644 --- a/pyalgotrading/algobulls/connection.py +++ b/pyalgotrading/algobulls/connection.py @@ -83,19 +83,17 @@ def set_access_token(self, access_token): assert isinstance(access_token, str), f'Argument "access_token" should be a string' self.api.set_access_token(access_token) - def set_generative_ai_keys(self, api_key, secret_key, token_key): + def set_generative_ai_keys(self, genai_api_key): """ Set the API keys of the generative AI took used Args: - api_key: api key name - # todo: learn about different generative AIs and how many and what keys are required ? - # also confirm with backend the format of API keys to be received + genai_api_key: GenAI API key """ - assert isinstance(api_key, str), f'Argument "api_key" should be a string' - self.api.openai_key = api_key + assert isinstance(genai_api_key, str), f'Argument "api_key" should be a string' + self.api.genai_api_key = genai_api_key - def get_genai_response_pooling(self, no_of_tries, user_prompt, chat_gpt_model): + def get_genai_response_pooling(self, no_of_tries, user_prompt=None, chat_gpt_model=None): if no_of_tries < GENAI_RESPONSE_POOLING_LIMIT: try: if no_of_tries > 1: @@ -106,7 +104,7 @@ def get_genai_response_pooling(self, no_of_tries, user_prompt, chat_gpt_model): except AlgoBullsAPIGatewayTimeoutErrorException: response = self.get_genai_response_pooling(no_of_tries + 1) else: - response = {'message': 'Somthing went wrong please try again'} + response = {"message": "Somthing went wrong please try again"} return response def display_genai_sessions(self): @@ -116,12 +114,16 @@ def display_genai_sessions(self): available sessions """ customer_genai_sessions = self.api.get_genai_sessions() - for i, session in enumerate(customer_genai_sessions): - print(f"Session {i + 1}: Started: {session['timestamp_created']}, Title: {session['first_user_prompt']}") + df = pd.DataFrame(customer_genai_sessions) + df.index += 1 + + if customer_genai_sessions: + df.drop(columns=["id"], inplace=True) + print(tabulate(df, headers=["id", "Timestamp Created", "Title"], tablefmt="pretty")) + return customer_genai_sessions def continue_from_previous_sessions(self): - customer_genai_sessions = self.display_genai_sessions() while True: user_input = int(input("Enter session number")) @@ -135,17 +137,20 @@ def continue_from_previous_sessions(self): else: print("Please select a valid session number.") - def get_session_history(self, session_id): + def display_session_chat_history(self, session_id): if not self.api.genai_sessions_map: self.api.get_genai_sessions() customer_genai_session_history = self.api.get_genai_session_history(session_id) - for chat in customer_genai_session_history: - print(f"User: {chat['user_prompt']}") - print(f"GenAI: {chat['genai_response']}") + if customer_genai_session_history: + for chat in customer_genai_session_history: + print(f"User:\n{chat['user_prompt']}", end="\n\n") + print(f"GenAI:\n{chat['genai_response']}", end=f"\n\n{'-' * 50}\n\n") + else: + print(f"No available chat history for session id: {session_id}") def start_chat(self, start_fresh=None, session_id=None, chat_gpt_model=None): - + assert self.api.genai_api_key, f"Please set your GenAI key using set_generative_ai_keys()" # This will set the session_id if start_fresh: # reset session @@ -154,20 +159,22 @@ def start_chat(self, start_fresh=None, session_id=None, chat_gpt_model=None): if session_id: if self.api.genai_sessions_map is not None: self.api.get_genai_sessions() - assert session_id in self.api.genai_sessions_map, f'Please selecta valid session id.' + assert session_id in self.api.genai_sessions_map, f"Please selecta valid session id." self.api.genai_session_id = self.api.genai_sessions_map[session_id - 1][0] else: self.continue_from_previous_sessions() - print("Session Start") + print("Session Start", end="\n\n") while True: - user_prompt = str(input()) - if user_prompt.lower() == 'exit': - print("Session End") - return - - response = self.get_genai_response_pooling(1, user_prompt, chat_gpt_model) - print(f"GenAI: {response['message']}") + print("Enter 'Exit' to exit the session.") + user_prompt = str(input("Enter query: ")) + if user_prompt: + if user_prompt.lower() == "exit": + print("Session End") + return + + response = self.get_genai_response_pooling(1, user_prompt, chat_gpt_model) + print(f"GenAI: {response['message']}", end="\n\n") def create_strategy(self, strategy, overwrite=False, strategy_code=None, abc_version=None): """ From c892e3aaa7e4887cc5f718326209f215413a01f4 Mon Sep 17 00:00:00 2001 From: om-khade-algobulls Date: Sat, 19 Aug 2023 17:16:38 +0530 Subject: [PATCH 06/11] Add GenAI Strategy save method --- pyalgotrading/algobulls/api.py | 44 +++++++++++++++++++++------ pyalgotrading/algobulls/connection.py | 39 ++++++++++++++++++++++-- pyalgotrading/algobulls/exceptions.py | 9 ++++++ 3 files changed, 80 insertions(+), 12 deletions(-) diff --git a/pyalgotrading/algobulls/api.py b/pyalgotrading/algobulls/api.py index b0c405dd..3ee76883 100644 --- a/pyalgotrading/algobulls/api.py +++ b/pyalgotrading/algobulls/api.py @@ -9,7 +9,7 @@ import requests from .exceptions import AlgoBullsAPIBaseException, AlgoBullsAPIUnauthorizedErrorException, AlgoBullsAPIInsufficientBalanceErrorException, AlgoBullsAPIResourceNotFoundErrorException, AlgoBullsAPIBadRequestException, \ - AlgoBullsAPIInternalServerErrorException, AlgoBullsAPIForbiddenErrorException, AlgoBullsAPIGatewayTimeoutErrorException + AlgoBullsAPIInternalServerErrorException, AlgoBullsAPIForbiddenErrorException, AlgoBullsAPIGatewayTimeoutErrorException, AlgoBullsAPITooManyRequestsException from ..constants import TradingType, TradingReportType from ..utils.func import get_raw_response @@ -34,7 +34,6 @@ def __init__(self, connection): self.__key_papertrading = {} # strategy-cstc_id mapping self.__key_realtrading = {} # strategy-cstc_id mapping self.pattern = re.compile(r'(? Date: Sat, 19 Aug 2023 18:47:16 +0530 Subject: [PATCH 07/11] cleanup --- pyalgotrading/algobulls/connection.py | 40 +++++++++++++++------------ 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/pyalgotrading/algobulls/connection.py b/pyalgotrading/algobulls/connection.py index fbbd0816..868dcfb9 100644 --- a/pyalgotrading/algobulls/connection.py +++ b/pyalgotrading/algobulls/connection.py @@ -14,7 +14,7 @@ from tqdm.auto import tqdm from .api import AlgoBullsAPI -from .exceptions import AlgoBullsAPIBadRequestException, AlgoBullsAPIGatewayTimeoutErrorException +from .exceptions import AlgoBullsAPIBadRequestException, AlgoBullsAPIGatewayTimeoutErrorException, AlgoBullsAPIForbiddenErrorException from ..constants import StrategyMode, TradingType, TradingReportType, CandleInterval, AlgoBullsEngineVersion, Country, ExecutionStatus, EXCHANGE_LOCALE_MAP, Locale from ..strategy.strategy_base import StrategyBase from ..utils.func import get_valid_enum_names, get_datetime_with_tz @@ -33,10 +33,7 @@ def __init__(self): """ self.api = AlgoBullsAPI(self) - self.saved_parameters = { - 'start_timestamp_map': {}, - 'end_timestamp_map': {} - } + self.saved_parameters = {"start_timestamp_map": {}, "end_timestamp_map": {}} self.strategy_country_map = { TradingType.BACKTESTING: {}, @@ -47,6 +44,7 @@ def __init__(self): self.backtesting_pnl_data = None self.papertrade_pnl_data = None self.realtrade_pnl_data = None + self.recent_genai_response = None @staticmethod def get_authorization_url(): @@ -56,8 +54,8 @@ def get_authorization_url(): Returns: Authorization URL """ - url = 'https://app.algobulls.com/user/login' - print(f'Please login to this URL with your AlgoBulls credentials and get your developer access token: {url}') + url = "https://app.algobulls.com/user/login" + print(f"Please login to this URL with your AlgoBulls credentials and get your developer access token: {url}") @staticmethod def get_token_url(): @@ -67,8 +65,8 @@ def get_token_url(): Returns: Token URL """ - url = 'https://app.algobulls.com/settings?section=developerOptions' - print(f'Please login to this URL to get your unique token: {url}') + url = "https://app.algobulls.com/settings?section=developerOptions" + print(f"Please login to this URL to get your unique token: {url}") def set_access_token(self, access_token): """ @@ -143,7 +141,7 @@ def display_session_chat_history(self, session_id): customer_genai_session_history = self.api.get_genai_session_history(session_id) if customer_genai_session_history: - for chat in customer_genai_session_history: + for chat in customer_genai_session_history[::-1]: print(f"User:\n{chat['user_prompt']}", end="\n\n") print(f"GenAI:\n{chat['genai_response']}", end=f"\n\n{'-' * 50}\n\n") else: @@ -168,22 +166,27 @@ def start_chat(self, start_fresh=None, session_id=None, chat_gpt_model=None): print("Session Start", end="\n\n") while True: - print("Enter 'Exit' to exit the session.") - user_prompt = str(input("Enter query: ")) + print("Enter 'Save' to save the Strategy. Enter 'Exit' to exit the session.", end="\r") + user_prompt = str(input("Enter query: ")).lower() if user_prompt: - if user_prompt.lower() == "exit": + if user_prompt == "exit": print("Session End") return - print("Please wait your request is being precessed.") + if user_prompt == 'save': + strategy_name = str(input("Input a Strategy Name")) + return self.save_last_generated_strategy(strategy_name=strategy_name) + return + + print("Please wait your request is being precessed.", end='\r') response = self.get_genai_response_pooling(1, user_prompt, chat_gpt_model) if not response: break self.recent_genai_response = response['message'] - print(f"GenAI: {response['message']}", end="\n\n") + print(f"\nGenAI: {response['message']}", end=f"\n\n{'-' * 50}\n\n") - def save_last_generated_strategy(self, strategy_code=None, strategy_name=None): + def save_last_generated_strategy(self, strategy_name=None, strategy_code=None): if self.recent_genai_response or strategy_code: strategy_name = strategy_name or f'GenAI Strategy-{time.time():.0f}' strategy_details = strategy_code or self.recent_genai_response @@ -205,9 +208,12 @@ def save_last_generated_strategy(self, strategy_code=None, strategy_name=None): strategy_details = code_matches[0] response = self.api.create_strategy(strategy_name=strategy_name, strategy_details=strategy_details, abc_version='3.3.3') + if response: + self.recent_genai_response = None return response + else: - print("Please generate a GenAI strategy") + print("Warning: Please generate a strategy using GenAI before saving.") def create_strategy(self, strategy, overwrite=False, strategy_code=None, abc_version=None): """ From 35e5b4658126e0128c86f854eaa853de79bcede8 Mon Sep 17 00:00:00 2001 From: om-khade-algobulls Date: Sat, 19 Aug 2023 21:14:58 +0530 Subject: [PATCH 08/11] add doc string --- pyalgotrading/algobulls/api.py | 46 +++++++++++++++++ pyalgotrading/algobulls/connection.py | 71 ++++++++++++++++++++++++++- 2 files changed, 116 insertions(+), 1 deletion(-) diff --git a/pyalgotrading/algobulls/api.py b/pyalgotrading/algobulls/api.py index 3ee76883..7e08d94a 100644 --- a/pyalgotrading/algobulls/api.py +++ b/pyalgotrading/algobulls/api.py @@ -22,6 +22,7 @@ class AlgoBullsAPI: AlgoBulls API """ SERVER_ENDPOINT = 'http://localhost:7003/' + # SERVER_ENDPOINT = 'https://api.algobulls.com/' def __init__(self, connection): @@ -484,12 +485,37 @@ def get_reports(self, strategy_code: str, trading_type: TradingType, report_type return response def set_genai_api_key(self, genai_api_key): + """ + Set GenAI Api key + + This API is used to set GenAI API key. + + Args: + genai_api_key: GenAI api key + Returns: + response + + Info: ENDPOINT + `GET` v1/build/python/genai/key + """ endpoint = 'v1/build/python/genai/key' json_data = {"openaiApiKey": genai_api_key} response = self._send_request(method='post', endpoint=endpoint, json_data=json_data) return response def get_genai_api_key_status(self): + """ + Gen GenAI Api key status + + This API is used to check if user has set GenAI API key. + + Args: + Returns: + response + + Info: ENDPOINT + `GET` v1/build/python/genai/key + """ endpoint = f'v1/build/python/genai/key' response = self._send_request(endpoint=endpoint) return response @@ -547,6 +573,16 @@ def handle_genai_response_timeout(self): return response def get_genai_sessions(self): + """ + Fetch GenAI sessions. + + Args: + Returns: + GenAI sessions for the customer. + + Info: ENDPOINT + `GET` v1/build/python/genai/sessions + """ endpoint = 'v1/build/python/genai/sessions' params = {'session_id': self.genai_session_id, 'pageSize': GENAI_SESSION_SIZE} response = self._send_request(endpoint=endpoint, params=params) @@ -555,6 +591,16 @@ def get_genai_sessions(self): return response['data'] def get_genai_session_history(self, session_id): + """ + Fetch GenAI session history. + + Args: + Returns: + GenAI session history for the customer. + + Info: ENDPOINT + `GET` v1/build/python/genai/session/history + """ endpoint = 'v1/build/python/genai/session/history' params = {'sessionId': self.genai_sessions_map[session_id - 1]['id'], 'pageSize': GENAI_SESSION_HISTORY_SIZE} response = self._send_request(endpoint=endpoint, params=params) diff --git a/pyalgotrading/algobulls/connection.py b/pyalgotrading/algobulls/connection.py index 868dcfb9..d83c88a4 100644 --- a/pyalgotrading/algobulls/connection.py +++ b/pyalgotrading/algobulls/connection.py @@ -87,11 +87,28 @@ def set_generative_ai_keys(self, genai_api_key): Args: genai_api_key: GenAI API key + + Returns: + None """ assert isinstance(genai_api_key, str), f'Argument "api_key" should be a string' self.api.set_genai_api_key(genai_api_key) def get_genai_response_pooling(self, no_of_tries, user_prompt=None, chat_gpt_model=None): + """ + Method to get GenAI response + + During first execution get_genai_response API is fired and for next consecutive calls handle_genai_response_timeout API is fired + till we get a response other than AlgoBullsAPIGatewayTimeoutErrorException or GENAI_RESPONSE_POOLING_LIMIT is reached. + + Args: + no_of_tries: No of times this function is called recursively + user_prompt: User question + chat_gpt_model: OpenAI chat model name + + Returns: + GenAI response + """ if no_of_tries < GENAI_RESPONSE_POOLING_LIMIT: try: if no_of_tries > 1: @@ -107,7 +124,7 @@ def get_genai_response_pooling(self, no_of_tries, user_prompt=None, chat_gpt_mod def display_genai_sessions(self): """ - display previous sessions + Display previous sessions Returns: available sessions """ @@ -122,6 +139,12 @@ def display_genai_sessions(self): return customer_genai_sessions def continue_from_previous_sessions(self): + """ + Let user select from displayed sessions + + Returns: + None + """ customer_genai_sessions = self.display_genai_sessions() while True: user_input = int(input("Enter session number")) @@ -136,6 +159,15 @@ def continue_from_previous_sessions(self): print("Please select a valid session number.") def display_session_chat_history(self, session_id): + """ + Display Chat history for given session + + Args: + session_id: session id + + Returns: + None + """ if not self.api.genai_sessions_map: self.api.get_genai_sessions() @@ -148,6 +180,26 @@ def display_session_chat_history(self, session_id): print(f"No available chat history for session id: {session_id}") def start_chat(self, start_fresh=None, session_id=None, chat_gpt_model=None): + """ + Start chat with GenAI + + If start_fresh is True - + New session is started + If start_fresh is False - + If session_id is None + All available sessions are displayed and user is can select from available sessions. + If session_id is given + Session linked with given session id is used + + Args: + start_fresh: strategy name + session_id: strategy python code + chat_gpt_model: OpenAI chat model name + + Returns: + None + """ + response = self.api.get_genai_api_key_status() assert response['key_available'], f"Please set your GenAI key using set_generative_ai_keys()" @@ -187,6 +239,23 @@ def start_chat(self, start_fresh=None, session_id=None, chat_gpt_model=None): print(f"\nGenAI: {response['message']}", end=f"\n\n{'-' * 50}\n\n") def save_last_generated_strategy(self, strategy_name=None, strategy_code=None): + """ + Method to save last generated genai response as strategy + + User can either pass strategy code as a parameter our use last saved genai response to save strategy. + + All strategies are unique by name, per customer. + If customer tries to upload strategy with the same name as an already existing strategy + - AlgoBullsAPIBadRequest Exception will be thrown. No change would be done in the backend database. + + Args: + strategy_name: strategy name + strategy_code: strategy python code + + Returns: + Dictionary containing strategy name, strategy_id and cstc_id + """ + if self.recent_genai_response or strategy_code: strategy_name = strategy_name or f'GenAI Strategy-{time.time():.0f}' strategy_details = strategy_code or self.recent_genai_response From 073d0dbcc0843795a4fcac17eea25847cf9b4603 Mon Sep 17 00:00:00 2001 From: om-khade-algobulls Date: Sun, 20 Aug 2023 12:11:59 +0530 Subject: [PATCH 09/11] cleanup --- pyalgotrading/algobulls/connection.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyalgotrading/algobulls/connection.py b/pyalgotrading/algobulls/connection.py index d83c88a4..7d3bf1bf 100644 --- a/pyalgotrading/algobulls/connection.py +++ b/pyalgotrading/algobulls/connection.py @@ -33,7 +33,10 @@ def __init__(self): """ self.api = AlgoBullsAPI(self) - self.saved_parameters = {"start_timestamp_map": {}, "end_timestamp_map": {}} + self.saved_parameters = { + "start_timestamp_map": {} + , "end_timestamp_map": {} + } self.strategy_country_map = { TradingType.BACKTESTING: {}, From f2f68bc229f155698015c8bb81cbc0cf55bcc7a5 Mon Sep 17 00:00:00 2001 From: om-khade-algobulls Date: Sun, 20 Aug 2023 21:50:52 +0530 Subject: [PATCH 10/11] cleanup --- pyalgotrading/algobulls/api.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyalgotrading/algobulls/api.py b/pyalgotrading/algobulls/api.py index 7e08d94a..242a355b 100644 --- a/pyalgotrading/algobulls/api.py +++ b/pyalgotrading/algobulls/api.py @@ -21,9 +21,7 @@ class AlgoBullsAPI: """ AlgoBulls API """ - SERVER_ENDPOINT = 'http://localhost:7003/' - - # SERVER_ENDPOINT = 'https://api.algobulls.com/' + SERVER_ENDPOINT = 'https://api.algobulls.com/' def __init__(self, connection): """ @@ -595,6 +593,7 @@ def get_genai_session_history(self, session_id): Fetch GenAI session history. Args: + session_id: GenAI chat session id Returns: GenAI session history for the customer. From 8b12aca7c349d1d227c699f28ce17ec2c549c434 Mon Sep 17 00:00:00 2001 From: om-khade-algobulls Date: Sun, 20 Aug 2023 22:43:00 +0530 Subject: [PATCH 11/11] cleanup --- pyalgotrading/algobulls/api.py | 53 +-------------------------- pyalgotrading/algobulls/connection.py | 4 +- 2 files changed, 3 insertions(+), 54 deletions(-) diff --git a/pyalgotrading/algobulls/api.py b/pyalgotrading/algobulls/api.py index 242a355b..9080d12e 100644 --- a/pyalgotrading/algobulls/api.py +++ b/pyalgotrading/algobulls/api.py @@ -178,9 +178,6 @@ def create_strategy(self, strategy_name: str, strategy_details: str, abc_version Warning: For every user, the `strategy_name` should be unique. You cannot create multiple strategies with the same name. - - Info: ENDPOINT - `POST` v2/user/strategy/build/python """ try: @@ -206,9 +203,6 @@ def update_strategy(self, strategy_code: str, strategy_name: str, strategy_detai Returns: JSON Response received from AlgoBulls platform after (attempt to) updating an existing strategy. - - Info: ENDPOINT - PUT v2/user/strategy/build/python """ json_data = {'strategyId': strategy_code, 'strategyName': strategy_name, 'strategyDetails': strategy_details, 'abcVersion': abc_version} @@ -223,9 +217,6 @@ def get_all_strategies(self) -> dict: Returns: JSON Response received from AlgoBulls platform with list of all the created strategies. - - Info: ENDPOINT - `OPTIONS` v3/build/python/user/strategy/code """ endpoint = f'v3/build/python/user/strategy/code' @@ -242,9 +233,6 @@ def get_strategy_details(self, strategy_code: str) -> dict: Returns: JSON - - Info: ENDPOINT - `GET` v3/build/python/user/strategy/code/{strategy_code} """ params = {} @@ -263,9 +251,6 @@ def search_instrument(self, tradingsymbol: str, exchange: str) -> dict: Returns: JSON Response - - INFO: ENDPOINT - `GET` v4/portfolio/searchInstrument """ params = {'search': tradingsymbol, 'exchange': exchange} @@ -283,9 +268,6 @@ def delete_previous_trades(self, strategy: str): Returns: response: response from api - - Info: ENDPOINT - `DELETE` v3/build/python/user/strategy/deleteAll?strategyId={strategy} """ endpoint = f'v3/build/python/user/strategy/deleteAll?strategyId={strategy}' @@ -303,9 +285,6 @@ def set_strategy_config(self, strategy_code: str, strategy_config: dict, trading trading_type: BACKTESTING, PAPER TRADING or REAL TRADING Returns: - - Info: ENDPOINT - `POST` v4/portfolio/tweak/{key}/?isPythonBuild=true """ # Configure the params @@ -330,9 +309,6 @@ def start_strategy_algotrading(self, strategy_code: str, start_timestamp: dt, en location: Location of the exchange initial_funds_virtual: Virtual funds before starting the strategy broker_details: Client's broking details - - Info: ENDPOINT - `PATCH` v5/portfolio/strategies?isPythonBuild=true """ try: @@ -404,9 +380,6 @@ def get_job_status(self, strategy_code: str, trading_type: TradingType) -> dict: Returns: Job status - - Info: ENDPOINT - `GET` v2/user/strategy/status """ key = self.__get_key(strategy_code=strategy_code, trading_type=trading_type) @@ -428,9 +401,6 @@ def get_logs(self, strategy_code: str, trading_type: TradingType, log_type: str, Returns: Execution logs - - Info: ENDPOINT - `POST`: v2/user/strategy/logs """ key = self.__get_key(strategy_code=strategy_code, trading_type=trading_type) params = None @@ -460,11 +430,6 @@ def get_reports(self, strategy_code: str, trading_type: TradingType, report_type Returns: Report data - - Info: ENDPOINT - `GET` v2/user/strategy/pltable for P&L Table - `GET` v2/user/strategy/statstable for Stats Table - `GET` v2/user/strategy/orderhistory Order History """ key = self.__get_key(strategy_code=strategy_code, trading_type=trading_type) @@ -486,15 +451,10 @@ def set_genai_api_key(self, genai_api_key): """ Set GenAI Api key - This API is used to set GenAI API key. - Args: genai_api_key: GenAI api key Returns: response - - Info: ENDPOINT - `GET` v1/build/python/genai/key """ endpoint = 'v1/build/python/genai/key' json_data = {"openaiApiKey": genai_api_key} @@ -507,12 +467,8 @@ def get_genai_api_key_status(self): This API is used to check if user has set GenAI API key. - Args: Returns: response - - Info: ENDPOINT - `GET` v1/build/python/genai/key """ endpoint = f'v1/build/python/genai/key' response = self._send_request(endpoint=endpoint) @@ -527,9 +483,6 @@ def get_genai_response(self, user_prompt: str, chat_gpt_model: str = ''): chat_gpt_model: Chat gpt model name Returns: GenAI response - - Info: ENDPOINT - `GET` v1/build/python/genai Get GenAI response """ endpoint = 'v1/build/python/genai' params = {"userPrompt": user_prompt, 'sessionId': self.genai_session_id, 'chatGPTModel': chat_gpt_model} @@ -549,12 +502,8 @@ def handle_genai_response_timeout(self): """ Fetch GenAI response. - Args: Returns: - GenAI response for current session. Last active session is used when session_id is None. - - Info: ENDPOINT - `GET` v1/build/python/genai/response Pooling API to get response in case of timeout + GenAI response for current session. Last active session is used when self.session_id is None. """ endpoint = 'v1/build/python/genai/response' params = {'session_id': self.genai_session_id} diff --git a/pyalgotrading/algobulls/connection.py b/pyalgotrading/algobulls/connection.py index 7d3bf1bf..e27eb24a 100644 --- a/pyalgotrading/algobulls/connection.py +++ b/pyalgotrading/algobulls/connection.py @@ -34,8 +34,8 @@ def __init__(self): self.api = AlgoBullsAPI(self) self.saved_parameters = { - "start_timestamp_map": {} - , "end_timestamp_map": {} + "start_timestamp_map": {}, + "end_timestamp_map": {} } self.strategy_country_map = {