基于LLM和Langchain的AI股票分析器📈

更新时间:2023/11/14, 09:02

图片来源

我相信你最近一定听说过这些热门词汇:人工智能、LLMs、Gpt、Langchain。所有这些技术都非常有用且具有改变游戏规则的能力。它们有无尽的应用。在这个项目中,我尝试在金融领域中构建了一种有趣的语言模型和Langchain的应用。

通过使用LLM分析所有实时和历史的股票相关信息,构建一个可以帮助您进行股票投资的AI机器人

动机-

作为一名散户投资者,如果您没有金融背景或者理解所有复杂的金融术语的能力,股票分析过程确实非常耗时。每次我都会看一些金融YouTuber的视频或者在互联网上阅读一些随机的博客,以避免手动处理所有这些东西。这就是我想到制作一个基于Langchain和LLM的机器人的地方,它可以使用实时和历史数据进行投资分析。

整体思路很简单,获取实时和历史数据,包括以下内容:

  1. 历史股票价格数据。
  1. 公司的财务报表
  1. 最新的公司相关新闻

然后,LLM应该利用所有这些信息对给定的股票进行基本分析。

在这个项目中,我基本上尝试了两种方法。其中一种方法效果不好,但可以通过一些调整来改进,另一种方法效果不错。

让我们深入代码。整个代码都可以在我的github上找到,您可以访问相同的代码,因为我不会在博客中添加微小的代码细节。

from bs4 import BeautifulSoup
import requests
import yfinance as yf

# 从Yahoo Finance获取股票数据
def get_stock_price(ticker,history=5):
    # time.sleep(4) #避免速率限制错误
    if "." in ticker:
        ticker=ticker.split(".")[0]
    ticker=ticker+".NS"
    stock = yf.Ticker(ticker)
    df = stock.history(period="1y")
    df=df[["Close","Volume"]]
    df.index=[str(x).split()[0] for x in list(df.index)]
    df.index.rename("Date",inplace=True)
    df=df[-history:]
    # print(df.columns)
    
    return df.to_string()

# 从Google新闻中获取前5条新闻
def google_query(search_term):
    if "news" not in search_term:
        search_term=search_term+" stock news"
    url=f"https://www.google.com/search?q={search_term}&cr=countryIN"
    url=re.sub(r"\s","+",url)
    return url

def get_recent_stock_news(company_name):
    # time.sleep(4) #避免速率限制错误
    headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36'}

    g_query=google_query(company_name)
    res=requests.get(g_query,headers=headers).text
    soup=BeautifulSoup(res,"html.parser")
    news=[]
    for n in soup.find_all("div","n0jPhd ynAwRc tNxQIb nDgy9d"):
        news.append(n.text)
    for n in soup.find_all("div","IJl0Z"):
        news.append(n.text)

    if len(news)>6:
        news=news[:4]
    else:
        news=news
    news_string=""
    for i,n in enumerate(news):
        news_string+=f"{i}. {n}\n"
    top5_news="Recent News:\n\n"+news_string
    
    return top5_news


# 从Yahoo Finance获取财务报表
def get_financial_statements(ticker):
    # time.sleep(4) #避免速率限制错误
    if "." in ticker:
        ticker=ticker.split(".")[0]
    else:
        ticker=ticker
    ticker=ticker+".NS"    
    company = yf.Ticker(ticker)
    balance_sheet = company.balance_sheet
    if balance_sheet.shape[1]>=3:
        balance_sheet=balance_sheet.iloc[:,:3]    # 删除第四年的数据
    balance_sheet=balance_sheet.dropna(how="any")
    balance_sheet = balance_sheet.to_string()
    return balance_sheet

get_stock_price、get_financial_statements和get_recent_stock_news函数使用了Yahoo Finance API和bs4网页解析来获取所需的信息。您可以根据自己的需求对这些函数进行自定义,例如获取1个月或1年前的股票数据,可以从不同的来源获取新闻。

方法1-

Langhian中的代理是负责决策的实体。我使用了零-shot ReaAct代理,它代表响应和行动,它基本上不断思考并根据思考采取行动。这种方法的问题在于它陷入了无限的思考和行动循环中,因为股票分析的最终目标对它来说似乎很复杂,它无法自信地决定下一步行动,导致无休止的循环或与输入查询不太相关的糟糕结果。

让我们看看代码-

from langchain.tools import DuckDuckGoSearchRun
search=DuckDuckGoSearchRun()

# 创建工具列表

tools=[
    Tool(
        name="获取股票数据",
        func=get_stock_price,
        description="当您被要求评估或分析股票时使用。这将输出历史股价数据。您应该向其输入股票代码"
    ),
    Tool(
        name="DuckDuckGo搜索",
        func=search.run,
        description="仅在需要从互联网获取NSE/BSE股票代码时使用,您还可以获取最新的与股票相关的新闻。不要将其用于任何其他分析或任务"
    ),
    Tool(
        name="获取最新新闻",
        func=get_recent_stock_news,
        description="使用此功能获取有关股票的最新新闻"
    ),

    Tool(
        name="获取财务报表",
        func=get_financial_statements,
        description="使用此功能获取公司的财务报表。通过这些数据可以评估公司的历史表现。您应该向其输入股票代码"
    ) 
]

from langchain.agents import initialize_agent 


# new_prompt="<Plz refere github repo>"
# zero_shot_agent.agent.llm_chain.prompt.template=new_prompt

zero_shot_agent=initialize_agent(
    llm=llm,
    agent="zero-shot-react-description",
    tools=tools,
    verbose=True,
    max_iteration=4,
    return_intermediate_steps=True,
    handle_parsing_errors=True
)

