sanjeevl10 commited on
Commit
cb954a2
1 Parent(s): fa36d6b

Push all the changes to Hugging Face

Browse files
.DS_Store ADDED
Binary file (6.15 kB). View file
 
README.md CHANGED
@@ -1,7 +1,7 @@
1
  # Chatbot using Langchain and Chainlit
2
 
3
  ```bash
4
- git clone git@github.com:sanjeevl10/StockSavvyFinal.git
5
  ```
6
  Install dependencies
7
  ```bash
 
1
  # Chatbot using Langchain and Chainlit
2
 
3
  ```bash
4
+ git clone https://github.com/amalaj7/Chatbot-using-Langchain-Chainlit.git
5
  ```
6
  Install dependencies
7
  ```bash
app.py CHANGED
@@ -1,228 +1,172 @@
1
- from langchain_experimental.agents import create_pandas_dataframe_agent
2
- from langchain.llms import OpenAI
3
- import chainlit as cl
4
- from plotly.subplots import make_subplots
5
- import utils as u
6
- from langchain.agents import AgentExecutor, create_openai_tools_agent
7
- from langchain_core.messages import BaseMessage, HumanMessage
8
- from langchain_openai import ChatOpenAI
9
- from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser
10
- from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
11
- from tools import data_analyst
12
- import functools
13
- from typing import Annotated
14
- import operator
15
- from typing import Sequence, TypedDict
16
- from langchain.agents import initialize_agent, Tool
17
- from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
18
- from langgraph.graph import END, StateGraph
19
- import numpy as np
20
- import pandas as pd
21
- from dotenv import load_dotenv
22
- import yfinance as yf
23
- import functools
24
- from typing import Annotated
25
- import operator
26
- from typing import Sequence, TypedDict
27
- from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
28
- from langgraph.graph import END, StateGraph
29
- from tools import data_analyst, forecasting_expert_arima, forecasting_expert_rf, evaluator
30
- from chainlit.input_widget import Select
31
- from langchain_core.runnables import RunnableConfig
32
- import matplotlib.pyplot as plt
33
-
34
- load_dotenv()
35
-
36
- def create_agent(llm: ChatOpenAI, tools: list, system_prompt: str):
37
- # Each worker node will be given a name and some tools.
38
- prompt = ChatPromptTemplate.from_messages(
39
- [
40
- (
41
- "system",
42
- system_prompt,
43
- ),
44
- MessagesPlaceholder(variable_name="messages"),
45
- MessagesPlaceholder(variable_name="agent_scratchpad"),
46
- ]
47
- )
48
- agent = create_openai_tools_agent(llm, tools, prompt)
49
- executor = AgentExecutor(agent=agent, tools=tools)
50
- return executor
51
-
52
- def agent_node(state, agent, name):
53
- result = agent.invoke(state)
54
- return {"messages": [HumanMessage(content=result["output"], name=name)]}
55
-
56
- llm = ChatOpenAI(model="gpt-3.5-turbo")
57
-
58
- #======================== AGENTS ==================================
59
- # The agent state is the input to each node in the graph
60
- class AgentState(TypedDict):
61
- # The annotation tells the graph that new messages will always
62
- # be added to the current states
63
- messages: Annotated[Sequence[BaseMessage], operator.add]
64
- # The 'next' field indicates where to route to next
65
- next: str
66
-
67
- # DATA ANALYST
68
- prompt_data_analyst="You are a stock data analyst.\
69
- Provide correct stock ticker from Yahoo Finance.\
70
- Expected output: stocticker.\
71
- Provide it in the following format: >>stockticker>> \
72
- for example: >>AAPL>>"
73
-
74
- tools_data_analyst=data_analyst.data_analyst_tools()
75
- data_agent = create_agent(
76
- llm,
77
- tools_data_analyst,
78
- prompt_data_analyst)
79
- get_historical_prices = functools.partial(agent_node, agent=data_agent, name="Data_analyst")
80
-
81
- #ARIMA Forecasting expert
82
- prompt_forecasting_expert_arima="""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
83
- You are stock prediction expert, \
84
- take historical stock data from message and train the ARIMA model from statsmodels Python library on the last week,then provide prediction for the 'Close' price for the next day.\
85
- Give the value for mae_arima to Evaluator.\
86
- Expected output:list of predicted prices with predicted dates for a selected stock ticker and mae_arima value.\n
87
- <|eot_id|><|start_header_id|>assistant<|end_header_id|>"""
88
-
89
- tools_forecasting_expert_arima=forecasting_expert_arima.forecasting_expert_arima_tools()
90
- code_forecasting_arima = create_agent(
91
- llm,
92
- tools_forecasting_expert_arima,
93
- prompt_forecasting_expert_arima,
94
- )
95
- predict_future_prices_arima = functools.partial(agent_node, agent=code_forecasting_arima, name="Forecasting_expert_ARIMA")
96
-
97
- # RF Forecasting expert
98
- prompt_forecasting_expert_random_forest="""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
99
- You are stock prediction expert, \
100
- take historical stock data from message and train the Random forest model from statsmodels Python library on the last week,then provide prediction for the 'Close' price for the next day.\
101
- Give the value for mae_rf to Evaluator.\
102
- Expected output:list of predicted prices with predicted dates for a selected stock ticker and mae_rf value.\n
103
- <|eot_id|><|start_header_id|>assistant<|end_header_id|>"""
104
-
105
- tools_forecasting_expert_random_forest=forecasting_expert_rf.forecasting_expert_rf_tools()
106
- code_forecasting_random_forest = create_agent(
107
- llm,
108
- tools_forecasting_expert_random_forest,
109
- prompt_forecasting_expert_random_forest,
110
- )
111
- predict_future_prices_random_forest = functools.partial(agent_node, agent=code_forecasting_random_forest, name="Forecasting_expert_random_forest")
112
-
113
- # EVALUATOR
114
- prompt_evaluator="""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
115
- You are an evaluator retrieve arima_prediction and arima mean average error from forecasting expert arima and rf_prediction and mean average error for random forest from forecasting expert random forest\
116
- print final prediction number.\
117
- Expected output: one value for the prediction, explain why you have selected this value.\
118
- <|eot_id|><|start_header_id|>assistant<|end_header_id|>"""
119
-
120
- tools_evaluate=evaluator.evaluator_tools()
121
- code_evaluate = create_agent(
122
- llm,
123
- tools_evaluate,
124
- prompt_evaluator,
125
- )
126
-
127
- evaluate = functools.partial(agent_node, agent=code_evaluate, name="Evaluator")
128
-
129
- workflow_data = StateGraph(AgentState)
130
- workflow_data.add_node("Data_analyst", get_historical_prices)
131
- workflow_data.set_entry_point("Data_analyst")
132
- graph_data=workflow_data.compile()
133
-
134
- workflow = StateGraph(AgentState)
135
- #workflow.add_node("Data_analyst", get_historical_prices)
136
- workflow.add_node("Forecasting_expert_random_forest", predict_future_prices_random_forest)
137
- workflow.add_node("Forecasting_expert_ARIMA", predict_future_prices_arima)
138
- workflow.add_node("Evaluator", evaluate)
139
-
140
- # Finally, add entrypoint
141
- workflow.set_entry_point("Forecasting_expert_random_forest")
142
- workflow.add_edge("Forecasting_expert_random_forest","Forecasting_expert_ARIMA")
143
- workflow.add_edge("Forecasting_expert_ARIMA","Evaluator")
144
- graph = workflow.compile()
145
-
146
- @cl.on_chat_start
147
- async def on_chat_start():
148
-
149
- # Sending an image with the local file path
150
- elements = [
151
- cl.Image(name="image1", display="inline", path="./good_day.jpg",size="large")
152
- ]
153
- await cl.Message(content="Hello there, Welcome to ##StockSavyy!", elements=elements).send()
154
- await cl.Message(content="Tell me the stockticker you want me to analyze.").send()
155
-
156
- @cl.on_message
157
- async def main(message: cl.Message):
158
- #"what is the weather in sf"
159
-
160
- inputs = {"messages": [HumanMessage(content=message.content)]}
161
-
162
- res_data = graph_data.invoke(inputs, config=RunnableConfig(callbacks=[
163
- cl.LangchainCallbackHandler(
164
- to_ignore=["ChannelRead", "RunnableLambda", "ChannelWrite", "__start__", "_execute"]
165
- # can add more into the to_ignore: "agent:edges", "call_model"
166
- # to_keep=
167
-
168
- )]))
169
- #print(res_data)
170
- await cl.Message(content=res_data["messages"][-1].content).send()
171
- #print('ticker',str(res_data).split(">>"))
172
- if len(str(res_data).split(">>")[1])<10:
173
- stockticker=(str(res_data).split(">>")[1])
174
- else:
175
- stockticker=(str(res_data).split(">>")[0])
176
- #print('ticker1',stockticker)
177
-
178
- df=u.get_stock_price(stockticker)
179
- df_history=u.historical_stock_prices(stockticker,90)
180
- df_history_to_msg1=eval(str(list((pd.DataFrame(df_history['Close'].values.reshape(1, -1)[0]).T).iloc[0,:])))
181
- df_history_to_msg=dict(df_history.reset_index()['Close'])
182
- #print('here',eval(str(list(((df_history['Close']))))))
183
-
184
- # print('dict',dict(df_history.reset_index()['Close']))
185
- #print('tady',str(list((pd.DataFrame(df_history['Close'].values.reshape(1, -1)[0]).T).iloc[0,:])))
186
- #print('heere',df_history_to_msg1)
187
-
188
- #inputs_all = {"messages": [HumanMessage(content=("Predict Aaple, historical prices are: {172.45608520507812, 169.15057373046875, 167.77244567871094, 166.81373596191406, 164.77650451660156, 165.6153564453125, 166.67391967773438, 168.7910614013672"))]} #,df_history_to_msg))]}
189
- #print(f"Predict {stockticker}, historical prices are: {df_history_to_msg1}")
190
- inputs_all = {"messages": [HumanMessage(content=(f"Predict {stockticker}, historical prices are: {df_history_to_msg1}"))]}
191
- #print(inputs_all)
192
-
193
- res = graph.invoke(inputs_all, config=RunnableConfig(callbacks=[
194
- cl.LangchainCallbackHandler(
195
- to_ignore=["ChannelRead", "RunnableLambda", "ChannelWrite", "__start__", "_execute"]
196
- # can add more into the to_ignore: "agent:edges", "call_model"
197
- # to_keep=
198
-
199
- )]))
200
- await cl.Message(content=res["messages"][-1].content).send()
201
- # await cl.Message(content=df).send()
202
- # print(res)
203
- # print(str(res).split('>>')[0])
204
-
205
- #print('here',str(res).split('>>')[0].split("n")[-1].split("'")[-1])
206
- #stockticker=(str(inputs['messages']).split('=')[1].split("'")[1])
207
- print('stockticker',stockticker)
208
-
209
- df=u.historical_stock_prices(stockticker,90)
210
- df=u.calculate_MACD(df, fast_period=12, slow_period=26, signal_period=9)
211
- #df values
212
- #Index(['Open', 'High', 'Low', 'Close', 'Volume', 'Dividends', 'Stock Splits','EMA_fast', 'EMA_slow', 'MACD', 'Signal_Line', 'MACD_Histogram']
213
- fig = u.plot_macd2(df,str(stockticker))
214
-
215
- if fig:
216
- elements = [cl.Pyplot(name="plot", figure=fig, display="inline",size="large"),
217
- ]
218
- await cl.Message(
219
- content="Here is the MACD plot",
220
- elements=elements,
221
- ).send()
222
- else:
223
- await cl.Message(
224
- content="Failed to generate the MACD plot."
225
- ).send()
226
-
227
-
228
-
 
