{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "0PSrErguxVcn" }, "source": [ "### Brief Description\n", "\n", "This notebook shows few examples on how to leverage OpenBB functionality via an Agent built with Langchain.\n", "It requires the user to have\n", "- an OpenAI Key. This is required as OpenAI is used as LLM\n", "\n", "\n", "For help on how to configure Colab Secrets, please refer to this article\n", "https://margaretmz.medium.com/use-colab-secrets-to-store-kaggle-api-key-b57c7464f9fa\n", "\n", "This work was inspired by examples from this repo https://github.com/AlgoTrading101/Magentic-AlgoTrading101\n", "\n", "Functionality shown in this notebook is purely an example of what can be done.\n", "\n", "### Author\n", "Marco Mistroni" ] }, { "cell_type": "markdown", "source": [ "### Installing dependencies" ], "metadata": { "id": "pw_DrWCXVijQ" } }, { "cell_type": "code", "source": [ "!pip install openbb\n", "!pip install openbb-yfinance\n", "!pip install openbb-finviz\n", "!pip install langchain\n", "!pip install langchain_core\n", "!pip install langchain_openai\n" ], "metadata": { "id": "sNhm_dyvVlI1" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "### Getting keys" ], "metadata": { "id": "Ua8Hmj2lWI6R" } }, { "cell_type": "code", "source": [ "from google.colab import userdata\n", "OPENAI_KEY = userdata.get('OPENAI_KEY')" ], "metadata": { "id": "fTUdeQpdWL81" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "TEBnI33fxVcr" }, "outputs": [], "source": [ "import os\n", "from openbb import obb\n", "from langchain_openai import ChatOpenAI\n", "import logging\n", "from langchain.agents import tool\n", "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", "\n", "llm = ChatOpenAI(model=\"gpt-4.1\", temperature=0, openai_api_key=OPENAI_KEY)" ] }, { "cell_type": "markdown", "metadata": { "id": "6zNCxSmOxVct" }, "source": [ "### OpenBB Useful functions" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "28N-T7aIxVcu" }, "outputs": [], "source": [ "@tool\n", "def get_industry_performance() -> list:\n", " \"\"\" Return performance by industry for last week, last month, last quarter, last half year and last year\"\"\"\n", " return obb.equity.compare.groups(group='industry', metric='performance').to_llm()\n", "\n", "@tool\n", "def get_strong_buy_for_sector(sector : str) -> list :\n", " \"\"\" Return the strong buy recommendation for a given sector\"\"\"\n", " new_sector = '_'.join(sector.lower().split()).lower()\n", " data = obb.equity.screener(provider='finviz', sector=new_sector, recommendation='buy')\n", " return data.to_llm()\n", "\n", "@tool\n", "def get_strong_buy_for_industry(industry : str) -> list :\n", " \"\"\" Return the strong buy recommendation for a given industry\"\"\"\n", " data = obb.equity.screener(provider='finviz', industry=industry, recommendation='buy')\n", " return data.to_llm()\n", "\n", "@tool\n", "def get_best_stock_performers_for_sector(sector:str) -> list :\n", " \"\"\" Return the best 5 stock performers for last week and last month for a given sector\"\"\"\n", " data = obb.equity.screener(provider='finviz', filters_dict={'Sector' : sector, 'Performance' : 'Week Up', 'Performance 2' : 'Month Up'}, limit=5)\n", " return data.to_llm()\n", "\n", "@tool\n", "def get_best_stock_performers_for_industry(industry:str) -> list :\n", " \"\"\" Return the best 5 stock performers for last week and last month for an industry\"\"\"\n", " data = obb.equity.screener(provider='finviz', filters_dict={'Industry' : industry, 'Performance' : 'Week Up', 'Performance 2' : 'Month Up'}, limit=3)\n", " return data.to_llm()\n", "\n", "@tool\n", "def get_candidate_stocks_to_invest_relaxed(industry:str) -> list:\n", " ''' Use relaxed criteria to find best companies in an industry which are worth investing into'''\n", " desc_filters = {\n", " 'Market Cap.': '+Small (over $300mln)',\n", " 'Average Volume': 'Over 200K',\n", " }\n", " fund_filters = {\n", " 'InstitutionalOwnership': 'Under 60%',\n", " 'Current Ratio' : 'Over 1.5',\n", " 'Debt/Equity' : 'Over 0.3',\n", " #'EPS growthnext 5 years' : 'Positive (>0%)',\n", " }\n", "\n", " desc_filters.update(fund_filters)\n", "\n", " try:\n", " data = obb.equity.screener(provider='finviz', industry='semiconductors',\n", " filters_dict=desc_filters\n", " )\n", " return data.to_llm()\n", " except Exception as e:\n", " logging.info(f'No data found:{str(e)}')\n", " return []\n", "\n", "\n", "@tool\n", "def get_valuation_for_industries(input:str) -> list:\n", " \"\"\" Return valuation metrics for the industry provided as input\"\"\"\n", " data = obb.equity.compare.groups(group='industry', metric='valuation', provider='finviz').to_df()\n", " filtered = data[data.name == input]\n", " return filtered.to_json(\n", " orient=\"records\",\n", " date_format=\"iso\",\n", " date_unit=\"s\",\n", " )\n", "\n", "@tool\n", "def get_consensus(ticker:str) -> list:\n", " \"\"\" Return analyst consensus for the ticker provided\n", " It returns the following fields:\n", " - target_high: float, High target of the price target consensus.\n", " - target_low: float Low target of the price target consensus.\n", " - target_consensus: float Consensus target of the price target consensus.\n", " - target_median: float Median target of the price target consensus\n", "\n", "\n", " \"\"\"\n", " data = obb.equity.estimates.consensus(symbol=ticker, limit=3, provider='yfinance').to_df()\n", " return data.to_json(\n", " orient=\"records\",\n", " date_format=\"iso\",\n", " date_unit=\"s\",\n", " )\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "id": "1hXQnSGFxVcv" }, "source": [ "### Chat Memory" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "YBF6S6DxxVcv" }, "outputs": [], "source": [ "from langchain_core.prompts import MessagesPlaceholder\n", "from langchain.memory import ConversationTokenBufferMemory\n", "from langchain.agents.format_scratchpad.openai_tools import (\n", " format_to_openai_tool_messages,\n", ")\n", "from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser\n", "from langchain_core.output_parsers import StrOutputParser, CommaSeparatedListOutputParser\n", "from langchain.agents import AgentExecutor\n", "from langchain_core.messages import AIMessage, HumanMessage\n", "\n", "MEMORY_KEY = \"chat_history\"\n", "prompt = ChatPromptTemplate.from_messages(\n", " [\n", " (\n", " \"system\",\n", " \"\"\" You are very powerful stock financial researcher.\n", " You will take the user questions and answer using the tools available.\n", " Once you have the information you need, you will answer user's questions using the data returned.\n", " Use the following tools to answer user queries:\n", " - get_strong_buy_for_sector to find strong buy recommendations for a sector\n", " - get_strong_buy_for_industry to find strong buy recommendations for an industry\n", " - get_industry_performance to find the performance for an industry\n", " - get_valuation_for_industries to find valuation metrics for industries\n", " - get_candidate_stocks_to_invest_relaxed to fetch all companies using relaxed criteria\n", " - def get_consensus(ticker:str) - to find analyst consensus for a company\n", " You should call each function only once, and you should not call the function if you already have the information you need.\n", " \"\"\",\n", " ),\n", " MessagesPlaceholder(variable_name=MEMORY_KEY),\n", " (\"user\", \"{input}\"),\n", " MessagesPlaceholder(variable_name=\"agent_scratchpad\"),\n", " ]\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "1yrlv9jUxVcw" }, "outputs": [], "source": [ "tools = [get_industry_performance, get_strong_buy_for_sector, get_strong_buy_for_industry, get_best_stock_performers_for_industry, get_valuation_for_industries,\n", " get_candidate_stocks_to_invest_relaxed, get_consensus]\n", "llm_with_tools = llm.bind_tools(tools)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ToVLUWZfxVcw" }, "outputs": [], "source": [ "chat_history = []\n", "chat_history.append(HumanMessage(content=\"Your question here\"))\n", "chat_history.append(AIMessage(content=\"AI response here\"))\n", "memory = ConversationTokenBufferMemory(\n", " llm=llm, # Required for token counting\n", " max_token_limit=16000, # Leave buffer for functions + responses\n", " memory_key=\"chat_history\", # Must match your prompt's key\n", " return_messages=True\n", ")\n", "\n", "agent = (\n", " {\n", " \"input\": lambda x: x[\"input\"],\n", " \"agent_scratchpad\": lambda x: format_to_openai_tool_messages(\n", " x[\"intermediate_steps\"]\n", " ),\n", " \"chat_history\": lambda x: memory.load_memory_variables(x)[\"chat_history\"],\n", " }\n", " | prompt\n", " | llm_with_tools\n", " | OpenAIToolsAgentOutputParser()\n", ")\n", "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)" ] }, { "cell_type": "markdown", "metadata": { "id": "kbFXeyMUxVcy" }, "source": [ "### Let's try a chain of thought approach. We start with the industry with best performance.\n", "Then find the best performing company and check some metrics" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "MlAvYHU0xVcy" }, "outputs": [], "source": [ "input1 = '''\n", "First, find an industry that has consistently shown positive performance across quarterly, monthly, and weekly timeframes.\n", "Second, once you have identified the industry, extract its relevant valuation metrics (e.g., P/E, P/B, EV/EBITDA).\n", "Third, extract companies from the selected industry using relaxed criteria.\n", "Fourth, for the best performing companies get the analyst consensus\n", "Finally, summarize your findings in no more than 80 words detailing:\n", "- Best performing industry\n", "- Best performing companies in industry\n", "- A table displaying the analyst consensus for each of the companies you found at previous step'''\n", "result = agent_executor.invoke({\"input\": input1, \"chat_history\": chat_history})\n", "print(result['output'])" ] }, { "cell_type": "markdown", "metadata": { "id": "au-Qbu9KxVcy" }, "source": [ "### Finding strong buys in the Utilities sector " ] }, { "cell_type": "code", "source": [ "input1 = '''\n", "First, find the stocks recommended fro strong buy in the Utilities Sector\n", "Second, find the valuation metrics for this stock.\n", "Third, summarize your findings in a short paragraph.\n", "'''\n", "result = agent_executor.invoke({\"input\": input1, \"chat_history\": chat_history})\n", "print(result['output'])" ], "metadata": { "id": "doUw61HPU6fR" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [], "metadata": { "id": "rc7X4Ep4VNbS" }, "execution_count": null, "outputs": [] } ], "metadata": { "kernelspec": { "display_name": "myenv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.1" }, "colab": { "provenance": [] } }, "nbformat": 4, "nbformat_minor": 0 }