├── Procfile ├── requirements.txt ├── assets ├── stonk-img.png └── styles.css ├── __pycache__ ├── model.cpython-38.pyc └── model.cpython-39.pyc ├── .vscode └── settings.json ├── model.py └── app.py /Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn app:server -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sg23600/stock-dash/HEAD/requirements.txt -------------------------------------------------------------------------------- /assets/stonk-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sg23600/stock-dash/HEAD/assets/stonk-img.png -------------------------------------------------------------------------------- /__pycache__/model.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sg23600/stock-dash/HEAD/__pycache__/model.cpython-38.pyc -------------------------------------------------------------------------------- /__pycache__/model.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sg23600/stock-dash/HEAD/__pycache__/model.cpython-39.pyc -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.formatting.provider": "yapf", 3 | "python.pythonPath": "/usr/bin/python3", 4 | "python.dataScience.jupyterServerURI": "local" 5 | } -------------------------------------------------------------------------------- /assets/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: 0; 5 | font-family: "Roboto", sans-serif; 6 | } 7 | 8 | body { 9 | overflow-x: hidden; 10 | } 11 | .container { 12 | display: flex; 13 | } 14 | 15 | .nav { 16 | /*position: fixed;*/ 17 | width: 25vw; 18 | /* height: 100%; */ 19 | align-items: center; 20 | display: flex; 21 | justify-content: flex-start; 22 | flex-direction: column; 23 | background-color: rgb(5, 107, 107); 24 | } 25 | 26 | .content { 27 | width: 65vw; 28 | padding: 1rem 5rem; 29 | } 30 | 31 | .start { 32 | margin-top: 2rem; 33 | margin-bottom: 5rem; 34 | text-align: center; 35 | font-size: larger; 36 | color: rgb(166, 243, 248); 37 | } 38 | 39 | .input-place p { 40 | color: antiquewhite; 41 | font-size: larger; 42 | } 43 | .form { 44 | display: flex; 45 | margin-top: 1rem; 46 | margin-bottom: 2rem; 47 | height: 1.5rem; 48 | } 49 | .form button { 50 | width: 5rem; 51 | background-color: yellow; 52 | color: black; 53 | border: none; 54 | } 55 | .buttons { 56 | margin: 2rem; 57 | width: 100%; 58 | display: flex; 59 | flex-wrap: wrap; 60 | position: relative; 61 | justify-content: space-around; 62 | } 63 | #forecast { 64 | margin-top: 2rem; 65 | height: 2.2rem; 66 | } 67 | #n_days { 68 | height: 2rem; 69 | margin-top: 2rem; 70 | } 71 | .buttons button { 72 | width: 7.5rem; 73 | height: 2.5rem; 74 | border: none; 75 | background-color: rgb(166, 255, 0); 76 | color: rgb(0, 0, 0); 77 | } 78 | 79 | .header { 80 | display: flex; 81 | justify-content: flex-start; 82 | align-items: center; 83 | margin-bottom: 2rem; 84 | } 85 | .header p { 86 | font-size: 4rem; 87 | margin-left: 3rem; 88 | line-height: 80%; 89 | } 90 | 91 | #logo { 92 | max-width: 15rem; 93 | height: auto; 94 | } 95 | -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | def prediction(stock, n_days): 2 | import dash 3 | import dash_core_components as dcc 4 | import dash_html_components as html 5 | from datetime import datetime as dt 6 | import yfinance as yf 7 | from dash.dependencies import Input, Output, State 8 | from dash.exceptions import PreventUpdate 9 | import pandas as pd 10 | import plotly.graph_objs as go 11 | import plotly.express as px 12 | # model 13 | from model import prediction 14 | from sklearn.model_selection import train_test_split 15 | from sklearn.model_selection import GridSearchCV 16 | import numpy as np 17 | from sklearn.svm import SVR 18 | from datetime import date, timedelta 19 | # load the data 20 | 21 | df = yf.download(stock, period='60d') 22 | df.reset_index(inplace=True) 23 | df['Day'] = df.index 24 | 25 | days = list() 26 | for i in range(len(df.Day)): 27 | days.append([i]) 28 | 29 | # Splitting the dataset 30 | 31 | X = days 32 | Y = df[['Close']] 33 | 34 | x_train, x_test, y_train, y_test = train_test_split(X, 35 | Y, 36 | test_size=0.1, 37 | shuffle=False) 38 | 39 | gsc = GridSearchCV( 40 | estimator=SVR(kernel='rbf'), 41 | param_grid={ 42 | 'C': [0.001, 0.01, 0.1, 1, 100, 1000], 43 | 'epsilon': [ 44 | 0.0001, 0.0005, 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10, 45 | 50, 100, 150, 1000 46 | ], 47 | 'gamma': [0.0001, 0.001, 0.005, 0.1, 1, 3, 5, 8, 40, 100, 1000] 48 | }, 49 | cv=5, 50 | scoring='neg_mean_absolute_error', 51 | verbose=0, 52 | n_jobs=-1) 53 | 54 | y_train = y_train.values.ravel() 55 | y_train 56 | grid_result = gsc.fit(x_train, y_train) 57 | best_params = grid_result.best_params_ 58 | best_svr = SVR(kernel='rbf', 59 | C=best_params["C"], 60 | epsilon=best_params["epsilon"], 61 | gamma=best_params["gamma"], 62 | max_iter=-1) 63 | 64 | # Support Vector Regression Models 65 | 66 | # RBF model 67 | #rbf_svr = SVR(kernel='rbf', C=1000.0, gamma=4.0) 68 | rbf_svr = best_svr 69 | 70 | rbf_svr.fit(x_train, y_train) 71 | 72 | output_days = list() 73 | for i in range(1, n_days): 74 | output_days.append([i + x_test[-1][0]]) 75 | 76 | dates = [] 77 | current = date.today() 78 | for i in range(n_days): 79 | current += timedelta(days=1) 80 | dates.append(current) 81 | 82 | # plot Results 83 | # fig = go.Figure() 84 | # fig.add_trace( 85 | # go.Scatter(x=np.array(x_test).flatten(), 86 | # y=y_test.values.flatten(), 87 | # mode='markers', 88 | # name='data')) 89 | # fig.add_trace( 90 | # go.Scatter(x=np.array(x_test).flatten(), 91 | # y=rbf_svr.predict(x_test), 92 | # mode='lines+markers', 93 | # name='test')) 94 | fig = go.Figure() 95 | fig.add_trace( 96 | go.Scatter( 97 | x=dates, # np.array(ten_days).flatten(), 98 | y=rbf_svr.predict(output_days), 99 | mode='lines+markers', 100 | name='data')) 101 | fig.update_layout( 102 | title="Predicted Close Price of next " + str(n_days - 1) + " days", 103 | xaxis_title="Date", 104 | yaxis_title="Closed Price", 105 | # legend_title="Legend Title", 106 | ) 107 | 108 | return fig 109 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import dash 2 | from dash import dcc 3 | from dash import html 4 | from datetime import datetime as dt 5 | import yfinance as yf 6 | from dash.dependencies import Input, Output, State 7 | from dash.exceptions import PreventUpdate 8 | import pandas as pd 9 | import plotly.graph_objs as go 10 | import plotly.express as px 11 | # model 12 | from model import prediction 13 | from sklearn.svm import SVR 14 | 15 | 16 | def get_stock_price_fig(df): 17 | 18 | fig = px.line(df, 19 | x="Date", 20 | y=["Close", "Open"], 21 | title="Closing and Openning Price vs Date") 22 | 23 | return fig 24 | 25 | 26 | def get_more(df): 27 | df['EWA_20'] = df['Close'].ewm(span=20, adjust=False).mean() 28 | fig = px.scatter(df, 29 | x="Date", 30 | y="EWA_20", 31 | title="Exponential Moving Average vs Date") 32 | fig.update_traces(mode='lines+markers') 33 | return fig 34 | 35 | 36 | app = dash.Dash( 37 | __name__, 38 | external_stylesheets=[ 39 | "https://fonts.googleapis.com/css2?family=Roboto&display=swap" 40 | ]) 41 | server = app.server 42 | # html layout of site 43 | app.layout = html.Div( 44 | [ 45 | html.Div( 46 | [ 47 | # Navigation 48 | html.P("Welcome to the Stock Dash App!", className="start"), 49 | html.Div([ 50 | html.P("Input stock code: "), 51 | html.Div([ 52 | dcc.Input(id="dropdown_tickers", type="text"), 53 | html.Button("Submit", id='submit'), 54 | ], 55 | className="form") 56 | ], 57 | className="input-place"), 58 | html.Div([ 59 | dcc.DatePickerRange(id='my-date-picker-range', 60 | min_date_allowed=dt(1995, 8, 5), 61 | max_date_allowed=dt.now(), 62 | initial_visible_month=dt.now(), 63 | end_date=dt.now().date()), 64 | ], 65 | className="date"), 66 | html.Div([ 67 | html.Button( 68 | "Stock Price", className="stock-btn", id="stock"), 69 | html.Button("Indicators", 70 | className="indicators-btn", 71 | id="indicators"), 72 | dcc.Input(id="n_days", 73 | type="text", 74 | placeholder="number of days"), 75 | html.Button( 76 | "Forecast", className="forecast-btn", id="forecast") 77 | ], 78 | className="buttons"), 79 | # here 80 | ], 81 | className="nav"), 82 | 83 | # content 84 | html.Div( 85 | [ 86 | html.Div( 87 | [ # header 88 | html.Img(id="logo"), 89 | html.P(id="ticker") 90 | ], 91 | className="header"), 92 | html.Div(id="description", className="decription_ticker"), 93 | html.Div([], id="graphs-content"), 94 | html.Div([], id="main-content"), 95 | html.Div([], id="forecast-content") 96 | ], 97 | className="content"), 98 | ], 99 | className="container") 100 | 101 | 102 | # callback for company info 103 | @app.callback([ 104 | Output("description", "children"), 105 | Output("logo", "src"), 106 | Output("ticker", "children"), 107 | Output("stock", "n_clicks"), 108 | Output("indicators", "n_clicks"), 109 | Output("forecast", "n_clicks") 110 | ], [Input("submit", "n_clicks")], [State("dropdown_tickers", "value")]) 111 | def update_data(n, val): # inpur parameter(s) 112 | if n == None: 113 | return "Hey there! Please enter a legitimate stock code to get details.", "https://melmagazine.com/wp-content/uploads/2019/07/Screen-Shot-2019-07-31-at-5.47.12-PM.png", "Stonks", None, None, None 114 | # raise PreventUpdate 115 | else: 116 | if val == None: 117 | raise PreventUpdate 118 | else: 119 | ticker = yf.Ticker(val) 120 | inf = ticker.info 121 | df = pd.DataFrame().from_dict(inf, orient="index").T 122 | df[['logo_url', 'shortName', 'longBusinessSummary']] 123 | return df['longBusinessSummary'].values[0], df['logo_url'].values[ 124 | 0], df['shortName'].values[0], None, None, None 125 | 126 | 127 | # callback for stocks graphs 128 | @app.callback([ 129 | Output("graphs-content", "children"), 130 | ], [ 131 | Input("stock", "n_clicks"), 132 | Input('my-date-picker-range', 'start_date'), 133 | Input('my-date-picker-range', 'end_date') 134 | ], [State("dropdown_tickers", "value")]) 135 | def stock_price(n, start_date, end_date, val): 136 | if n == None: 137 | return [""] 138 | #raise PreventUpdate 139 | if val == None: 140 | raise PreventUpdate 141 | else: 142 | if start_date != None: 143 | df = yf.download(val, str(start_date), str(end_date)) 144 | else: 145 | df = yf.download(val) 146 | 147 | df.reset_index(inplace=True) 148 | fig = get_stock_price_fig(df) 149 | return [dcc.Graph(figure=fig)] 150 | 151 | 152 | # callback for indicators 153 | @app.callback([Output("main-content", "children")], [ 154 | Input("indicators", "n_clicks"), 155 | Input('my-date-picker-range', 'start_date'), 156 | Input('my-date-picker-range', 'end_date') 157 | ], [State("dropdown_tickers", "value")]) 158 | def indicators(n, start_date, end_date, val): 159 | if n == None: 160 | return [""] 161 | if val == None: 162 | return [""] 163 | 164 | if start_date == None: 165 | df_more = yf.download(val) 166 | else: 167 | df_more = yf.download(val, str(start_date), str(end_date)) 168 | 169 | df_more.reset_index(inplace=True) 170 | fig = get_more(df_more) 171 | return [dcc.Graph(figure=fig)] 172 | 173 | 174 | # callback for forecast 175 | @app.callback([Output("forecast-content", "children")], 176 | [Input("forecast", "n_clicks")], 177 | [State("n_days", "value"), 178 | State("dropdown_tickers", "value")]) 179 | def forecast(n, n_days, val): 180 | if n == None: 181 | return [""] 182 | if val == None: 183 | raise PreventUpdate 184 | fig = prediction(val, int(n_days) + 1) 185 | return [dcc.Graph(figure=fig)] 186 | 187 | 188 | if __name__ == '__main__': 189 | app.run_server(debug=True) 190 | --------------------------------------------------------------------------------