1
+ from langchain_experimental.agents import create_pandas_dataframe_agent
2
+ from langchain.llms import OpenAI
3
+ import chainlit as cl
4
+ from plotly.subplots import make_subplots
5
+ import utils as u
6
+ from langchain.agents import AgentExecutor, create_openai_tools_agent
7
+ from langchain_core.messages import BaseMessage, HumanMessage
8
+ from langchain_openai import ChatOpenAI
9
+ from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser
10
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
11
+ from tools import data_analyst, stock_sentiment_evalutor, forecasting_expert_arima, forecasting_expert_rf, evaluator, investment_advisor
12
+ import functools
13
+ from typing import Annotated, Sequence, TypedDict
14
+ from langgraph.graph import END, StateGraph
15
+ import operator
16
+ import numpy as np
17
+ import pandas as pd
18
+ from dotenv import load_dotenv
19
+ import os
20
+ import yfinance as yf
21
+ from chainlit.input_widget import Select
22
+ import matplotlib.pyplot as plt
23
+ from langgraph.checkpoint.memory import MemorySaver
24
+ from langchain_core.runnables import RunnableConfig
25
+
26
+
27
+ load_dotenv()
28
+ OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
29
+
30
+ from GoogleNews import GoogleNews
31
+
32
+ def search_news(stockticker):
33
+ googlenews = GoogleNews()
34
+ googlenews.set_period('7d')
35
+ googlenews.get_news(stockticker)
36
+ return googlenews.get_texts()
37
+
38
+ def create_agent(llm: ChatOpenAI, tools: list, system_prompt: str):
39
+ prompt = ChatPromptTemplate.from_messages(
40
+ [
41
+ ("system", system_prompt),
42
+ MessagesPlaceholder(variable_name="messages"),
43
+ MessagesPlaceholder(variable_name="agent_scratchpad"),
44
+ ]
45
+ )
46
+ agent = create_openai_tools_agent(llm, tools, prompt)
47
+ return AgentExecutor(agent=agent, tools=tools)
48
+
49
+ def agent_node(state, agent, name):
50
+ result = agent.invoke(state)
51
+ return {"messages": [HumanMessage(content=result["output"], name=name)]}
52
+
53
+ llm = ChatOpenAI(model="gpt-3.5-turbo")
54
+
55
+ #======================== AGENTS ==================================
56
+ class AgentState(TypedDict):
57
+ messages: Annotated[Sequence[BaseMessage], operator.add]
58
+ next: str
59
+
60
+ # Data Analyst
61
+ prompt_data_analyst = "You are a stock data analyst. Provide correct stock ticker from Yahoo Finance. Expected output: stockticker. Provide it in the following format: >>stockticker>> for example: >>AAPL>>"
62
+ tools_data_analyst = data_analyst.data_analyst_tools()
63
+ data_agent = create_agent(llm, tools_data_analyst, prompt_data_analyst)
64
+ get_historical_prices = functools.partial(agent_node, agent=data_agent, name="Data_analyst")
65
+
66
+ # ARIMA Forecasting Expert
67
+ prompt_forecasting_expert_arima = "system You are a stock prediction expert. Take historical stock data from message and train the ARIMA model from statsmodels Python library on the last week, then provide prediction for the 'Close' price for the next day. Give the value for mae_arima to Evaluator. Expected output: list of predicted prices with predicted dates for a selected stock ticker and mae_arima value. assistant"
68
+ tools_forecasting_expert_arima = forecasting_expert_arima.forecasting_expert_arima_tools()
69
+ code_forecasting_arima = create_agent(llm, tools_forecasting_expert_arima, prompt_forecasting_expert_arima)
70
+ predict_future_prices_arima = functools.partial(agent_node, agent=code_forecasting_arima, name="Forecasting_expert_ARIMA")
71
+
72
+ # RF Forecasting Expert
73
+ prompt_forecasting_expert_random_forest = "system You are a stock prediction expert. Take historical stock data from message and train the Random Forest model from statsmodels Python library on the last week, then provide prediction for the 'Close' price for the next day. Give the value for mae_rf to Evaluator. Expected output: list of predicted prices with predicted dates for a selected stock ticker and mae_rf value. assistant"
74
+ tools_forecasting_expert_random_forest = forecasting_expert_rf.forecasting_expert_rf_tools()
75
+ code_forecasting_random_forest = create_agent(llm, tools_forecasting_expert_random_forest, prompt_forecasting_expert_random_forest)
76
+ predict_future_prices_random_forest = functools.partial(agent_node, agent=code_forecasting_random_forest, name="Forecasting_expert_random_forest")
77
+
78
+ # Evaluator
79
+ prompt_evaluator = "system You are an evaluator. Retrieve arima_prediction and arima mean average error from forecasting expert arima and rf_prediction and mean average error for random forest from forecasting expert random forest. Print final prediction number. Next, compare prediction price and current price to provide recommendation if he should buy/sell/hold the stock. Expected output: one value for the prediction, explain why you have selected this value, recommendation buy or sell stock and why. assistant"
80
+ tools_evaluate = evaluator.evaluator_tools()
81
+ code_evaluate = create_agent(llm, tools_evaluate, prompt_evaluator)
82
+ evaluate = functools.partial(agent_node, agent=code_evaluate, name="Evaluator")
83
+
84
+ # Stock Sentiment Evaluator
85
+ prompt_sentiment_evaluator = "system You are a stock sentiment evaluator. Retrieve news for the stock based on the configured data range starting today and their corresponding sentiment, along with the most dominant sentiment for the stock. Expected output: List ALL stock news and their sentiment from the StockSentimentAnalysis tool response, and the dominant sentiment for the stock also in StockSentimentAnalysis tool response as is without change. assistant"
86
+ tools_sentiment_evaluator = stock_sentiment_evalutor.sentimental_analysis_tools()
87
+ sentiment_evaluator = create_agent(llm, tools_sentiment_evaluator, prompt_sentiment_evaluator)
88
+ evaluate_sentiment = functools.partial(agent_node, agent=sentiment_evaluator, name="Sentiment_Evaluator")
89
+
90
+ # Investment Advisor
91
+ prompt_inv_advisor = "system Provide personalized investment advice and recommendations. Consider user input message for the latest news on the stock. Provide overall sentiment of the news Positive/Negative/Neutral, and recommend if the user should invest in such stock. MUST finish the analysis with a summary on the latest news from the user input on the stock! assistant"
92
+ tools_reccommend = investment_advisor.investment_advisor_tools()
93
+ code_inv_advisor = create_agent(llm, tools_reccommend, prompt_inv_advisor)
94
+ reccommend = functools.partial(agent_node, agent=code_inv_advisor, name="Investment_advisor")
95
+
96
+ workflow_data = StateGraph(AgentState)
97
+ workflow_data.add_node("Data_analyst", get_historical_prices)
98
+ workflow_data.set_entry_point("Data_analyst")
99
+ graph_data = workflow_data.compile()
100
+
101
+ workflow = StateGraph(AgentState)
102
+ workflow.add_node("Forecasting_expert_random_forest", predict_future_prices_random_forest)
103
+ workflow.add_node("Forecasting_expert_ARIMA", predict_future_prices_arima)
104
+ workflow.add_node("Evaluator", evaluate)
105
+ workflow.set_entry_point("Forecasting_expert_random_forest")
106
+ workflow.add_edge("Forecasting_expert_random_forest", "Forecasting_expert_ARIMA")
107
+ workflow.add_edge("Forecasting_expert_ARIMA", "Evaluator")
108
+ workflow.add_edge("Evaluator", END)
109
+ graph = workflow.compile()
110
+
111
+ memory = MemorySaver()
112
+ workflow_news = StateGraph(AgentState)
113
+ workflow_news.add_node("Investment_advisor", reccommend)
114
+ workflow_news.set_entry_point("Investment_advisor")
115
+ workflow_news.add_edge("Investment_advisor", END)
116
+ graph_news = workflow_news.compile(checkpointer=memory)
117
+
118
+ @cl.on_chat_start
119
+ async def on_chat_start():
120
+ cl.user_session.set("counter", 0)
121
+ elements = [cl.Image(name="image1", display="inline", path="./stock_image1.png", size="large")]
122
+ await cl.Message(content="Welcome to ##StockSavvy!", elements=elements).send()
123
+ await cl.Message(content="Enter a Company Name for Stock Recommendations from Our Chatbot").send()
124
+
125
+ @cl.on_message
126
+ async def main(message: cl.Message):
127
+ counter = cl.user_session.get("counter")
128
+ counter += 1
129
+ cl.user_session.set("counter", counter)
130
+ await cl.Message(content=f"You sent {counter} message(s)!").send()
131
+
132
+ if counter == 1:
133
+ inputs = {"messages": [HumanMessage(content=message.content)]}
134
+ res_data = graph_data.invoke(inputs, config=RunnableConfig(callbacks=[
135
+ cl.LangchainCallbackHandler(
136
+ to_ignore=["ChannelRead", "RunnableLambda", "ChannelWrite", "__start__", "_execute"]
137
+ )]))
138
+ await cl.Message(content=res_data["messages"][-1].content).send()
139
+
140
+ stockticker = (str(res_data).split(">>")[1] if len(str(res_data).split(">>")[1]) < 10 else str(res_data).split(">>")[0])
141
+ df = u.get_stock_price(stockticker)
142
+ df_history = u.historical_stock_prices(stockticker, 90)
143
+ df_history_to_msg1 = eval(str(list((pd.DataFrame(df_history['Close'].values.reshape(1, -1)[0]).T).iloc[0, :])))
144
+ inputs_all = {"messages": [HumanMessage(content=(f"Predict {stockticker}, historical prices are: {df_history_to_msg1}."))]}
145
+ df_history = pd.DataFrame(df_history)
146
+ df_history['stockticker'] = np.repeat(stockticker, len(df_history))
147
+ df_history.to_csv('df_history.csv')
148
+
149
+ res = graph.invoke(inputs_all, config=RunnableConfig(callbacks=[
150
+ cl.LangchainCallbackHandler(
151
+ to_ignore=["ChannelRead", "RunnableLambda", "ChannelWrite", "__start__", "_execute"]
152
+ )]))
153
+ await cl.Message(content=res["messages"][-2].content + '\n\n' + res["messages"][-1].content).send()
154
+
155
+ df_history = pd.read_csv('df_history.csv')
156
+ stockticker = str(df_history['stockticker'][0])
157
+ df_search = search_news(stockticker)
158
+ with open('search_news.txt', 'w') as a:
159
+ a.write(str(df_search[0:10]))
160
+ with open("search_news.txt", "r") as file:
161
+ df_search = file.read()
162
+
163
+ inputs_news = {"messages": [HumanMessage(content=(f"Summarize articles for {stockticker} to write 2 sentences about following articles: {df_search}."))]}
164
+ for event in graph_news.stream(inputs_news, {"configurable": {"thread_id": "1"}}, stream_mode="values"):
165
+ await cl.Message(content=event["messages"][-1].content).send()
166
+
167
+ if counter == 1:
168
+ df = u.historical_stock_prices(stockticker, 90)
169
+ df = u.calculate_MACD(df, fast_period=12, slow_period=26, signal_period=9)
170
+ fig = u.plot_macd2(df)
171
+ elements = [cl.Pyplot(name="plot", figure=fig, display="inline", size="large")] if fig else []
172
+ await cl.Message(content="Here is the MACD plot" if fig else "Failed to generate the MACD plot.", elements=elements).send()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app_test3_memory.py ADDED
@@ -0,0 +1,303 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_experimental.agents import create_pandas_dataframe_agent
2
+ from langchain.llms import OpenAI
3
+ import chainlit as cl
4
+ from plotly.subplots import make_subplots
5
+ import utils as u
6
+ from langchain.agents import AgentExecutor, create_openai_tools_agent
7
+ from langchain_core.messages import BaseMessage, HumanMessage
8
+ from langchain_openai import ChatOpenAI
9
+ from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser
10
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
11
+ from tools import data_analyst
12
+ from tools import stock_sentiment_evalutor
13
+ import functools
14
+ from typing import Annotated
15
+ import operator
16
+ from typing import Sequence, TypedDict
17
+ from langchain.agents import initialize_agent, Tool
18
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
19
+ from langgraph.graph import END, StateGraph
20
+ import numpy as np
21
+ import pandas as pd
22
+ from dotenv import load_dotenv
23
+ import os
24
+ import yfinance as yf
25
+ import functools
26
+ from typing import Annotated
27
+ import operator
28
+ from typing import Sequence, TypedDict
29
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
30
+ from langgraph.graph import END, StateGraph
31
+ from tools import data_analyst, forecasting_expert_arima, forecasting_expert_rf, evaluator, stock_sentiment_evalutor, investment_advisor
32
+ from chainlit.input_widget import Select
33
+ import matplotlib.pyplot as plt
34
+ from langgraph.checkpoint.memory import MemorySaver
35
+
36
+ load_dotenv()
37
+ OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
38
+
39
+ from GoogleNews import GoogleNews
40
+
41
+ def search_news(stockticker):
42
+ """Useful to search the internet for news about a given topic and return relevant results."""
43
+ # Set the number of top news results to return
44
+ googlenews = GoogleNews()
45
+ googlenews.set_period('7d')
46
+ googlenews.get_news(stockticker)
47
+ result_string=googlenews.get_texts()
48
+
49
+ return result_string
50
+
51
+
52
+ def create_agent(llm: ChatOpenAI, tools: list, system_prompt: str):
53
+ # Each worker node will be given a name and some tools.
54
+ prompt = ChatPromptTemplate.from_messages(
55
+ [
56
+ (
57
+ "system",
58
+ system_prompt,
59
+ ),
60
+ MessagesPlaceholder(variable_name="messages"),
61
+ MessagesPlaceholder(variable_name="agent_scratchpad"),
62
+ ]
63
+ )
64
+ agent = create_openai_tools_agent(llm, tools, prompt)
65
+ executor = AgentExecutor(agent=agent, tools=tools)
66
+ return executor
67
+
68
+
69
+ def agent_node(state, agent, name):
70
+ result = agent.invoke(state)
71
+ return {"messages": [HumanMessage(content=result["output"], name=name)]}
72
+
73
+ llm = ChatOpenAI(model="gpt-3.5-turbo")
74
+
75
+ #======================== AGENTS ==================================
76
+ # The agent state is the input to each node in the graph
77
+ class AgentState(TypedDict):
78
+ # The annotation tells the graph that new messages will always
79
+ # be added to the current states
80
+ messages: Annotated[Sequence[BaseMessage], operator.add]
81
+ # The 'next' field indicates where to route to next
82
+ next: str
83
+
84
+ # DATA ANALYST
85
+ prompt_data_analyst="You are a stock data analyst.\
86
+ Provide correct stock ticker from Yahoo Finance.\
87
+ Expected output: stocticker.\
88
+ Provide it in the following format: >>stockticker>> \
89
+ for example: >>AAPL>>"
90
+
91
+ tools_data_analyst=data_analyst.data_analyst_tools()
92
+ data_agent = create_agent(
93
+ llm,
94
+ tools_data_analyst,
95
+ prompt_data_analyst)
96
+ get_historical_prices = functools.partial(agent_node, agent=data_agent, name="Data_analyst")
97
+
98
+ #ARIMA Forecasting expert
99
+ prompt_forecasting_expert_arima="""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
100
+ You are stock prediction expert, \
101
+ take historical stock data from message and train the ARIMA model from statsmodels Python library on the last week,then provide prediction for the 'Close' price for the next day.\
102
+ Give the value for mae_arima to Evaluator.\
103
+ Expected output:list of predicted prices with predicted dates for a selected stock ticker and mae_arima value.\n
104
+ <|eot_id|><|start_header_id|>assistant<|end_header_id|>"""
105
+
106
+ tools_forecasting_expert_arima=forecasting_expert_arima.forecasting_expert_arima_tools()
107
+ code_forecasting_arima = create_agent(
108
+ llm,
109
+ tools_forecasting_expert_arima,
110
+ prompt_forecasting_expert_arima,
111
+ )
112
+ predict_future_prices_arima = functools.partial(agent_node, agent=code_forecasting_arima, name="Forecasting_expert_ARIMA")
113
+
114
+ # RF Forecasting expert
115
+ prompt_forecasting_expert_random_forest="""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
116
+ You are stock prediction expert, \
117
+ take historical stock data from message and train the Random forest model from statsmodels Python library on the last week,then provide prediction for the 'Close' price for the next day.\
118
+ Give the value for mae_rf to Evaluator.\
119
+ Expected output:list of predicted prices with predicted dates for a selected stock ticker and mae_rf value.\n
120
+ <|eot_id|><|start_header_id|>assistant<|end_header_id|>"""
121
+
122
+ tools_forecasting_expert_random_forest=forecasting_expert_rf.forecasting_expert_rf_tools()
123
+ code_forecasting_random_forest = create_agent(
124
+ llm,
125
+ tools_forecasting_expert_random_forest,
126
+ prompt_forecasting_expert_random_forest,
127
+ )
128
+ predict_future_prices_random_forest = functools.partial(agent_node, agent=code_forecasting_random_forest, name="Forecasting_expert_random_forest")
129
+
130
+ # EVALUATOR
131
+ prompt_evaluator="""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
132
+ You are an evaluator retrieve arima_prediction and arima mean average error from forecasting expert arima and rf_prediction and mean average error for random forest from forecasting expert random forest\
133
+ print final prediction number.
134
+ Next, compare prediction price and current price to provide reccommendation if he should buy/sell/hold the stock. \
135
+ Expected output: one value for the prediction, explain why you have selected this value, reccommendation buy or sell stock and why.\
136
+ <|eot_id|><|start_header_id|>assistant<|end_header_id|>"""
137
+
138
+ tools_evaluate=evaluator.evaluator_tools()
139
+ code_evaluate = create_agent(
140
+ llm,
141
+ tools_evaluate,
142
+ prompt_evaluator,
143
+ )
144
+ evaluate = functools.partial(agent_node, agent=code_evaluate, name="Evaluator")
145
+
146
+ #Stock Sentiment Evaluator
147
+ prompt_sentiment_evaluator="""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
148
+ You are a stock sentiment evaluator, that takes in a stock ticker and
149
+ then using your StockSentimentAnalysis tool retrieve news for the stock based on the configured data range starting today and their corresponding sentiment,
150
+ alongwith the most dominant sentiment for the stock\
151
+ Expected output: List ALL stock news and their sentiment from the StockSentimentAnalysis tool response, and the dominant sentiment for the stock also in StockSentimentAnalysis tool response as is without change\
152
+ Also ensure you use the tool only once and do not make changes to messages
153
+ Also you are not to change the response from the tool\
154
+ <|eot_id|><|start_header_id|>assistant<|end_header_id|>"""
155
+
156
+ tools_sentiment_evaluator=stock_sentiment_evalutor.sentimental_analysis_tools()
157
+ sentiment_evaluator = create_agent(
158
+ llm,
159
+ tools_sentiment_evaluator,
160
+ prompt_sentiment_evaluator,
161
+ )
162
+ evaluate_sentiment = functools.partial(agent_node, agent=sentiment_evaluator, name="Sentiment_Evaluator")
163
+
164
+ # Investment advisor
165
+ prompt_inv_advisor="""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
166
+ Provide personalized investment advice and recommendations.\
167
+ Consider user input message for the latest news on the stock.\
168
+ Provide overall sentiment of the news Positive/Negative/Neutral, and recommend if the user should invest in such stock.\
169
+ MUST finish the analysis with a summary on the latest news from the user input on the stock!\
170
+ <|eot_id|><|start_header_id|>assistant<|end_header_id|>"""
171
+
172
+ tools_reccommend=investment_advisor.investment_advisor_tools()
173
+
174
+ code_inv_advisor = create_agent(
175
+ llm,
176
+ tools_reccommend,
177
+ prompt_inv_advisor,
178
+ )
179
+
180
+ reccommend = functools.partial(agent_node, agent=code_inv_advisor, name="Investment_advisor")
181
+
182
+ workflow_data = StateGraph(AgentState)
183
+ workflow_data.add_node("Data_analyst", get_historical_prices)
184
+ workflow_data.set_entry_point("Data_analyst")
185
+ graph_data=workflow_data.compile()
186
+
187
+ workflow = StateGraph(AgentState)
188
+ #workflow.add_node("Data_analyst", get_historical_prices)
189
+ workflow.add_node("Forecasting_expert_random_forest", predict_future_prices_random_forest)
190
+ workflow.add_node("Forecasting_expert_ARIMA", predict_future_prices_arima)
191
+ workflow.add_node("Evaluator", evaluate)
192
+
193
+
194
+ # Finally, add entrypoint
195
+ workflow.set_entry_point("Forecasting_expert_random_forest")
196
+ workflow.add_edge("Forecasting_expert_random_forest","Forecasting_expert_ARIMA")
197
+ workflow.add_edge("Forecasting_expert_ARIMA","Evaluator")
198
+ workflow.add_edge("Evaluator",END)
199
+ graph = workflow.compile()
200
+
201
+ #Print graph
202
+ #graph.get_graph().print_ascii()
203
+
204
+ memory = MemorySaver()
205
+ workflow_news = StateGraph(AgentState)
206
+ workflow_news.add_node("Investment_advisor", reccommend)
207
+ workflow_news.set_entry_point("Investment_advisor")
208
+ workflow_news.add_edge("Investment_advisor",END)
209
+ graph_news = workflow_news.compile(checkpointer=memory)
210
+
211
+ from langchain_core.runnables import RunnableConfig
212
+ @cl.on_chat_start
213
+ async def on_chat_start():
214
+ cl.user_session.set("counter", 0)
215
+ # Sending an image with the local file path
216
+ elements = [
217
+ cl.Image(name="image1", display="inline", path="./stock_image1.png",size="large")
218
+ ]
219
+ await cl.Message(content="Hello there, Welcome to ##StockSavyy!", elements=elements).send()
220
+ await cl.Message(content="Tell me the stockticker you want me to analyze.").send()
221
+
222
+ @cl.on_message
223
+ async def main(message: cl.Message):
224
+ #"what is the weather in sf"
225
+ counter = cl.user_session.get("counter")
226
+ counter += 1
227
+ cl.user_session.set("counter", counter)
228
+ await cl.Message(content=f"You sent {counter} message(s)!").send()
229
+ if counter==1:
230
+ inputs = {"messages": [HumanMessage(content=message.content)]}
231
+
232
+ res_data = graph_data.invoke(inputs, config=RunnableConfig(callbacks=[
233
+ cl.LangchainCallbackHandler(
234
+ to_ignore=["ChannelRead", "RunnableLambda", "ChannelWrite", "__start__", "_execute"]
235
+ # can add more into the to_ignore: "agent:edges", "call_model"
236
+ # to_keep=
237
+
238
+ )]))
239
+ #print(res_data)
240
+ await cl.Message(content=res_data["messages"][-1].content).send()
241
+ #print('ticker',str(res_data).split(">>"))
242
+ if len(str(res_data).split(">>")[1])<10:
243
+ stockticker=(str(res_data).split(">>")[1])
244
+ else:
245
+ stockticker=(str(res_data).split(">>")[0])
246
+ #print('ticker1',stockticker)
247
+ print('here')
248
+ df=u.get_stock_price(stockticker)
249
+ df_history=u.historical_stock_prices(stockticker,90)
250
+ df_history_to_msg1=eval(str(list((pd.DataFrame(df_history['Close'].values.reshape(1, -1)[0]).T).iloc[0,:])))
251
+ inputs_all = {"messages": [HumanMessage(content=(f"Predict {stockticker}, historical prices are: {df_history_to_msg1}."))]}
252
+ #print(inputs_all)
253
+ df_history=pd.DataFrame(df_history)
254
+ df_history['stockticker']=np.repeat(stockticker,len(df_history))
255
+ df_history.to_csv('df_history.csv')
256
+
257
+ res = graph.invoke(inputs_all, config=RunnableConfig(callbacks=[
258
+ cl.LangchainCallbackHandler(
259
+ to_ignore=["ChannelRead", "RunnableLambda", "ChannelWrite", "__start__", "_execute"]
260
+ # can add more into the to_ignore: "agent:edges", "call_model"
261
+ # to_keep=
262
+
263
+ )]))
264
+ await cl.Message(content= res["messages"][-2].content + '\n\n' + res["messages"][-1].content).send()
265
+
266
+ df_history=pd.read_csv('df_history.csv')
267
+ stockticker=str(df_history['stockticker'][0])
268
+ df_search=search_news(stockticker)
269
+ with open('search_news.txt', 'w') as a:
270
+ a.write(str(df_search[0:10]))
271
+ file = open("search_news.txt", "r")
272
+ df_search = file.read()
273
+ print(stockticker)
274
+
275
+ config = {"configurable": {"thread_id": "1"}}
276
+ inputs_news = {"messages": [HumanMessage(content=(f"Summarize articles for {stockticker} to write 2 sentences about following articles: {df_search}."))]}
277
+ k=0
278
+ for event in graph_news.stream(inputs_news, config, stream_mode="values"):
279
+ k+=1
280
+ if k>1:
281
+ await cl.Message(content=event["messages"][-1].content).send()
282
+
283
+
284
+ if counter==1:
285
+ df=u.historical_stock_prices(stockticker,90)
286
+ df=u.calculate_MACD(df, fast_period=12, slow_period=26, signal_period=9)
287
+ fig = u.plot_macd2(df)
288
+
289
+ if fig:
290
+ elements = [cl.Pyplot(name="plot", figure=fig, display="inline",size="large"),
291
+ ]
292
+ await cl.Message(
293
+ content="Here is the MACD plot",
294
+ elements=elements,
295
+ ).send()
296
+ else:
297
+ await cl.Message(
298
+ content="Failed to generate the MACD plot."
299
+ ).send()
300
+
301
+
302
+
303
+
df_history.csv ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Date,Open,High,Low,Close,Volume,Dividends,Stock Splits,stockticker
2
+ 2024-04-22 00:00:00-04:00,176.94000244140625,178.8699951171875,174.55999755859375,177.22999572753906,37924900,0.0,0.0,AMZN
3
+ 2024-04-23 00:00:00-04:00,178.0800018310547,179.92999267578125,175.97999572753906,179.5399932861328,37046500,0.0,0.0,AMZN
4
+ 2024-04-24 00:00:00-04:00,179.94000244140625,180.32000732421875,176.17999267578125,176.58999633789062,34185100,0.0,0.0,AMZN
5
+ 2024-04-25 00:00:00-04:00,169.67999267578125,173.9199981689453,166.32000732421875,173.6699981689453,49249400,0.0,0.0,AMZN
6
+ 2024-04-26 00:00:00-04:00,177.8000030517578,180.82000732421875,176.1300048828125,179.6199951171875,43919800,0.0,0.0,AMZN
7
+ 2024-04-29 00:00:00-04:00,182.75,183.52999877929688,179.38999938964844,180.9600067138672,54063900,0.0,0.0,AMZN
8
+ 2024-04-30 00:00:00-04:00,181.08999633789062,182.99000549316406,174.8000030517578,175.0,94639800,0.0,0.0,AMZN
9
+ 2024-05-01 00:00:00-04:00,181.63999938964844,185.14999389648438,176.55999755859375,179.0,94645100,0.0,0.0,AMZN
10
+ 2024-05-02 00:00:00-04:00,180.85000610351562,185.10000610351562,179.91000366210938,184.72000122070312,54303500,0.0,0.0,AMZN
11
+ 2024-05-03 00:00:00-04:00,186.99000549316406,187.8699951171875,185.4199981689453,186.2100067138672,39172000,0.0,0.0,AMZN
12
+ 2024-05-06 00:00:00-04:00,186.27999877929688,188.75,184.8000030517578,188.6999969482422,34725300,0.0,0.0,AMZN
13
+ 2024-05-07 00:00:00-04:00,188.9199981689453,189.94000244140625,187.30999755859375,188.75999450683594,34048900,0.0,0.0,AMZN
14
+ 2024-05-08 00:00:00-04:00,187.44000244140625,188.42999267578125,186.38999938964844,188.0,26136400,0.0,0.0,AMZN
15
+ 2024-05-09 00:00:00-04:00,188.8800048828125,191.6999969482422,187.44000244140625,189.5,43368400,0.0,0.0,AMZN
16
+ 2024-05-10 00:00:00-04:00,189.16000366210938,189.88999938964844,186.92999267578125,187.47999572753906,34141800,0.0,0.0,AMZN
17
+ 2024-05-13 00:00:00-04:00,188.0,188.30999755859375,185.36000061035156,186.57000732421875,24898600,0.0,0.0,AMZN
18
+ 2024-05-14 00:00:00-04:00,183.82000732421875,187.72000122070312,183.4499969482422,187.07000732421875,38698200,0.0,0.0,AMZN
19
+ 2024-05-15 00:00:00-04:00,185.97000122070312,186.72000122070312,182.72999572753906,185.99000549316406,75459900,0.0,0.0,AMZN
20
+ 2024-05-16 00:00:00-04:00,185.60000610351562,187.30999755859375,183.4600067138672,183.6300048828125,38834500,0.0,0.0,AMZN
21
+ 2024-05-17 00:00:00-04:00,183.75999450683594,185.3000030517578,183.35000610351562,184.6999969482422,33175700,0.0,0.0,AMZN
22
+ 2024-05-20 00:00:00-04:00,184.33999633789062,186.6699981689453,183.27999877929688,183.5399932861328,30511800,0.0,0.0,AMZN
23
+ 2024-05-21 00:00:00-04:00,182.3000030517578,183.25999450683594,180.75,183.14999389648438,50839100,0.0,0.0,AMZN
24
+ 2024-05-22 00:00:00-04:00,183.8800048828125,185.22000122070312,181.97000122070312,183.1300048828125,28148800,0.0,0.0,AMZN
25
+ 2024-05-23 00:00:00-04:00,183.66000366210938,184.75999450683594,180.0800018310547,181.0500030517578,33670200,0.0,0.0,AMZN
26
+ 2024-05-24 00:00:00-04:00,181.64999389648438,182.44000244140625,180.3000030517578,180.75,27434100,0.0,0.0,AMZN
27
+ 2024-05-28 00:00:00-04:00,179.92999267578125,182.24000549316406,179.49000549316406,182.14999389648438,29927000,0.0,0.0,AMZN
28
+ 2024-05-29 00:00:00-04:00,181.6999969482422,184.0800018310547,181.5500030517578,182.02000427246094,32009300,0.0,0.0,AMZN
29
+ 2024-05-30 00:00:00-04:00,181.30999755859375,181.33999633789062,178.36000061035156,179.32000732421875,29249200,0.0,0.0,AMZN
30
+ 2024-05-31 00:00:00-04:00,178.3000030517578,179.2100067138672,173.8699951171875,176.44000244140625,58903900,0.0,0.0,AMZN
31
+ 2024-06-03 00:00:00-04:00,177.6999969482422,178.6999969482422,175.9199981689453,178.33999633789062,30786600,0.0,0.0,AMZN
32
+ 2024-06-04 00:00:00-04:00,177.63999938964844,179.82000732421875,176.44000244140625,179.33999633789062,27198400,0.0,0.0,AMZN
33
+ 2024-06-05 00:00:00-04:00,180.10000610351562,181.5,178.75,181.27999877929688,32116400,0.0,0.0,AMZN
34
+ 2024-06-06 00:00:00-04:00,181.75,185.0,181.49000549316406,185.0,31371200,0.0,0.0,AMZN
35
+ 2024-06-07 00:00:00-04:00,184.89999389648438,186.2899932861328,183.36000061035156,184.3000030517578,28021500,0.0,0.0,AMZN
36
+ 2024-06-10 00:00:00-04:00,184.07000732421875,187.22999572753906,183.7899932861328,187.05999755859375,34494500,0.0,0.0,AMZN
37
+ 2024-06-11 00:00:00-04:00,187.05999755859375,187.77000427246094,184.5399932861328,187.22999572753906,27265100,0.0,0.0,AMZN
38
+ 2024-06-12 00:00:00-04:00,188.02000427246094,188.35000610351562,185.42999267578125,186.88999938964844,33984200,0.0,0.0,AMZN
39
+ 2024-06-13 00:00:00-04:00,186.08999633789062,187.6699981689453,182.6699981689453,183.8300018310547,39721500,0.0,0.0,AMZN
40
+ 2024-06-14 00:00:00-04:00,183.0800018310547,183.72000122070312,182.22999572753906,183.66000366210938,25456400,0.0,0.0,AMZN
41
+ 2024-06-17 00:00:00-04:00,182.52000427246094,185.0,181.22000122070312,184.05999755859375,35601900,0.0,0.0,AMZN
42
+ 2024-06-18 00:00:00-04:00,183.74000549316406,184.2899932861328,181.42999267578125,182.80999755859375,36659200,0.0,0.0,AMZN
43
+ 2024-06-20 00:00:00-04:00,182.91000366210938,186.50999450683594,182.72000122070312,186.10000610351562,44726800,0.0,0.0,AMZN
44
+ 2024-06-21 00:00:00-04:00,187.8000030517578,189.27999877929688,185.86000061035156,189.0800018310547,72931800,0.0,0.0,AMZN
45
+ 2024-06-24 00:00:00-04:00,189.3300018310547,191.0,185.3300018310547,185.57000732421875,50610400,0.0,0.0,AMZN
46
+ 2024-06-25 00:00:00-04:00,186.80999755859375,188.83999633789062,185.4199981689453,186.33999633789062,45898500,0.0,0.0,AMZN
47
+ 2024-06-26 00:00:00-04:00,186.9199981689453,194.8000030517578,186.25999450683594,193.61000061035156,65103900,0.0,0.0,AMZN
48
+ 2024-06-27 00:00:00-04:00,195.00999450683594,199.83999633789062,194.1999969482422,197.85000610351562,74397500,0.0,0.0,AMZN
49
+ 2024-06-28 00:00:00-04:00,197.72999572753906,198.85000610351562,192.5,193.25,76930200,0.0,0.0,AMZN
50
+ 2024-07-01 00:00:00-04:00,193.49000549316406,198.3000030517578,192.82000732421875,197.1999969482422,41192000,0.0,0.0,AMZN
51
+ 2024-07-02 00:00:00-04:00,197.27999877929688,200.42999267578125,195.92999267578125,200.0,45600000,0.0,0.0,AMZN
52
+ 2024-07-03 00:00:00-04:00,199.94000244140625,200.02999877929688,196.75999450683594,197.58999633789062,31597900,0.0,0.0,AMZN
53
+ 2024-07-05 00:00:00-04:00,198.64999389648438,200.5500030517578,198.1699981689453,200.0,39858900,0.0,0.0,AMZN
54
+ 2024-07-08 00:00:00-04:00,200.0399932861328,201.1999969482422,197.9600067138672,199.2899932861328,34767300,0.0,0.0,AMZN
55
+ 2024-07-09 00:00:00-04:00,199.39999389648438,200.57000732421875,199.0500030517578,199.33999633789062,32700100,0.0,0.0,AMZN
56
+ 2024-07-10 00:00:00-04:00,200.0,200.11000061035156,197.69000244140625,199.7899932861328,32883800,0.0,0.0,AMZN
57
+ 2024-07-11 00:00:00-04:00,200.08999633789062,200.27000427246094,192.86000061035156,195.0500030517578,44565000,0.0,0.0,AMZN
58
+ 2024-07-12 00:00:00-04:00,194.8000030517578,196.47000122070312,193.8300018310547,194.49000549316406,30598500,0.0,0.0,AMZN
59
+ 2024-07-15 00:00:00-04:00,194.55999755859375,196.19000244140625,190.8300018310547,192.72000122070312,40683200,0.0,0.0,AMZN
60
+ 2024-07-16 00:00:00-04:00,195.58999633789062,196.6199951171875,192.24000549316406,193.02000427246094,33994700,0.0,0.0,AMZN
61
+ 2024-07-17 00:00:00-04:00,191.35000610351562,191.5800018310547,185.99000549316406,187.92999267578125,48076100,0.0,0.0,AMZN
62
+ 2024-07-18 00:00:00-04:00,189.58999633789062,189.67999267578125,181.4499969482422,183.75,51043600,0.0,0.0,AMZN
63
+ 2024-07-19 00:00:00-04:00,181.13999938964844,184.92999267578125,180.11000061035156,183.1300048828125,42994700,0.0,0.0,AMZN
historicalprices.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ from bs4 import BeautifulSoup
3
+ import re
4
+
5
+ def get_historical_prices(product_url):
6
+ headers = {
7
+ 'User-Agent': 'Your User Agent'
8
+ }
9
+ response = requests.get(product_url, headers=headers)
10
+
11
+ if response.status_code == 200:
12
+ soup = BeautifulSoup(response.content, 'html.parser')
13
+ price_data = {}
14
+
15
+ # Extract historical price data
16
+ price_blocks = soup.find_all('div', class_='price-history__row')
17
+
18
+ for block in price_blocks:
19
+ date = block.find('span', class_='price-history__date').text.strip()
20
+ price = block.find('span', class_='price-history__price').text.strip()
21
+ price_data[date] = price
22
+
23
+ return price_data
24
+ else:
25
+ print(f"Failed to retrieve data. Status code: {response.status_code}")
26
+ return None
27
+
28
+ # Example usage
29
+ if __name__ == '__main__':
30
+ product_url = 'https://camelcamelcamel.com/product/ASIN'
31
+ historical_prices = get_historical_prices(product_url)
32
+
33
+ if historical_prices:
34
+ print("Historical Prices:")
35
+ for date, price in historical_prices.items():
36
+ print(f"{date}: {price}")
requirements.txt CHANGED
@@ -11,7 +11,7 @@ plotly==5.22.0
11
  pandas==2.2.2