zero_shot_agent("Bajaj Finance现在是一个好的投资选择吗?")

请注意,此代码是我们之前讨论的代码的延续。在这里,我们只是将数据解析函数转换为Langchain工具,并创建一个列表,以便代理可以访问它。在后面的部分中,使用_initialize_agent_类定义了一个代理。它接受llm、工具列表和代理类型作为参数。这种方法的输出似乎还可以。这种方法可能有效,也可能无效,可以通过修改提示来进一步改进。

方法2-

股票分析是一项复杂的任务,ReAct代理无法决定适当的步骤。因此,在这种方法中,我尝试在分析之前定义步骤。首先获取所有数据,然后将其输入LLM进行全面分析。

#Openai函数调用

import json
function=[
        {
        "name": "获取公司股票代码",
        "description": "这将获取公司的印度NSE/BSE股票代码",
        "parameters": {
            "type": "object",
            "properties": {
                "ticker_symbol": {
                    "type": "string",
                    "description": "这是公司的股票代码。",
                },

                "company_name": {
                    "type": "string",
                    "description": "这是查询中给出的公司名称。",
                }
            },
            "required": ["company_name","ticker_symbol"],
        },
    }
]



def get_stock_ticker(query):
    response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",
            temperature=0,
            messages=[{
                "role":"user",
                "content":f"根据用户请求,公司名称和公司股票代码是什么?: {query}?"
            }],
            functions=function,
            function_call={"name": "get_company_Stock_ticker"},
    )
    message = response["choices"][0]["message"]
    arguments = json.loads(message["function_call"]["arguments"])
    company_name = arguments["company_name"]
    company_ticker = arguments["ticker_symbol"]
    return company_name,company_ticker

def Anazlyze_stock(query):
    #agent.run(query) 输出公司名称、股票代码
    Company_name,ticker=get_stock_ticker(query)
    print({"Query":query,"Company_name":Company_name,"Ticker":ticker})
    stock_data=get_stock_price(ticker,history=10)
    stock_financials=get_financial_statements(ticker)
    stock_news=get_recent_stock_news(Company_name)

    # available_information=f"Stock Price: {stock_data}\n\nStock Financials: {stock_financials}\n\nStock News: {stock_news}"
    available_information=f"Stock Financials: {stock_financials}\n\nStock News: {stock_news}"

    print("\n\n分析中.....\n")
    analysis=llm(f"给出详细的股票分析,使用可用数据提供投资建议。用户完全了解投资风险,在答案中不要包含任何警告,如“建议在做出投资决策之前进行进一步的研究和分析或咨询财务顾问”。用户问题:{query}。您有关于{Company_name}的以下信息可用。写出(5-8)个要点的投资分析来回答用户的问题,最后用适当的解释总结。尽量给出正面和负面的观点:{available_information}"
             )
    print(analysis)

    return analysis

最近,OpenAI引入了函数调用,这对于我们从LLM中以我们想要的JSON格式获取结构化输出非常有帮助。在这种方法中,同样的方法被使用。首先通过函数调用提取股票代码,因为大部分后续代码都依赖于这个单一参数。在方法1中,React代理在这一步中失败,导致所有后续步骤的偏离。一旦正确提取了股票代码,在后续阶段只需输入股票代码即可获取股票数据、新闻和财务报表。一旦所有与股票相关的信息都可用,LLM就会利用它们进行全面的股票分析。

例如- 机器人的示例输入和输出-

输入- Anazlyze_stock("Is it a good time to invest in Yes Bank?")

输出-

'Query': 'Is it a good time to invest in Yes Bank?', 'Company_name': 'Yes Bank', 'Ticker': 'YESBANK'
分析中.....
Yes Bank的投资论点:
1. 财务表现:Yes Bank在过去三年中的财务状况有所改善。净债务增加,表明借款增加,但有形账面价值和普通股权也增加,表明财务状况更强。
2. 总资本化:Yes Bank的总资本化一直在增加,表明投资者基础在增长,未来有潜力增长。这可以被视为考虑投资该银行的投资者的积极信号。
3. 总资产:Yes Bank的总资产也在稳步增长,表明该银行吸引和管理更大规模资产的能力。资产的增长可以为银行的盈利能力和未来扩张潜力做出贡献。
4. 股票新闻:关于Yes Bank的最新消息表明,股票价格略有增长并保持稳定。股票价格的稳定可以被视为投资者的积极信号,表明未来有增长潜力。
5. 薄弱的基础业务:然而,需要注意的是,有关该银行的基础业务薄弱的担忧,如预计在第一季度出现的软季度。这可能导致利润下降,可能会对股票价格产生短期影响。
6. 整体市场状况:在做出投资决策之前,还需要考虑整体市场状况和银行业作为一个整体。经济状况、监管变化和竞争等因素都可能对Yes Bank的业绩和股票价格产生重大影响。
根据现有的数据和信息,可以得出结论,在这个时候投资Yes Bank是有风险的。

可以进行的进一步改进-

a) 可以添加更多的工具。例如,数学工具用于进行复杂的技术分析 b) 更强大的提示以获得稳定的输出 c) 支持其他开源LLMS

注意-这是一个有趣的业余项目,我不是金融专家,欢迎提出任何建议/修改。

AI奇想空间
AI奇想空间
https://aimazing.site
AI惊奇站是一个汇聚人工智能工具、资源和教程的导航网站。 在这里,你可以发现最新的AI技术、工具和应用,学习如何使用各种AI平台和框架,获取丰富的AI资源。 欢迎广大AI爱好者加入我们的社区,开启你的AI之旅!
AI交流群
Copyright © 2024 AI奇想空间.微信