Spaces:
Sleeping
Sleeping
| import warnings | |
| warnings.simplefilter(action='ignore', category=FutureWarning) | |
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| import plotly.graph_objs as go | |
| from vnstock import Vnstock, Listing | |
| st.set_page_config(page_title="Vietnam Stock Market Insight", layout="wide") | |
| st.title("📈 Vietnam Stock Market Insight") | |
| symbol = st.text_input("Nhập mã cổ phiếu (ví dụ: VNM, FPT, VCB):", value="GMD") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| start_date = st.date_input("Ngày bắt đầu", pd.to_datetime("2025-01-01")) | |
| with col2: | |
| end_date = st.date_input("Ngày kết thúc", pd.to_datetime("2025-12-31")) | |
| tab1, tab2, tab3 = st.tabs([ | |
| "📉 Phân tích kỹ thuật", | |
| "📊 Phân tích cơ bản", | |
| "🏢 Thông tin doanh nghiệp" | |
| ]) | |
| # TAB 1 - Phân tích kỹ thuật | |
| with tab1: | |
| if st.button("Phân tích kỹ thuật"): | |
| with st.spinner("Đang tải dữ liệu..."): | |
| try: | |
| stock = Vnstock().stock(symbol=symbol, source='VCI') | |
| df = stock.quote.history( | |
| start=start_date.strftime("%Y-%m-%d"), | |
| end=end_date.strftime("%Y-%m-%d"), | |
| interval='1D' | |
| ) | |
| df['date'] = pd.to_datetime(df['time']) | |
| df.set_index('date', inplace=True) | |
| df.sort_index(inplace=True) | |
| df['EMA12'] = df['close'].ewm(span=12, adjust=False).mean() | |
| df['EMA26'] = df['close'].ewm(span=26, adjust=False).mean() | |
| df['MACD'] = df['EMA12'] - df['EMA26'] | |
| df['MACD_Signal'] = df['MACD'].ewm(span=9, adjust=False).mean() | |
| df['BB_Middle'] = df['close'].rolling(window=20).mean() | |
| df['BB_Std'] = df['close'].rolling(window=20).std() | |
| df['BB_Upper'] = df['BB_Middle'] + (2 * df['BB_Std']) | |
| df['BB_Lower'] = df['BB_Middle'] - (2 * df['BB_Std']) | |
| delta = df['close'].diff() | |
| gain = delta.where(delta > 0, 0) | |
| loss = -delta.where(delta < 0, 0) | |
| avg_gain = gain.rolling(window=14).mean() | |
| avg_loss = loss.rolling(window=14).mean() | |
| rs = avg_gain / avg_loss | |
| df['RSI'] = 100 - (100 / (1 + rs)) | |
| st.subheader("📊 Dữ liệu giá cổ phiếu") | |
| st.dataframe(df[['open', 'high', 'low', 'close', 'volume']].dropna().tail(10)) | |
| st.subheader("📈 Bollinger Bands") | |
| fig_bb = go.Figure() | |
| fig_bb.add_trace(go.Scatter(x=df.index, y=df['close'], name='Close')) | |
| fig_bb.add_trace(go.Scatter(x=df.index, y=df['BB_Upper'], name='Upper Band')) | |
| fig_bb.add_trace(go.Scatter(x=df.index, y=df['BB_Lower'], name='Lower Band')) | |
| st.plotly_chart(fig_bb, use_container_width=True) | |
| st.subheader("📉 RSI") | |
| fig_rsi = go.Figure() | |
| fig_rsi.add_trace(go.Scatter(x=df.index, y=df['RSI'], name='RSI')) | |
| fig_rsi.update_layout(yaxis=dict(range=[0, 100])) | |
| st.plotly_chart(fig_rsi, use_container_width=True) | |
| st.subheader("📉 MACD") | |
| fig_macd = go.Figure() | |
| fig_macd.add_trace(go.Scatter(x=df.index, y=df['MACD'], name='MACD')) | |
| fig_macd.add_trace(go.Scatter(x=df.index, y=df['MACD_Signal'], name='Signal')) | |
| st.plotly_chart(fig_macd, use_container_width=True) | |
| except Exception as e: | |
| st.error(f"❌ Lỗi kỹ thuật: {e}") | |
| # TAB 2 - Phân tích cơ bản | |
| with tab2: | |
| if st.button("Phân tích cơ bản"): | |
| with st.spinner("Đang tải báo cáo tài chính..."): | |
| try: | |
| stock = Vnstock().stock(symbol=symbol, source='VCI') | |
| df_financial = stock.finance.income_statement(period='quarter', lang='vi', dropna=True) | |
| st.subheader("📊 Báo cáo tài chính quý") | |
| st.dataframe(df_financial) | |
| except Exception as e: | |
| st.error(f"❌ Lỗi dữ liệu tài chính: {e}") | |
| # TAB 3 - Thông tin doanh nghiệp đầy đủ | |
| with tab3: | |
| try: | |
| stock = Vnstock().stock(symbol=symbol, source='VCI') | |
| st.subheader(f"🏢 Tổng quan công ty: {symbol}") | |
| st.dataframe(stock.company.overview()) | |
| st.subheader("💰 Bảng cân đối kế toán") | |
| st.dataframe(stock.finance.balance_sheet()) | |
| st.subheader("💸 Báo cáo lưu chuyển tiền tệ") | |
| st.dataframe(stock.finance.cash_flow()) | |
| st.subheader("👥 Cổ đông lớn") | |
| st.dataframe(stock.company.shareholders()) | |
| st.subheader("🧑💼 Ban lãnh đạo (đang làm việc)") | |
| st.dataframe(stock.company.officers(filter_by="working")) | |
| st.subheader("📎 Tài liệu công bố") | |
| st.dataframe(stock.company.documents()) | |
| st.subheader("📋 Danh sách công ty niêm yết") | |
| listing = Listing() | |
| df_listing = listing.all_symbols() | |
| st.dataframe(df_listing) | |
| except Exception as e: | |
| st.error(f"❌ Lỗi khi lấy thông tin doanh nghiệp: {e}") | |