12
  yfinance==0.2.40
13
  langchain-openai==0.1.16
14
- langgraph==0.1.18
15
  pydantic==2.8.2
16
  langchain.tools==0.1.34
17
  statsmodels==0.14.2
@@ -19,4 +19,5 @@ matplotlib==3.9.1
19
  python-dotenv==1.0.1
20
  alpaca_trade_api
21
  transformers
22
- pandas
 
 
11
  pandas==2.2.2
12
  yfinance==0.2.40
13
  langchain-openai==0.1.16
14
+ langgraph==0.1.8
15
  pydantic==2.8.2
16
  langchain.tools==0.1.34
17
  statsmodels==0.14.2
 
19
  python-dotenv==1.0.1
20
  alpaca_trade_api
21
  transformers
22
+ googlenews
23
+
search_news.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ['Investing in Amazon Stock (AMZN)', 'Amazon.com, Inc. (NASDAQ:AMZN) Shares Could Be 40% Below Their Intrinsic Value Estimate', 'Why Amazon Stock Is the Biggest Bargain After Amazon Prime Day', 'Is Amazon Stock A Buy As Analysts Project Strong Prime Day Sales?', "Amazon cracks down on 'coffee badging' employees by tracking individual hours spent in the office", 'Amazon Stock (AMZN) Price Prediction and Forecast 2025-2030', 'Amazon CEO Andy Jassy says being ‘ravenous’ about one thing will determine if your career is a success', 'Amazon says this year’s Prime Day was its biggest ever', 'Amazon Prime Day 2024 returns this July', '4 stocks to watch on Thursday: NFLX, AMZN and more']
tools/evaluator.py CHANGED
@@ -40,11 +40,41 @@ def evaluator_tools():
40
 
