Spaces:
Running
Running
Megan Chiovaro
commited on
Commit
•
e61143f
1
Parent(s):
a06b36f
Add first app
Browse files- Dockerfile +13 -0
- app.py +182 -0
- requirements.txt +4 -0
Dockerfile
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.9
|
2 |
+
|
3 |
+
WORKDIR /code
|
4 |
+
|
5 |
+
COPY ./requirements.txt /code/requirements.txt
|
6 |
+
|
7 |
+
#RUN python3 -m pip install --no-cache-dir --upgrade pip
|
8 |
+
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
9 |
+
#RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
10 |
+
|
11 |
+
COPY . .
|
12 |
+
|
13 |
+
CMD ["panel", "serve", "/code/app.py", "--address", "0.0.0.0", "--port", "7860", "--allow-websocket-origin", "mchiovaro-stock-assistant.hf.space"]
|
app.py
ADDED
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#%% packages
|
2 |
+
import yfinance as yf
|
3 |
+
import anthropic
|
4 |
+
import panel as pn
|
5 |
+
import datetime
|
6 |
+
import os
|
7 |
+
import matplotlib.pyplot as plt
|
8 |
+
|
9 |
+
pn.extension() # this activates chat interface
|
10 |
+
|
11 |
+
#%% set client
|
12 |
+
client = anthropic.Anthropic(api_key=os.environ.get("CLAUDE_API_KEY"))
|
13 |
+
|
14 |
+
#%% model params
|
15 |
+
MODEL = "claude-3-haiku-20240307"
|
16 |
+
MAX_TOKENS = 1024
|
17 |
+
|
18 |
+
#%% pricing function (child)
|
19 |
+
def get_data(ticker:str, start='2024-01-01', end='2024-06-16'):
|
20 |
+
stock_data = yf.download(ticker, start=start, end=end)
|
21 |
+
return stock_data
|
22 |
+
|
23 |
+
#%% ticker function (child)
|
24 |
+
def get_ticker(description:str):
|
25 |
+
response = client.messages.create(
|
26 |
+
|
27 |
+
# set up model
|
28 |
+
model=MODEL,
|
29 |
+
max_tokens=MAX_TOKENS,
|
30 |
+
|
31 |
+
# define the instructions and properties
|
32 |
+
tools=[
|
33 |
+
{
|
34 |
+
"name": "get_ticker", # name of the func
|
35 |
+
"description": "Provide the stock ticker for the most probable company which is described in the input text. If in doubt which company to choose, use the company with the highest market capitalization.",
|
36 |
+
"input_schema": {
|
37 |
+
"type": "object",
|
38 |
+
"properties": { # define what properties to define
|
39 |
+
"ticker": {
|
40 |
+
"type": "string",
|
41 |
+
"description": "Ticker symbol of the company, e.g. TSLA",
|
42 |
+
}
|
43 |
+
},
|
44 |
+
"required": ["ticker"],
|
45 |
+
},
|
46 |
+
}
|
47 |
+
],
|
48 |
+
messages=[{"role": "user", "content": description}],
|
49 |
+
)
|
50 |
+
return response.content[0].input['ticker']
|
51 |
+
|
52 |
+
#%% get advanced metrics
|
53 |
+
def get_adv_metrics(df):
|
54 |
+
|
55 |
+
# Calculate daily returns
|
56 |
+
df['Daily Return'] = df['Adj Close'].pct_change()
|
57 |
+
|
58 |
+
# Calculate average daily return
|
59 |
+
avg_daily_return = df['Daily Return'].mean()
|
60 |
+
|
61 |
+
# Calculate volatility (standard deviation of returns)
|
62 |
+
volatility = df['Daily Return'].std()
|
63 |
+
|
64 |
+
# Calculate Sharpe ratio (assumes risk-free rate is 0)
|
65 |
+
sharpe_ratio = avg_daily_return / volatility
|
66 |
+
|
67 |
+
# Calculate cumulative returns
|
68 |
+
df['Cumulative Return'] = (1 + df['Daily Return']).cumprod()
|
69 |
+
|
70 |
+
# Calculate maximum drawdown
|
71 |
+
rolling_max = df['Cumulative Return'].cummax()
|
72 |
+
drawdown = df['Cumulative Return'] / rolling_max - 1
|
73 |
+
max_drawdown = drawdown.min()
|
74 |
+
|
75 |
+
return avg_daily_return, volatility, sharpe_ratio, max_drawdown
|
76 |
+
|
77 |
+
#%% get plot of performance
|
78 |
+
def get_year_plot():
|
79 |
+
|
80 |
+
# create figure
|
81 |
+
figsize=(20,15)
|
82 |
+
|
83 |
+
try:
|
84 |
+
|
85 |
+
closing_price = df['Adj Close']
|
86 |
+
df.reset_index(inplace=True)
|
87 |
+
date = df['Date']
|
88 |
+
|
89 |
+
# create a simple plot
|
90 |
+
fig, ax = plt.subplots(figsize=figsize)
|
91 |
+
ax.plot(date, closing_price)
|
92 |
+
|
93 |
+
# wrap up
|
94 |
+
#ax.set(xlabel ='date', ylabel ='closing price', title = "Stock Value")
|
95 |
+
ax.set_xlabel(xlabel ='date', fontsize=25)
|
96 |
+
ax.set_ylabel(ylabel ='closing price', fontsize=25)
|
97 |
+
ax.set_title(label ='Stock Value', fontsize=40)
|
98 |
+
ax.xaxis.set_tick_params(labelsize=20)
|
99 |
+
|
100 |
+
#ax.set('date', fontsize = 50)
|
101 |
+
plt.close(fig)
|
102 |
+
|
103 |
+
except:
|
104 |
+
# generate a blank figure before user has entered prompt
|
105 |
+
fig, ax = plt.subplots(figsize=(20, 15))
|
106 |
+
ax.axis('off') # Turn off axis
|
107 |
+
ax.set_facecolor('white') # Set background color to white
|
108 |
+
plt.close(fig)
|
109 |
+
|
110 |
+
return fig
|
111 |
+
#%%
|
112 |
+
def update_plot():
|
113 |
+
# Clear the current plot
|
114 |
+
plt.clf()
|
115 |
+
# Get the new performance data for the company
|
116 |
+
new_plot = get_year_plot()
|
117 |
+
# Update the plot pane
|
118 |
+
plot.object = new_plot
|
119 |
+
|
120 |
+
#%% get stock performance in this year (callback - parent)
|
121 |
+
def get_performance(question, user, interface):
|
122 |
+
|
123 |
+
# get date and ticker
|
124 |
+
current_day = str(datetime.date.today())
|
125 |
+
last_year_date = str(f"{datetime.date.today().year-1}-{datetime.date.today().month}-{datetime.date.today().day}")
|
126 |
+
ticker = get_ticker(question)
|
127 |
+
|
128 |
+
# get the price info
|
129 |
+
global df
|
130 |
+
df = get_data(ticker, start=last_year_date, end=current_day)
|
131 |
+
|
132 |
+
# update the plot
|
133 |
+
update_plot()
|
134 |
+
|
135 |
+
# get basic pricing info
|
136 |
+
price_at_beginning_of_last = df["Close"].iloc[0]
|
137 |
+
price_recent = df["Close"].iloc[-1]
|
138 |
+
performance_since_last_year = (price_recent / price_at_beginning_of_last - 1) * 100
|
139 |
+
|
140 |
+
# get advanced metrics
|
141 |
+
avg_daily_return, volatility, sharpe_ratio, max_drawdown = get_adv_metrics(df)
|
142 |
+
|
143 |
+
# clear up memory
|
144 |
+
del [df]
|
145 |
+
|
146 |
+
# feed the ticker, price, and performance info to the llm
|
147 |
+
message = client.messages.create(
|
148 |
+
model=MODEL,
|
149 |
+
max_tokens=MAX_TOKENS,
|
150 |
+
messages=[
|
151 |
+
{
|
152 |
+
"role": "user",
|
153 |
+
"content": f"You are a stock analyst and financial advisor. You are considering the company and performance for the stock {ticker}. First, provide an overview of the company. Review how the stock is {performance_since_last_year}% in the last year, starting with {price_at_beginning_of_last} one year ago and the price on {current_day} is {price_recent}. Be sure to list these out in bullet points before evaluating them. Then, evaluate how this year, the average daily return is {avg_daily_return} per day, volatility is {volatility}, Sharpe ratio is {sharpe_ratio}, and Max Drawdown is {max_drawdown}. Be sure to list these out in bullet points before evaluating them. Round everything to one decimal place when reporting. As you review, provide guidance on if investmenting now is a good choice or if they should wait, based on risk tolerance. Explain everything simply, as if talking to someone with little knowledge about investing."}
|
154 |
+
|
155 |
+
])
|
156 |
+
|
157 |
+
# return the performance eval
|
158 |
+
return message.content[0].text
|
159 |
+
|
160 |
+
#%% set up chat interface where the call is to get_performance()
|
161 |
+
chat_interface = pn.chat.ChatInterface(
|
162 |
+
callback = get_performance,
|
163 |
+
callback_user = "LLM"
|
164 |
+
)
|
165 |
+
|
166 |
+
# add elements to the chat interface (prompt and entry bar/submit button)
|
167 |
+
chat_interface.send(
|
168 |
+
"Describe the company you want to know the stock performance for.",
|
169 |
+
user="AI Stock Analyst",
|
170 |
+
respond=False
|
171 |
+
)
|
172 |
+
|
173 |
+
# make plot
|
174 |
+
plot = pn.pane.Matplotlib(get_year_plot(), dpi=44, tight=True)
|
175 |
+
|
176 |
+
#put elements together
|
177 |
+
layout = pn.Row(chat_interface, plot)
|
178 |
+
|
179 |
+
# serve
|
180 |
+
#layout.servable()
|
181 |
+
#layout.show()
|
182 |
+
# %%
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
panel
|
2 |
+
yfinance
|
3 |
+
anthropic
|
4 |
+
matplotlib
|