Chào các bạn, hôm nay mình sẽ viết bài đầu tiên trong series Tự học và phát triển ứng dụng thực tế AI, ML, DL, DS. Ứng dụng Dự đoán giá cổ phiếu bằng Machine Learning.
Trong bài viết này, chúng ta sẽ lần lượt phát triển hai phần:
- Đầu tiên, chúng ta sẽ học cách dự đoán giá cổ phiếu bằng mạng nơ-ron LSTM.
- Sau đó, chúng ta sẽ xây dựng một bảng điều khiển bằng cách sử dụng Plotly dash để phân tích chứng khoán.
Lưu ý: Mình không khuyến khích áp dụng 100% vào thực tế, các bạn cân nhắc kỹ khi sử dụng 🙂
Dự đoán giá cổ phiếu sử dụng LSTM
Long Short-Term Memory (LSTM) là phiên bản mở rộng của mạng nơ ron hồi quy (Recurrent Neural Network – RNN) được thiết kế để giải quyết các bài toán về phụ thuộc xa (long-term dependencies) trong mạng RNN do bị ảnh hưởng bởi vấn đề gradient biến mất. Có thể hiểu một cách đơn giản là mạng RNN cơ bản trong thực tế không có khả năng ghi nhớ thông tin từ các bước có khoảng cách xa và do đó những phần tử đầu tiên trong chuỗi đầu vào không có nhiều ảnh hưởng đến các kết quả tính toán dự đoán phần tử cho chuỗi đầu ra trong các bước sau.
Trong phạm vi bài viết này mình không giải thích chi tiết về LSTM, các bạn có thể tìm hiểu ở các nguồn khác nhé. Bắt tay vào thực hiện ngay thôi.
Dataset
Ở đây mình có 2 bộ dataset:
- Để xây dựng mô hình dự đoán giá cổ phiếu, chúng ta sẽ sử dụng tập dữ liệu NSE TATA GLOBAL. Đây là tập dữ liệu về Đồ uống Tata từ Tata Global Beverage Limited, Sở giao dịch chứng khoán quốc gia Ấn Độ: NSE-TATA dataset
- Để phát triển bảng điều khiển cho phân tích chứng khoán, chúng ta sẽ sử dụng một tập dữ liệu cổ phiếu khác như Apple, Microsoft, Facebook: Stocks Dataset
Python code
Import thư viện Pandas, Numpy, Matplotlib, Sklearn, Keras
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import pandas as pd import numpy as np import matplotlib.pyplot as plt %matplotlib inline from matplotlib.pylab import rcParams rcParams['figure.figsize']=20,10 from sklearn.preprocessing import MinMaxScaler scaler=MinMaxScaler(feature_range=(0,1)) from keras.models import Sequential from keras.layers import LSTM,Dropout,Dense |
Đọc dữ liệu và phân tích giá cổ phiếu từ dataset
1 2 3 4 5 6 7 8 |
df=pd.read_csv("NSE-TATA.csv") df.head() df["Date"]=pd.to_datetime(df.Date,format="%Y-%m-%d") df.index=df['Date'] plt.figure(figsize=(16,8)) plt.plot(df["Close"],label='Close Price history') |
Sắp xếp và chuẩn hóa dữ liệu train
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
data=df.sort_index(ascending=True,axis=0) new_dataset=pd.DataFrame(index=range(0,len(df)),columns=['Date','Close']) for i in range(0,len(data)): new_dataset["Date"][i]=data['Date'][i] new_dataset["Close"][i]=data["Close"][i] new_dataset.index=new_dataset.Date new_dataset.drop("Date",axis=1,inplace=True) final_dataset=new_dataset.values train_data=final_dataset[0:987,:] valid_data=final_dataset[987:,:] scaler=MinMaxScaler(feature_range=(0,1)) scaled_data=scaler.fit_transform(final_dataset) x_train_data,y_train_data=[],[] for i in range(60,len(train_data)): x_train_data.append(scaled_data[i-60:i,0]) y_train_data.append(scaled_data[i,0]) x_train_data,y_train_data=np.array(x_train_data),np.array(y_train_data) x_train_data=np.reshape(x_train_data,(x_train_data.shape[0],x_train_data.shape[1],1)) |
Xây dựng và huấn luyện mô hình LSTM
1 2 3 4 5 6 7 |
lstm_model=Sequential() lstm_model.add(LSTM(units=50,return_sequences=True,input_shape=(x_train_data.shape[1],1))) lstm_model.add(LSTM(units=50)) lstm_model.add(Dense(1)) lstm_model.compile(loss='mean_squared_error',optimizer='adam') lstm_model.fit(x_train_data,y_train_data,epochs=1,batch_size=1,verbose=2) |
Lấy mẫu test để dự đoán mô hình vừa tạo ở bước trên
1 2 3 4 5 6 7 8 9 10 11 12 13 |
inputs_data=new_dataset[len(new_dataset)-len(valid_data)-60:].values inputs_data=inputs_data.reshape(-1,1) inputs_data=scaler.transform(inputs_data) X_test=[] for i in range(60,inputs_data.shape[0]): X_test.append(inputs_data[i-60:i,0]) X_test=np.array(X_test) X_test=np.reshape(X_test,(X_test.shape[0],X_test.shape[1],1)) closing_price=lstm_model.predict(X_test) closing_price=scaler.inverse_transform(closing_price) |
Lưu model lại
1 |
lstm_model.save("saved_model.h5") |
Vẽ biểu đồ trực quan kết quả dự đoán với thực tế
1 2 3 4 5 |
train_data=new_dataset[:987] valid_data=new_dataset[987:] valid_data['Predictions']=closing_price plt.plot(train_data["Close"]) plt.plot(valid_data[['Close',"Predictions"]]) |
Kết quả cũng không tệ lắm nhỉ 😀
Xây dựng Dashboard sử dụng Plotly dash
Trong phần này, chúng ta sẽ xây dựng một bảng điều khiển để phân tích cổ phiếu. Dash là một Python framework cung cấp mô hình trừu tượng hóa trên Flask và ReactJs để xây dựng các ứng dụng web phân tích.
Trước tiên, các bạn cần phải cài đặt thư viện:
1 2 3 |
pip3 install dash pip3 install dash-html-components pip3 install dash-core-components |
Tiến hành code thôi nào
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
import dash import dash_core_components as dcc import dash_html_components as html import pandas as pd import plotly.graph_objs as go from dash.dependencies import Input, Output from keras.models import load_model from sklearn.preprocessing import MinMaxScaler import numpy as np app = dash.Dash() server = app.server scaler=MinMaxScaler(feature_range=(0,1)) df_nse = pd.read_csv("./NSE-TATA.csv") df_nse["Date"]=pd.to_datetime(df_nse.Date,format="%Y-%m-%d") df_nse.index=df_nse['Date'] data=df_nse.sort_index(ascending=True,axis=0) new_data=pd.DataFrame(index=range(0,len(df_nse)),columns=['Date','Close']) for i in range(0,len(data)): new_data["Date"][i]=data['Date'][i] new_data["Close"][i]=data["Close"][i] new_data.index=new_data.Date new_data.drop("Date",axis=1,inplace=True) dataset=new_data.values train=dataset[0:987,:] valid=dataset[987:,:] scaler=MinMaxScaler(feature_range=(0,1)) scaled_data=scaler.fit_transform(dataset) x_train,y_train=[],[] for i in range(60,len(train)): x_train.append(scaled_data[i-60:i,0]) y_train.append(scaled_data[i,0]) x_train,y_train=np.array(x_train),np.array(y_train) x_train=np.reshape(x_train,(x_train.shape[0],x_train.shape[1],1)) model=load_model("saved_model.h5") inputs=new_data[len(new_data)-len(valid)-60:].values inputs=inputs.reshape(-1,1) inputs=scaler.transform(inputs) X_test=[] for i in range(60,inputs.shape[0]): X_test.append(inputs[i-60:i,0]) X_test=np.array(X_test) X_test=np.reshape(X_test,(X_test.shape[0],X_test.shape[1],1)) closing_price=model.predict(X_test) closing_price=scaler.inverse_transform(closing_price) train=new_data[:987] valid=new_data[987:] valid['Predictions']=closing_price df= pd.read_csv("./stock_data.csv") app.layout = html.Div([ html.H1("Stock Price Analysis Dashboard", style={"textAlign": "center"}), dcc.Tabs(id="tabs", children=[ dcc.Tab(label='NSE-TATAGLOBAL Stock Data',children=[ html.Div([ html.H2("Actual closing price",style={"textAlign": "center"}), dcc.Graph( id="Actual Data", figure={ "data":[ go.Scatter( x=train.index, y=valid["Close"], mode='markers' ) ], "layout":go.Layout( title='scatter plot', xaxis={'title':'Date'}, yaxis={'title':'Closing Rate'} ) } ), html.H2("LSTM Predicted closing price",style={"textAlign": "center"}), dcc.Graph( id="Predicted Data", figure={ "data":[ go.Scatter( x=valid.index, y=valid["Predictions"], mode='markers' ) ], "layout":go.Layout( title='scatter plot', xaxis={'title':'Date'}, yaxis={'title':'Closing Rate'} ) } ) ]) ]), dcc.Tab(label='Facebook Stock Data', children=[ html.Div([ html.H1("Stocks High vs Lows", style={'textAlign': 'center'}), dcc.Dropdown(id='my-dropdown', options=[{'label': 'Tesla', 'value': 'TSLA'}, {'label': 'Apple','value': 'AAPL'}, {'label': 'Facebook', 'value': 'FB'}, {'label': 'Microsoft','value': 'MSFT'}], multi=True,value=['FB'], style={"display": "block", "margin-left": "auto", "margin-right": "auto", "width": "60%"}), dcc.Graph(id='highlow'), html.H1("Stocks Market Volume", style={'textAlign': 'center'}), dcc.Dropdown(id='my-dropdown2', options=[{'label': 'Tesla', 'value': 'TSLA'}, {'label': 'Apple','value': 'AAPL'}, {'label': 'Facebook', 'value': 'FB'}, {'label': 'Microsoft','value': 'MSFT'}], multi=True,value=['FB'], style={"display": "block", "margin-left": "auto", "margin-right": "auto", "width": "60%"}), dcc.Graph(id='volume') ], className="container"), ]) ]) ]) @app.callback(Output('highlow', 'figure'), [Input('my-dropdown', 'value')]) def update_graph(selected_dropdown): dropdown = {"TSLA": "Tesla","AAPL": "Apple","FB": "Facebook","MSFT": "Microsoft",} trace1 = [] trace2 = [] for stock in selected_dropdown: trace1.append( go.Scatter(x=df[df["Stock"] == stock]["Date"], y=df[df["Stock"] == stock]["High"], mode='lines', opacity=0.7, name=f'High {dropdown[stock]}',textposition='bottom center')) trace2.append( go.Scatter(x=df[df["Stock"] == stock]["Date"], y=df[df["Stock"] == stock]["Low"], mode='lines', opacity=0.6, name=f'Low {dropdown[stock]}',textposition='bottom center')) traces = [trace1, trace2] data = [val for sublist in traces for val in sublist] figure = {'data': data, 'layout': go.Layout(colorway=["#5E0DAC", '#FF4F00', '#375CB1', '#FF7400', '#FFF400', '#FF0056'], height=600, title=f"High and Low Prices for {', '.join(str(dropdown[i]) for i in selected_dropdown)} Over Time", xaxis={"title":"Date", 'rangeselector': {'buttons': list([{'count': 1, 'label': '1M', 'step': 'month', 'stepmode': 'backward'}, {'count': 6, 'label': '6M', 'step': 'month', 'stepmode': 'backward'}, {'step': 'all'}])}, 'rangeslider': {'visible': True}, 'type': 'date'}, yaxis={"title":"Price (USD)"})} return figure @app.callback(Output('volume', 'figure'), [Input('my-dropdown2', 'value')]) def update_graph(selected_dropdown_value): dropdown = {"TSLA": "Tesla","AAPL": "Apple","FB": "Facebook","MSFT": "Microsoft",} trace1 = [] for stock in selected_dropdown_value: trace1.append( go.Scatter(x=df[df["Stock"] == stock]["Date"], y=df[df["Stock"] == stock]["Volume"], mode='lines', opacity=0.7, name=f'Volume {dropdown[stock]}', textposition='bottom center')) traces = [trace1] data = [val for sublist in traces for val in sublist] figure = {'data': data, 'layout': go.Layout(colorway=["#5E0DAC", '#FF4F00', '#375CB1', '#FF7400', '#FFF400', '#FF0056'], height=600, title=f"Market Volume for {', '.join(str(dropdown[i]) for i in selected_dropdown_value)} Over Time", xaxis={"title":"Date", 'rangeselector': {'buttons': list([{'count': 1, 'label': '1M', 'step': 'month', 'stepmode': 'backward'}, {'count': 6, 'label': '6M', 'step': 'month', 'stepmode': 'backward'}, {'step': 'all'}])}, 'rangeslider': {'visible': True}, 'type': 'date'}, yaxis={"title":"Transactions Volume"})} return figure if __name__=='__main__': app.run_server(debug=True) |
Chạy thử xem sao
1 |
python3 stock_app.py |
Các bạn mở trình duyệt để xem kết quả nhé: http://127.0.0.1:8050/
Vậy là xong, chúc các bạn thành công!
cho em xin full project dc ko ạ