41
  args_schema: Optional[Type[BaseModel]] = compare_predictionInput
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  tools_evaluate = [
44
  StructuredTool.from_function(
45
  func=compare_predictionTool,
46
  args_schema=compare_predictionInput,
47
  description="Function to evaluate predicted stock prices and print final result.",
48
- )
 
 
 
 
 
49
  ]
50
  return tools_evaluate
 
40
 
41
  args_schema: Optional[Type[BaseModel]] = compare_predictionInput
42
 
43
+ def buy_or_sell(current_price: float, prediction:float) -> str:
44
+ if current_price>prediction:
45
+ position="sell"
46
+ else:
47
+ position="buy"
48
+ return str(position)
49
+
50
+ class buy_or_sellInput(BaseModel):
51
+ """Input for printing final prediction number."""
52
+ current_price: float = Field(..., description="Current stock price")
53
+ prediction: float = Field(..., description="Final price prediction from Evaluator")
54
+
55
+ class buy_or_sellTool(BaseTool):
56
+ name = "Comparing current price with prediction"
57
+ description = """Useful for deciding if to buy/sell stocks based on the prediction result."""
58
+
59
+ def _run(self, current_price=float,prediction=float):
60
+ position = buy_or_sell(current_price,prediction)
61
+ return {"position": position}
62
+
63
+ def _arun(self,current_price=float,prediction=float):
64
+ raise NotImplementedError("This tool does not support async")
65
+
66
+ args_schema: Optional[Type[BaseModel]] = buy_or_sellInput
67
+
68
  tools_evaluate = [
69
  StructuredTool.from_function(
70
  func=compare_predictionTool,
71
  args_schema=compare_predictionInput,
72
  description="Function to evaluate predicted stock prices and print final result.",
73
+ ),
74
+ StructuredTool.from_function(
75
+ func=buy_or_sellTool,
76
+ args_schema=buy_or_sellInput,
77
+ description="Function to evaluate client stock position.",
78
+ ),
79
  ]
