| import gradio as gr |
| from gradio.themes import Base |
| from gradio.themes.utils import colors, sizes, fonts |
| from typing import Iterable |
| import yfinance as yf |
| import numpy as np |
| import pandas as pd |
| import plotly.graph_objects as go |
| from datetime import datetime |
|
|
| |
| class Seafoam(Base): |
| def __init__( |
| self, |
| *, |
| primary_hue: colors.Color | str = colors.emerald, |
| secondary_hue: colors.Color | str = colors.blue, |
| neutral_hue: colors.Color | str = colors.blue, |
| spacing_size: sizes.Size | str = sizes.spacing_md, |
| radius_size: sizes.Size | str = sizes.radius_md, |
| text_size: sizes.Size | str = sizes.text_lg, |
| font: fonts.Font | str | Iterable[fonts.Font | str] = ( |
| fonts.GoogleFont("Quicksand"), |
| "ui-sans-serif", |
| "sans-serif", |
| ), |
| font_mono: fonts.Font | str | Iterable[fonts.Font | str] = ( |
| fonts.GoogleFont("IBM Plex Mono"), |
| "ui-monospace", |
| "monospace", |
| ), |
| ): |
| super().__init__( |
| primary_hue=primary_hue, |
| secondary_hue=secondary_hue, |
| neutral_hue=neutral_hue, |
| spacing_size=spacing_size, |
| radius_size=radius_size, |
| text_size=text_size, |
| font=font, |
| font_mono=font_mono, |
| ) |
| super().set( |
| body_background_fill="linear-gradient(to bottom right, *primary_50, *primary_100, *primary_200)", |
| body_background_fill_dark="linear-gradient(to bottom right, *primary_900, *primary_800, *primary_700)", |
| button_primary_background_fill="linear-gradient(90deg, *primary_300, *secondary_400)", |
| button_primary_background_fill_hover="linear-gradient(90deg, *primary_200, *secondary_300)", |
| button_primary_text_color="white", |
| button_primary_background_fill_dark="linear-gradient(90deg, *primary_600, *secondary_800)", |
| slider_color="*secondary_300", |
| slider_color_dark="*secondary_600", |
| block_title_text_weight="600", |
| block_border_width="3px", |
| block_shadow="*shadow_drop_lg", |
| button_shadow="*shadow_drop_lg", |
| button_large_padding="32px", |
| ) |
|
|
| seafoam = Seafoam() |
|
|
| def download_stock_data(ticker, start_date, end_date): |
| stock = yf.Ticker(ticker) |
| df = stock.history(start=start_date, end=end_date) |
| return df |
|
|
| def plot_interactive_stock_chart(ticker, start_date, end_date, chart_type): |
| try: |
| stock = yf.Ticker(ticker) |
| data = stock.history(start=start_date, end=end_date) |
|
|
| if data.empty: |
| return "No data available for the specified date range." |
|
|
| if chart_type == "Log": |
| return plot_logarithmic_chart(data, ticker) |
| else: |
| return plot_candlestick_chart(data, ticker) |
|
|
| except Exception as e: |
| return f"An error occurred: {str(e)}" |
|
|
| def plot_logarithmic_chart(data, ticker): |
| x = (data.index - data.index[0]).days |
| y = np.log(data['Close']) |
| slope, intercept = np.polyfit(x, y, 1) |
|
|
| future_days = 365 * 10 |
| all_days = np.arange(len(x) + future_days) |
| log_trend = np.exp(intercept + slope * all_days) |
|
|
| inner_upper_band = log_trend * 2 |
| inner_lower_band = log_trend / 2 |
| outer_upper_band = log_trend * 4 |
| outer_lower_band = log_trend / 4 |
|
|
| extended_dates = pd.date_range(start=data.index[0], periods=len(all_days), freq='D') |
|
|
| fig = go.Figure() |
|
|
| fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price', line=dict(color='blue'))) |
| fig.add_trace(go.Scatter(x=extended_dates, y=log_trend, mode='lines', name='Log Trend', line=dict(color='red'))) |
| fig.add_trace(go.Scatter(x=extended_dates, y=inner_upper_band, mode='lines', name='Inner Upper Band', line=dict(color='#6FB1A7'))) |
| fig.add_trace(go.Scatter(x=extended_dates, y=inner_lower_band, mode='lines', name='Inner Lower Band', line=dict(color='#6FB1A7'))) |
| fig.add_trace(go.Scatter(x=extended_dates, y=outer_upper_band, mode='lines', name='Outer Upper Band', line=dict(color='#FFC2A5'))) |
| fig.add_trace(go.Scatter(x=extended_dates, y=outer_lower_band, mode='lines', name='Outer Lower Band', line=dict(color='#FFC2A5'))) |
|
|
| fig.update_layout( |
| title={ |
| 'text': f'Stock Log Chart: {ticker}', |
| 'y': 0.95, |
| 'x': 0.5, |
| 'xanchor': 'center', |
| 'yanchor': 'top' |
| }, |
| xaxis_title='Date', |
| yaxis_title='Price (Log Scale)', |
| yaxis_type="log", |
| height=800, |
| legend=dict(x=0.01, y=0.99, bgcolor='rgba(255, 255, 255, 0.8)'), |
| hovermode='x unified', |
| plot_bgcolor='#F5F9F8', |
| paper_bgcolor='#F5F9F8', |
| font=dict(family="Quicksand, sans-serif", size=12, color="#313D38") |
| ) |
|
|
| fig.update_xaxes( |
| rangeslider_visible=True, |
| rangeselector=dict( |
| buttons=list([ |
| dict(count=1, label="1m", step="month", stepmode="backward"), |
| dict(count=6, label="6m", step="month", stepmode="backward"), |
| dict(count=1, label="YTD", step="year", stepmode="todate"), |
| dict(count=1, label="1y", step="year", stepmode="backward"), |
| dict(step="all") |
| ]) |
| ) |
| ) |
|
|
| return fig |
|
|
| def plot_candlestick_chart(data, ticker): |
| fig = go.Figure(data=[go.Candlestick(x=data.index, |
| open=data['Open'], |
| high=data['High'], |
| low=data['Low'], |
| close=data['Close'])]) |
|
|
| fig.update_layout( |
| title={ |
| 'text': f'Stock Candlestick Chart: {ticker}', |
| 'y': 0.95, |
| 'x': 0.5, |
| 'xanchor': 'center', |
| 'yanchor': 'top' |
| }, |
| xaxis_title='Date', |
| yaxis_title='Price', |
| height=800, |
| legend=dict(x=0.01, y=0.99, bgcolor='rgba(255, 255, 255, 0.8)'), |
| hovermode='x unified', |
| plot_bgcolor='#F5F9F8', |
| paper_bgcolor='#F5F9F8', |
| font=dict(family="Quicksand, sans-serif", size=12, color="#313D38") |
| ) |
|
|
| fig.update_xaxes( |
| rangeslider_visible=True, |
| rangeselector=dict( |
| buttons=list([ |
| dict(count=1, label="1m", step="month", stepmode="backward"), |
| dict(count=6, label="6m", step="month", stepmode="backward"), |
| dict(count=1, label="YTD", step="year", stepmode="todate"), |
| dict(count=1, label="1y", step="year", stepmode="backward"), |
| dict(step="all") |
| ]) |
| ) |
| ) |
|
|
| return fig |
|
|
| |
| current_date = datetime.now().strftime("%Y-%m-%d") |
|
|
| |
| custom_css = """ |
| .center-text { |
| text-align: center; |
| } |
| |
| #generate-button:hover, #ticker-input input:hover, #start-date-input input:hover, #end-date-input input:hover { |
| background-color: #FFB3BA !important; /* Pastel red */ |
| } |
| |
| #header-image { |
| display: block; |
| margin: 0 auto; |
| max-width: 100%; |
| height: auto; |
| } |
| """ |
|
|
| |
| with gr.Blocks(theme=seafoam, title="Log Stock Charts", css=custom_css) as iface: |
| |
| gr.Image("header.png", elem_id="header-image", show_label=False) |
| |
| gr.Markdown("Enter a stock ticker and date range to generate a chart.", elem_classes=["center-text"]) |
| |
| with gr.Row(): |
| ticker = gr.Textbox(label="Stock Ticker", value="MSFT", elem_id="ticker-input") |
| start_date = gr.Textbox(label="Start Date", value="2015-01-01", elem_id="start-date-input") |
| end_date = gr.Textbox(label="End Date", value=current_date, elem_id="end-date-input") |
| |
| with gr.Accordion("Chart Options", open=False): |
| chart_type = gr.Radio(["Log", "Candlestick"], label="Chart Type", value="Log") |
| |
| submit_button = gr.Button("Generate Chart", elem_id="generate-button") |
| |
| with gr.Row(): |
| stock_chart = gr.Plot(label="Stock Chart") |
| |
| submit_button.click( |
| plot_interactive_stock_chart, |
| inputs=[ticker, start_date, end_date, chart_type], |
| outputs=[stock_chart] |
| ) |
|
|
| |
| iface.launch(show_api=False, show_error=False) |