-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfinance_agent.py
More file actions
357 lines (273 loc) Β· 13.1 KB
/
finance_agent.py
File metadata and controls
357 lines (273 loc) Β· 13.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
import os
from groq import Groq
import yfinance as yf
import datetime
import pandas as pd
import json
from dotenv import load_dotenv
load_dotenv()
from scrapeNews import extract_news
from tickerMap import company_ticker_map
from functions import analyze_financials,analyze_sector,get_Full_ticker,get_stock_price
client = Groq(api_key=os.environ.get("GROQ_API_KEY"))
tools=[
{
"type":"function",
"function":{
"name":"get_stock_price",
"description":"Get the stock price of the given stock",
"parameters":{
"type":"object",
"properties":{
"symbol":{
"type":"string",
"description":"Fetch real-time stock price by using the ticker symbol. Always use this when the user asks about a stock or share price."
}
},
"required":["symbol"]
}
}
},
{
"type":"function",
"function":{
"name":"analyze_financials",
"description":"Summarize the key financial metrics for a given stock including FCF, Net Income, P/E Ratio, etc.",
"parameters":{
"type":"object",
"properties":{
"symbol":{
"type":"string",
"description":"Analyze key financial metrics of a company using its stock ticker. Use this to provide investment insights based on revenue, profit, growth trends and different ratios"
}
},
"required":["symbol"]
}
}
},
{
"type": "function",
"function": {
"name": "analyze_sector",
"description": "Analyze the sector by inferring it from a stock ticker (e.g., 'TCS sector analysis','Tell me how the sector related to CIPLA is doing ').",
"parameters": {
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "A stock ticker (e.g., TCS.NS or AAPL). If provided, the sector will be inferred from this ticker."
},
"sector": {
"type": "string",
"description": "The name of the sector (e.g., 'it', 'pharma', 'banking'). If no ticker is provided, this will be used directly."
}
},
"required": []
}
}
}
]
def sentiment_analysis(symbol):
news = extract_news(symbol)
chat_completion = client.chat.completions.create(
messages=[
{
"role":"system",
"content":"You are a financial news sentiment analyzer and give brief explantion as to how you classified them"
},
{
"role":"user",
"content":f"""Classify the market sentiment as Neutral,Positive or Negative according to the
//{news}//
Also, briefly explain why.
When giving the explantions be crisp and to point
Summarize the most influential news item
Use emojis like β
π π° π π’ for positive, β β οΈ π π» π΄ for negative andπ π‘ π€ for neutral and give good spacing
"""
}
],
model="llama3-70b-8192",
max_tokens=300
)
return chat_completion.choices[0].message.content
def classify_levl(user_prompt):
level_identifier_prompt= f""""
Classify the user's knowledge as:
- **Beginner**: Asks basic questions like "Whats the price of the stock",,asks to explain basic finance terms like P/E ratio,free cash flow,Income statement and similar terms and says "what to buy",phrases like "I am new to this","explain in simple terms" and so on.
-**Amateur**: Uses terms like "risk vs return","undervalued","overvalued","Company financials and stability" etc.
--**Seasoned**: Asks detailed questions based on phrases such as "capital allocation","long term stability of stock","FCF","beta" and similar advanced financial terms and short forms.
Analyze // {user_prompt} //
Which category does it most closely reflect? Respond only with one of: **beginner**, **amateur**, or **seasoned**.
If unclear dont make any assumption and carry on
"""
chat_completion = client.chat.completions.create(
messages=[
{
"role":"system",
"content":"You classify the level of the investor based on user queries"
},
{
"role":"user",
"content":level_identifier_prompt
}
],
model="llama3-70b-8192",
max_tokens=5
)
return chat_completion.choices[0].message.content.strip().lower()
def run_finance_agent(user_prompt,conversation_hist):
level = classify_levl(user_prompt)
print(len(conversation_hist))
sector_analysis_added = False
print(user_prompt)
conversation_hist=conversation_hist[-3:]
chat_completion = client.chat.completions.create(
messages=[
{ "role":"system",
"content":f"""
You are a smart AI finance chatbot.
The user is a **{level}** investor:
- Beginner: explain financial terms briefly and clearly.
- Amateur: use relevant financial vocabulary, but keep things clear.
- Seasoned: go deep into financial metrics, use ratios, and be concise.
Your goal is to analyze the stock data, adapt your tone accordingly, and provide a summary + investment verdict.
Focus on Explainibility rather than only data
- Use good spacing and give section wise content
-Please include relevant emojis to make the response more engaging.
Use emojis like π for growth, π° for profits, β οΈ for risk, β
for strong fundamentals, π for decline, and βοΈ for final verdicts.
"""
},
*conversation_hist,
{
"role":"user",
"content":user_prompt
,
}
],
model="llama3-70b-8192"
,
tools=tools,
tool_choice="auto",
max_completion_tokens=500
)
#print(chat_completion.choices[0].message)
message = chat_completion.choices[0].message
if message.tool_calls is None:
return message.content # This is a true fallback β no tool was ever planned
tool_outputs = []
sentiment_added = False
stock_price=False
analyze_financials_added=False
for tool_call in message.tool_calls:
function_name = tool_call.function.name
argument = json.loads(tool_call.function.arguments)
print(function_name)
symbol = argument.get('symbol')
symbol=get_Full_ticker(symbol)
print(symbol)
if argument.get('symbol') and not sentiment_added:
sentiment = sentiment_analysis(argument['symbol'])
#print(sentiment)
tool_outputs.append(f"π° **Market Sentiment Analysis for {argument['symbol']}**:\n{sentiment}")
sentiment_added=True
if function_name=='get_stock_price' and not stock_price:
result = get_stock_price(symbol)
tool_outputs.append(f"π Stock Price Info:\n{result}")
stock_price=True
print(result)
elif function_name=='analyze_sector':
if argument.get('symbol'):
sector_analysis=analyze_sector(argument['symbol'],"")
prompt = f"""
π **Sector Financial Analysis**
Here is a summary of the financial performance of the top companies in this sector:
{sector_analysis}
β
Use this information to evaluate the overall health of the sector based on profitability, valuation, and growth metrics.
π If a stock ticker was provided, compare its performance with these top companies across key metrics like Free Cash Flow, P/E Ratio, and Revenue Growth like:
π Mention 1β2 quick insights at the end such as:
- Which company leads in revenue growth?
- Which has the strongest cash flow or best valuation?
"""
tool_outputs.append(prompt)
sector_analysis_added = True
if symbol!=None and not stock_price:
result = get_stock_price(symbol)
tool_outputs.append(f"π Stock Price Info:\n{result}")
stock_price=True
print(result)
if symbol!=None and not analyze_financials_added:
summary = analyze_financials(symbol)
prompt = f"""
Here is the financial summary of {argument['symbol']}:
{summary}
Give an investment attractiveness score out of 100 and explain briefly.
- Use **bold headings** for sections like Stock Price,Sentiment Analysis,Financial Insights, Verdict, etc.
"Use emojis like β
π π° π π’ for positive, β β οΈ π π» π΄ for negative, and π π‘ π€ for neutral. Add them at the start of bullet points or section headers."
- Use bullet points * or - for each fact or insight.
- Add line breaks between paragraphs for better readability.
-Please include relevant emojis to make the response more engaging.
Use emojis like π for growth, π° for profits, β οΈ for risk, β
for strong fundamentals, π for decline, and βοΈ for final verdicts. """
tool_outputs.append(prompt)
if message.tool_calls is None and "sector" in user_prompt.lower() and not sector_analysis_added:
# Try to extract ticker from prompt
from difflib import get_close_matches
def extract_ticker_from_prompt(prompt):
prompt = prompt.lower()
company_names = list(company_ticker_map.keys())
matches = get_close_matches(prompt, company_names, n=1, cutoff=0.6)
if matches:
return company_ticker_map[matches[0]]
return None
fallback_ticker = extract_ticker_from_prompt(user_prompt)
if fallback_ticker:
sector_analysis = analyze_sector(fallback_ticker, "")
prompt = f"""
π **Sector Financial Analysis (via {fallback_ticker})**
Here is a summary of the financial performance of the top companies in this sector:
{sector_analysis}
β
Use this information to evaluate the overall health of the sector based on profitability, valuation, and growth metrics.
π Compare this company with sector peers on:
- Free Cash Flow
- P/E Ratio
- Revenue Growth
- Net Income
- Debt-to-Equity
- Market Cap
π― Format insights cleanly with a markdown table if possible.
"""
tool_outputs.append(prompt)
final_prompt = "\n\n".join(tool_outputs)
followup_messages = [
{
"role":"system",
"content": """
You are a helpful financial assistant. Use clear, engaging, and structured formatting with relevant emojis.
- Use emojis like β
π π° π π’ for positive, β β οΈ π π» π΄ for negative, and π π‘ π€ for neutral.
- Start section headings and bullet points with appropriate emojis.
-Use a strict rule based scoring out of 100 using financial data:
Reduce scoring as much as possible and be realistic
25 for Profitability - Above 20 only if Net Profit is positive
20 for Cash Flow
15 for Valuation
15 for Growth
20 for Shareholder Returns
- Add section headers like **Stock Price**, **Market Sentiment**, **Financials**, and **Final Verdict**.
- Make your response not less than 300 words.
- When doing sentiment analysis try to explain them in sentences rather than giving short verdicts
-If relevant news not found skip it.
"""
},
{
"role":"user",
"content": final_prompt,
}
]
summary_response = client.chat.completions.create(
model="llama3-70b-8192",
messages=followup_messages,
max_tokens=800
)
assistant_reply= summary_response.choices[0].message.content
return assistant_reply
#print(run_finance_agent("Can you analyze TCS stock price",[]))
#print(sentiment_analysis("TCS"))