80
  return tools_evaluate
tools/investment_advisor.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic.v1 import BaseModel, Field
2
+ from langchain.tools import BaseTool
3
+ from typing import Optional, Type
4
+ from langchain.tools import StructuredTool
5
+ import yfinance as yf
6
+ from typing import List
7
+ from datetime import datetime,timedelta
8
+
9
+ def investment_advisor_tools():
10
+
11
+
12
+ def news_summary(df_search):
13
+ "Take df_search from the user input message. Summarize news on the selected stockticker and provide Sentiment: positive/negative/neutral to the user."
14
+ return eval(df_search)
15
+
16
+ class newsSummaryInput(BaseModel):
17
+ """Input for summarizing articles."""
18
+ df_search: str = Field(..., description="News articles.")
19
+
20
+ class newsSummaryTool(BaseTool):
21
+ name = "Summarize news on the stockticker"
22
+ description = """Useful for summarizing the newest article on a selected stockticker."""
23
+
24
+ def _run(self, df_search=str):
25
+ position = news_summary(df_search)
26
+ return {"position": position}
27
+
28
+ def _arun(self,df_search=str):
29
+ raise NotImplementedError("This tool does not support async")
30
+
31
+ args_schema: Optional[Type[BaseModel]] = newsSummaryInput
32
+
33
+
34
+
35
+ tools_reccommend = [
36
+ StructuredTool.from_function(
37
+ func=newsSummaryTool,
38
+ args_schema=newsSummaryInput,
39
+ description="Summarize articles.",
40
+ )
41
+ ]
42
+ return tools_reccommend
tools/stock_sentiment_evalutor.py CHANGED
@@ -1,5 +1,4 @@
1
  from transformers import pipeline
