Toilanhat / app.py
nick5363's picture
Update app.py
78eb1cc verified
import streamlit as st
from streamlit_autorefresh import st_autorefresh
import pandas as pd
import requests
import yfinance as yf
from datetime import datetime, timedelta
# Hàm lấy danh sách cổ phiếu có Volume > Avg Vol (3M) từ Yahoo Finance
def get_active_stocks():
url = "https://finance.yahoo.com/markets/stocks/most-active/?start=0&count=100"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
"Accept-Language": "en-US,en;q=0.9"
}
response = requests.get(url, headers=headers, timeout=10)
tables = pd.read_html(response.text)
stocks_df = tables[0]
stocks_df['Volume'] = stocks_df['Volume'].replace({'M': '*1e6', 'k': '*1e3'}, regex=True).map(pd.eval).astype(int)
stocks_df['Avg Vol (3M)'] = stocks_df['Avg Vol (3M)'].replace({'M': '*1e6', 'k': '*1e3'}, regex=True).map(pd.eval).astype(int)
result = stocks_df[stocks_df['Volume'] > stocks_df['Avg Vol (3M)']]
result_df = result[['Symbol', 'Price', 'Change', 'Change %', 'Volume', 'Avg Vol (3M)']]
result_df.columns = ['Symbol', 'Price', 'Change', 'Change %', 'Volume', 'Avg Vol (3M)']
# Chuẩn hóa dữ liệu
result_df['Price'] = result_df['Price'].str.split(' ').str[0]
result_df['Volume'] = result_df['Volume'].apply(lambda x: f"{x:,}")
result_df['Avg Vol (3M)'] = result_df['Avg Vol (3M)'].apply(lambda x: f"{x:,}")
result_df['Price'] = result_df['Price'].astype(float).apply(lambda x: f"${x:.2f}")
result_df['Change'] = result_df['Change'].astype(float).apply(lambda x: f"+{x:.2f}" if x > 0 else f"{x:.2f}")
return result_df
# Hàm lấy dữ liệu Open, High, Close từ yfinance
def get_stock_data(symbols):
stock_data = []
for symbol in symbols:
try:
stock = yf.Ticker(symbol)
hist = stock.history(period="1d") # Lấy dữ liệu trong 1 ngày gần nhất
live_price = stock.info.get("regularMarketPrice", None)
if not hist.empty:
open_price = hist['Open'].iloc[-1]
high_price = hist['High'].iloc[-1]
close_price = hist['Close'].iloc[-1]
low_price = hist['Low'].iloc[-1]
stock_data.append({
"Symbol": symbol,
"Open": round(open_price, 2),
"High": round(high_price, 2),
"Close": round(close_price, 2),
"Low": round(low_price, 2),
"Live Price": round(live_price, 2) if live_price else "N/A"
})
except Exception as e:
print(f"Không lấy được dữ liệu của {symbol}: {e}")
return pd.DataFrame(stock_data)
# Hàm tính ATR
def compute_atr(ticker):
end_date = datetime.today()
start_date = end_date - timedelta(days=30)
df = yf.download(ticker, start=start_date, end=end_date, progress=False)
if df.empty or len(df) < 15:
return None
df['H-L'] = df['High'] - df['Low']
df['H-PC'] = abs(df['High'] - df['Close'].shift(1))
df['L-PC'] = abs(df['Low'] - df['Close'].shift(1))
df['TR'] = df[['H-L', 'H-PC', 'L-PC']].max(axis=1)
df['ATR'] = df['TR'].rolling(window=14).mean()
return round(df['ATR'].iloc[-1], 2)
# Main logic
with st.spinner("Đang tải dữ liệu..."):
df = get_active_stocks()
df['ATR (14)'] = df['Symbol'].apply(compute_atr)
st.dataframe(df.dropna(subset=["ATR (14)"]).reset_index(drop=True))
# Ứng dụng Streamlit
st.title("Stocks with Volume > Avg Vol (3M) and Price Data")
# Cập nhật tự động mỗi 60 giây
st_autorefresh(interval=60000, key="price_refresh")
# Hiển thị thời gian cập nhật mới nhất
st.write("🔄 **Lần cập nhật gần nhất:**", pd.Timestamp.now())
if st.button("Get Stocks Data"):
with st.spinner('Fetching data...'):
df = get_active_stocks() # Lấy danh sách cổ phiếu có volume cao
symbols = df["Symbol"].tolist() # Lấy danh sách mã cổ phiếu
stock_prices = get_stock_data(symbols) # Lấy giá Open, High, Close, Low, Live Price từ yfinance
# Kết hợp hai bảng dữ liệu
merged_df = pd.merge(df, stock_prices, on="Symbol", how="left")
st.dataframe(merged_df) # Hiển thị dữ liệu trên Streamlit