Update app.py
Browse files
app.py
CHANGED
|
@@ -63,73 +63,147 @@ def download_stock_data(ticker, start_date, end_date):
|
|
| 63 |
df = stock.history(start=start_date, end=end_date)
|
| 64 |
return df
|
| 65 |
|
| 66 |
-
def
|
| 67 |
try:
|
| 68 |
stock = yf.Ticker(ticker)
|
| 69 |
data = stock.history(start=start_date, end=end_date)
|
| 70 |
|
| 71 |
if data.empty:
|
| 72 |
-
return "No data available for the specified date range."
|
| 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 |
# Get the current date
|
| 135 |
current_date = datetime.now().strftime("%Y-%m-%d")
|
|
@@ -146,24 +220,33 @@ custom_css = """
|
|
| 146 |
"""
|
| 147 |
|
| 148 |
# Create Gradio interface with custom Seafoam theme
|
| 149 |
-
with gr.Blocks(theme=seafoam, title="Stock
|
| 150 |
-
gr.Markdown("# Stock
|
| 151 |
-
gr.Markdown("Enter a stock ticker and date range to generate a
|
| 152 |
|
| 153 |
with gr.Row():
|
| 154 |
ticker = gr.Textbox(label="Stock Ticker", value="MSFT", elem_id="ticker-input")
|
| 155 |
start_date = gr.Textbox(label="Start Date", value="2015-01-01", elem_id="start-date-input")
|
| 156 |
end_date = gr.Textbox(label="End Date", value=current_date, elem_id="end-date-input")
|
| 157 |
|
|
|
|
|
|
|
|
|
|
| 158 |
submit_button = gr.Button("Generate Chart", elem_id="generate-button")
|
| 159 |
|
| 160 |
with gr.Row():
|
| 161 |
-
|
| 162 |
|
|
|
|
|
|
|
| 163 |
submit_button.click(
|
| 164 |
-
|
| 165 |
-
inputs=[ticker, start_date, end_date],
|
| 166 |
-
outputs=[
|
|
|
|
|
|
|
|
|
|
|
|
|
| 167 |
)
|
| 168 |
|
| 169 |
# Launch the app
|
|
|
|
| 63 |
df = stock.history(start=start_date, end=end_date)
|
| 64 |
return df
|
| 65 |
|
| 66 |
+
def plot_chart(ticker, start_date, end_date, chart_type):
|
| 67 |
try:
|
| 68 |
stock = yf.Ticker(ticker)
|
| 69 |
data = stock.history(start=start_date, end=end_date)
|
| 70 |
|
| 71 |
if data.empty:
|
| 72 |
+
return "No data available for the specified date range.", None, None, None
|
| 73 |
+
|
| 74 |
+
if chart_type == "Log":
|
| 75 |
+
return plot_logarithmic_chart(data, ticker)
|
| 76 |
+
else:
|
| 77 |
+
return plot_candlestick_chart(data, ticker)
|
| 78 |
+
|
| 79 |
+
except Exception as e:
|
| 80 |
+
return f"An error occurred: {str(e)}", None, None, None
|
| 81 |
+
|
| 82 |
+
def plot_logarithmic_chart(data, ticker):
|
| 83 |
+
x = (data.index - data.index[0]).days
|
| 84 |
+
y = np.log(data['Close'])
|
| 85 |
+
slope, intercept = np.polyfit(x, y, 1)
|
| 86 |
+
|
| 87 |
+
future_days = 365 * 10
|
| 88 |
+
all_days = np.arange(len(x) + future_days)
|
| 89 |
+
log_trend = np.exp(intercept + slope * all_days)
|
| 90 |
+
|
| 91 |
+
inner_upper_band = log_trend * 2
|
| 92 |
+
inner_lower_band = log_trend / 2
|
| 93 |
+
outer_upper_band = log_trend * 4
|
| 94 |
+
outer_lower_band = log_trend / 4
|
| 95 |
+
|
| 96 |
+
extended_dates = pd.date_range(start=data.index[0], periods=len(all_days), freq='D')
|
| 97 |
+
|
| 98 |
+
fig = go.Figure()
|
| 99 |
+
|
| 100 |
+
fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price', line=dict(color='blue')))
|
| 101 |
+
fig.add_trace(go.Scatter(x=extended_dates, y=log_trend, mode='lines', name='Log Trend', line=dict(color='red')))
|
| 102 |
+
fig.add_trace(go.Scatter(x=extended_dates, y=inner_upper_band, mode='lines', name='Inner Upper Band', line=dict(color='#6FB1A7')))
|
| 103 |
+
fig.add_trace(go.Scatter(x=extended_dates, y=inner_lower_band, mode='lines', name='Inner Lower Band', line=dict(color='#6FB1A7')))
|
| 104 |
+
fig.add_trace(go.Scatter(x=extended_dates, y=outer_upper_band, mode='lines', name='Outer Upper Band', line=dict(color='#FFC2A5')))
|
| 105 |
+
fig.add_trace(go.Scatter(x=extended_dates, y=outer_lower_band, mode='lines', name='Outer Lower Band', line=dict(color='#FFC2A5')))
|
| 106 |
+
|
| 107 |
+
fig.update_layout(
|
| 108 |
+
title={
|
| 109 |
+
'text': f'Stock Log Chart: {ticker}',
|
| 110 |
+
'y': 0.95,
|
| 111 |
+
'x': 0.5,
|
| 112 |
+
'xanchor': 'center',
|
| 113 |
+
'yanchor': 'top'
|
| 114 |
+
},
|
| 115 |
+
xaxis_title='Date',
|
| 116 |
+
yaxis_title='Price (Log Scale)',
|
| 117 |
+
yaxis_type="log",
|
| 118 |
+
height=800,
|
| 119 |
+
legend=dict(x=0.01, y=0.99, bgcolor='rgba(255, 255, 255, 0.8)'),
|
| 120 |
+
hovermode='x unified',
|
| 121 |
+
plot_bgcolor='#F5F9F8',
|
| 122 |
+
paper_bgcolor='#F5F9F8',
|
| 123 |
+
font=dict(family="Quicksand, sans-serif", size=12, color="#313D38")
|
| 124 |
+
)
|
| 125 |
+
|
| 126 |
+
fig.update_xaxes(
|
| 127 |
+
rangeslider_visible=True,
|
| 128 |
+
rangeselector=dict(
|
| 129 |
+
buttons=list([
|
| 130 |
+
dict(count=1, label="1m", step="month", stepmode="backward"),
|
| 131 |
+
dict(count=6, label="6m", step="month", stepmode="backward"),
|
| 132 |
+
dict(count=1, label="YTD", step="year", stepmode="todate"),
|
| 133 |
+
dict(count=1, label="1y", step="year", stepmode="backward"),
|
| 134 |
+
dict(step="all")
|
| 135 |
+
])
|
| 136 |
)
|
| 137 |
+
)
|
| 138 |
+
|
| 139 |
+
current_price = data['Close'].iloc[-1]
|
| 140 |
+
log_price = log_trend[-len(data):]
|
| 141 |
+
percent_diff = ((current_price - log_price.iloc[-1]) / log_price.iloc[-1]) * 100
|
| 142 |
+
|
| 143 |
+
return fig, current_price, log_price.iloc[-1], percent_diff
|
| 144 |
+
|
| 145 |
+
def plot_candlestick_chart(data, ticker):
|
| 146 |
+
fig = go.Figure(data=[go.Candlestick(x=data.index,
|
| 147 |
+
open=data['Open'],
|
| 148 |
+
high=data['High'],
|
| 149 |
+
low=data['Low'],
|
| 150 |
+
close=data['Close'])])
|
| 151 |
+
|
| 152 |
+
fig.update_layout(
|
| 153 |
+
title={
|
| 154 |
+
'text': f'Stock Candlestick Chart: {ticker}',
|
| 155 |
+
'y': 0.95,
|
| 156 |
+
'x': 0.5,
|
| 157 |
+
'xanchor': 'center',
|
| 158 |
+
'yanchor': 'top'
|
| 159 |
+
},
|
| 160 |
+
xaxis_title='Date',
|
| 161 |
+
yaxis_title='Price',
|
| 162 |
+
height=800,
|
| 163 |
+
legend=dict(x=0.01, y=0.99, bgcolor='rgba(255, 255, 255, 0.8)'),
|
| 164 |
+
hovermode='x unified',
|
| 165 |
+
plot_bgcolor='#F5F9F8',
|
| 166 |
+
paper_bgcolor='#F5F9F8',
|
| 167 |
+
font=dict(family="Quicksand, sans-serif", size=12, color="#313D38")
|
| 168 |
+
)
|
| 169 |
|
| 170 |
+
fig.update_xaxes(
|
| 171 |
+
rangeslider_visible=True,
|
| 172 |
+
rangeselector=dict(
|
| 173 |
+
buttons=list([
|
| 174 |
+
dict(count=1, label="1m", step="month", stepmode="backward"),
|
| 175 |
+
dict(count=6, label="6m", step="month", stepmode="backward"),
|
| 176 |
+
dict(count=1, label="YTD", step="year", stepmode="todate"),
|
| 177 |
+
dict(count=1, label="1y", step="year", stepmode="backward"),
|
| 178 |
+
dict(step="all")
|
| 179 |
+
])
|
|
|
|
| 180 |
)
|
| 181 |
+
)
|
| 182 |
|
| 183 |
+
current_price = data['Close'].iloc[-1]
|
| 184 |
+
return fig, current_price, None, None
|
| 185 |
+
|
| 186 |
+
def format_price_info(current_price, log_price, percent_diff):
|
| 187 |
+
if log_price is None or percent_diff is None:
|
| 188 |
+
return f"Current Price: ${current_price:.2f}"
|
| 189 |
+
|
| 190 |
+
color = "green" if percent_diff > 0 else "red"
|
| 191 |
+
intensity = min(abs(percent_diff) / 100, 1) # Normalize to 0-1
|
| 192 |
+
bg_color = f"rgba({255 if color == 'red' else 0}, {255 if color == 'green' else 0}, 0, {intensity})"
|
| 193 |
+
|
| 194 |
+
return f"""
|
| 195 |
+
<div style="display: flex; justify-content: space-between; padding: 10px; background-color: {bg_color}; border-radius: 10px;">
|
| 196 |
+
<div>
|
| 197 |
+
<p>Current Price: ${current_price:.2f}</p>
|
| 198 |
+
<p>Log Price: ${log_price:.2f}</p>
|
| 199 |
+
</div>
|
| 200 |
+
<div>
|
| 201 |
+
<p style="font-size: 1.2em; font-weight: bold; color: {color};">
|
| 202 |
+
{percent_diff:.2f}% {'above' if percent_diff > 0 else 'below'} log price
|
| 203 |
+
</p>
|
| 204 |
+
</div>
|
| 205 |
+
</div>
|
| 206 |
+
"""
|
| 207 |
|
| 208 |
# Get the current date
|
| 209 |
current_date = datetime.now().strftime("%Y-%m-%d")
|
|
|
|
| 220 |
"""
|
| 221 |
|
| 222 |
# Create Gradio interface with custom Seafoam theme
|
| 223 |
+
with gr.Blocks(theme=seafoam, title="Stock Charts", css=custom_css) as iface:
|
| 224 |
+
gr.Markdown("# Stock Charts")
|
| 225 |
+
gr.Markdown("Enter a stock ticker and date range to generate a chart.")
|
| 226 |
|
| 227 |
with gr.Row():
|
| 228 |
ticker = gr.Textbox(label="Stock Ticker", value="MSFT", elem_id="ticker-input")
|
| 229 |
start_date = gr.Textbox(label="Start Date", value="2015-01-01", elem_id="start-date-input")
|
| 230 |
end_date = gr.Textbox(label="End Date", value=current_date, elem_id="end-date-input")
|
| 231 |
|
| 232 |
+
with gr.Accordion("Chart Options", open=False):
|
| 233 |
+
chart_type = gr.Radio(["Log", "Candlestick"], label="Chart Type", value="Log")
|
| 234 |
+
|
| 235 |
submit_button = gr.Button("Generate Chart", elem_id="generate-button")
|
| 236 |
|
| 237 |
with gr.Row():
|
| 238 |
+
chart = gr.Plot(label="Stock Chart")
|
| 239 |
|
| 240 |
+
price_info = gr.HTML(label="Price Information")
|
| 241 |
+
|
| 242 |
submit_button.click(
|
| 243 |
+
plot_chart,
|
| 244 |
+
inputs=[ticker, start_date, end_date, chart_type],
|
| 245 |
+
outputs=[chart, price_info]
|
| 246 |
+
).then(
|
| 247 |
+
lambda current_price, log_price, percent_diff: format_price_info(current_price, log_price, percent_diff),
|
| 248 |
+
inputs=[gr.State(None), gr.State(None), gr.State(None)],
|
| 249 |
+
outputs=[price_info]
|
| 250 |
)
|
| 251 |
|
| 252 |
# Launch the app
|