2
- from client import AlpacaNewsFetcher
3
  from alpaca_trade_api import REST
4
  import os
5
  from dotenv import load_dotenv
@@ -7,7 +6,7 @@ from datetime import datetime
7
  import pandas as pd
8
  import matplotlib.pyplot as plt
9
  from datetime import date, timedelta
10
- from pydantic import BaseModel, Field
11
  from langchain.tools import BaseTool
12
  from typing import Optional, Type
13
  from langchain.tools import StructuredTool
@@ -130,7 +129,6 @@ def sentimental_analysis_tools():
130
  Returns:
131
  - dict: A dictionary containing sentiment analysis results.
132
  """
133
- print(sentiment_analysis_result)
134
  df = pd.DataFrame(sentiment_analysis_result)
135
  df['Timestamp'] = pd.to_datetime(df['Timestamp'])
136
  df['Date'] = df['Timestamp'].dt.date
@@ -170,7 +168,7 @@ def sentimental_analysis_tools():
170
 
171
  #Function to get the stock sentiment
172
  def get_stock_sentiment(stockticker: str):
173
-
174
  #Initialize AlpacaNewsFetcher, a class for fetching news articles related to a specific stock from Alpaca API.
175
  news_fetcher = AlpacaNewsFetcher()
176
 
@@ -211,9 +209,14 @@ def sentimental_analysis_tools():
211
 
212
  #Get dominant sentiment
213
  dominant_sentiment = news_sentiment_analyzer.get_dominant_sentiment(sentiment_analysis_result)
 
 
 
 
 
214
 
215
  final_result = {
216
- 'Sentiment-analysis-result' : analysis_result,
217
  'Dominant-sentiment' : dominant_sentiment['sentiment']
218
  }
219
 
@@ -237,6 +240,9 @@ def sentimental_analysis_tools():
237
  def _run(self, stockticker: str):
238
  # print("i'm running")
239
  sentiment_response = get_stock_sentiment(stockticker)
 
 
 
240
 
241
  return sentiment_response
242
 
 
1
  from transformers import pipeline
 
2
  from alpaca_trade_api import REST
3
  import os
4
  from dotenv import load_dotenv
 
6
  import pandas as pd
7
  import matplotlib.pyplot as plt
8
  from datetime import date, timedelta
9
+ from pydantic.v1 import BaseModel, Field
10
  from langchain.tools import BaseTool
11
  from typing import Optional, Type
12
  from langchain.tools import StructuredTool
 
129
  Returns:
130
  - dict: A dictionary containing sentiment analysis results.
131
  """
 
