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)