from flask import Blueprint, render_template, request import os import pandas as pd from datetime import datetime from modules.utils import plot_candlestick_with_fibo_patterns, detect_candlestick_patterns, calculate_fibonacci_levels, calculate_money_flow, find_double_top_bottom, detect_w_double_bottom, detect_m_double_top, detect_cup_and_handle, get_financial_valuation, DATA_DIR from vnstock import Vnstock def load_financial_table(csv_path, symbol, period=None): header_row = 1 if 'ratio' in csv_path.lower() else 0 if not os.path.exists(csv_path): return None try: df = pd.read_csv(csv_path, header=header_row) df.columns = [str(col).strip().lower().replace(' ', '').replace('_', '') for col in df.columns] symbol_col = None for col in ['ticker', 'cp', 'mã', 'stock']: if col in df.columns: symbol_col = col break year_col = None for col in ['yearreport', 'năm', 'year', 'nam']: if col in df.columns: year_col = col break if symbol_col is None or year_col is None: return None df[symbol_col] = df[symbol_col].astype(str).str.upper().str.strip() df = df[df[symbol_col] == symbol.upper()] if df.empty: return None return df except Exception: return None def df_to_html(df, max_cols=12): if df is None or (hasattr(df, 'empty') and df.empty): return 'Chưa có dữ liệu tài chính. Hãy bấm Tải dữ liệu mới để lấy dữ liệu!' if len(df) == 1 and df.isnull().all(axis=None): return 'Chưa có dữ liệu tài chính. Hãy bấm Tải dữ liệu mới để lấy dữ liệu!' if len(df.columns) > max_cols: df = df.iloc[:, :max_cols] return df.to_html(classes='table table-sm table-bordered', index=False, border=0, justify='center') vsa_bp = Blueprint('vsa', __name__) @vsa_bp.route('/vsa', methods=['GET']) def vsa_index(): symbol = request.args.get('symbol', 'VNINDEX').strip().upper() start = request.args.get('start', '2024-01-01') end = request.args.get('end', datetime.now().strftime('%Y-%m-%d')) try: stock = Vnstock().stock(symbol=symbol) df = stock.quote.history(start=start, end=end, interval='1D') if df is None or df.empty: return render_template('vsa.html', symbol=symbol, error="Không có dữ liệu cho mã cổ phiếu hoặc khoảng thời gian đã chọn.", chart_path_vsa=None, tables={ 'bs_year': '', 'bs_quarter': '', 'is_year': '', 'is_quarter': '', 'cf_year': '', 'ratio_year': '', 'ratio_quarter': '' }) except Exception as e: return render_template('vsa.html', symbol=symbol, error=f"Lỗi khi lấy dữ liệu: {e}", chart_path_vsa=None, tables={ 'bs_year': '', 'bs_quarter': '', 'is_year': '', 'is_quarter': '', 'cf_year': '', 'ratio_year': '', 'ratio_quarter': '' }) # Data cleaning for col in ['open', 'high', 'low', 'close', 'volume']: df[col] = pd.to_numeric(df[col], errors='coerce') df.dropna(subset=['open', 'high', 'low', 'close', 'volume'], inplace=True) candlestick_patterns = detect_candlestick_patterns(df) fibonacci_levels = calculate_fibonacci_levels(df) df = calculate_money_flow(df) double_tops, double_bottoms = find_double_top_bottom(df) w_double_bottoms = detect_w_double_bottom(df) m_double_tops = detect_m_double_top(df) CHART_PATH_VSA = "static/images/vnindex_vsa.png" os.makedirs(os.path.dirname(CHART_PATH_VSA), exist_ok=True) plot_candlestick_with_fibo_patterns( df, fibonacci_levels, candlestick_patterns, symbol, chart_path=CHART_PATH_VSA, double_tops=double_tops, double_bottoms=double_bottoms, cup_handle_patterns=None, w_double_bottoms=w_double_bottoms, m_double_tops=m_double_tops ) # Bổ sung bảng tài chính bs_year = load_financial_table('DFbalance_sheet_year.csv', symbol, period='year') bs_quarter = load_financial_table('DFbalance_sheet_quarter.csv', symbol, period='quarter') is_year = load_financial_table('DFincome_statement_year.csv', symbol, period='year') is_quarter = load_financial_table('dfincome_statement_quarter.csv', symbol, period='quarter') cf_year = load_financial_table('dfcash_flow_year.csv', symbol, period='year') ratio_year = load_financial_table('dfratio_year.csv', symbol, period='year') ratio_quarter = load_financial_table('dfratio_quarter.csv', symbol, period='quarter') tables = { 'bs_year': df_to_html(bs_year), 'bs_quarter': df_to_html(bs_quarter), 'is_year': df_to_html(is_year), 'is_quarter': df_to_html(is_quarter), 'cf_year': df_to_html(cf_year), 'ratio_year': df_to_html(ratio_year), 'ratio_quarter': df_to_html(ratio_quarter), } financial_valuation = get_financial_valuation(stock) return render_template('vsa.html', symbol=symbol, chart_path_vsa=CHART_PATH_VSA, error=None, tables=tables, financial_valuation=financial_valuation)