132
  df = pd.DataFrame(sentiment_analysis_result)
133
  df['Timestamp'] = pd.to_datetime(df['Timestamp'])
134
  df['Date'] = df['Timestamp'].dt.date
 
168
 
169
  #Function to get the stock sentiment
170
  def get_stock_sentiment(stockticker: str):
171
+
172
  #Initialize AlpacaNewsFetcher, a class for fetching news articles related to a specific stock from Alpaca API.
173
  news_fetcher = AlpacaNewsFetcher()
174
 
 
209
 
210
  #Get dominant sentiment
211
  dominant_sentiment = news_sentiment_analyzer.get_dominant_sentiment(sentiment_analysis_result)
212
+
213
+ #Build response string for news sentiment
214
+ output_string = ""
215
+ for result in analysis_result:
216
+ output_string = output_string + f'{result["Timestamp"]} : {result["News- Title:Summary"]} : {result["Sentiment"]}' + '\n'
217
 
218
  final_result = {
219
+ 'Sentiment-analysis-result' : output_string,
220
  'Dominant-sentiment' : dominant_sentiment['sentiment']
221
  }
222
 
 
240
  def _run(self, stockticker: str):
241
  # print("i'm running")
242
  sentiment_response = get_stock_sentiment(stockticker)
243
+ print("++++++++++++++++++++++++++++++++++++++++++++++++++++++")
244
+ print(str(sentiment_response))
245
+ print("++++++++++++++++++++++++++++++++++++++++++++++++++++++")
246
 
247
  return sentiment_response
248
 
utils.py CHANGED
@@ -28,9 +28,7 @@ def plot_candlestick_stock_price(historical_data):
28
  fig.show()
29
 
30
  def historical_stock_prices(stockticker, days_ago):
31
- """Upload accurate data to accurate dates from yahoo finance.
32
- Receive data on the last week and give them to forecasting experts.
33
- Receive data on the last 90 days and give them to visualization expert."""
34
  ticker = yf.Ticker(stockticker)
35
  end_date = datetime.now()
36
  start_date = end_date - timedelta(days=days_ago)
 
28
  fig.show()
29
 
30
  def historical_stock_prices(stockticker, days_ago):
31
+ """Upload accurate data to accurate dates from yahoo finance."""
 
 
32
  ticker = yf.Ticker(stockticker)
33
  end_date = datetime.now()
34
  start_date = end_date - timedelta(days=days_ago)