Megan Chiovaro commited on
Commit
e61143f
1 Parent(s): a06b36f

Add first app

Browse files
Files changed (3) hide show
  1. Dockerfile +13 -0
  2. app.py +182 -0
  3. 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