Spaces:
Running
Running
| import yfinance as yf | |
| import pandas as pd | |
| import numpy as np | |
| def calculate_atr(df, period=14): | |
| """ | |
| 计算 ATR (Average True Range) 真实波幅,用来衡量波动率。 | |
| ATR 越高,说明波动越大,适合日内交易。 | |
| """ | |
| high_low = df['High'] - df['Low'] | |
| high_close = np.abs(df['High'] - df['Close'].shift()) | |
| low_close = np.abs(df['Low'] - df['Close'].shift()) | |
| ranges = pd.concat([high_low, high_close, low_close], axis=1) | |
| true_range = np.max(ranges, axis=1) | |
| atr = true_range.rolling(window=period).mean() | |
| return atr | |
| def scan_stocks(tickers): | |
| """ | |
| 模拟交易员开盘前的扫描逻辑: | |
| 1. 相对成交量 (RVol) - 今天交易量是否是过去20天平均成交量的 1.5 倍以上? | |
| 2. 波动率 (ATR % of Price) - 股票的波动性是否够大? | |
| 3. 跳空幅度 (Gap %) - 开盘价相比昨天收盘价跳空了多少? | |
| """ | |
| print("=" * 60) | |
| print(" QUANT.AI - PROFESSIONAL DAY TRADER SCANNER (盘前选股器)") | |
| print("=" * 60) | |
| print("正在从 Yahoo Finance 获取数据,请稍候...\n") | |
| watchlist = [] | |
| for ticker in tickers: | |
| try: | |
| # 获取最近 30 天的日线数据 | |
| stock = yf.Ticker(ticker) | |
| df = stock.history(period="30d") | |
| if df.empty or len(df) < 20: | |
| continue | |
| # 最新一天的行情数据 | |
| latest_day = df.iloc[-1] | |
| prev_day = df.iloc[-2] | |
| # 1. 计算相对成交量 (Relative Volume - RVol) | |
| avg_volume_20d = df['Volume'].iloc[-21:-1].mean() | |
| latest_volume = latest_day['Volume'] | |
| rvol = latest_volume / avg_volume_20d if avg_volume_20d > 0 else 0 | |
| # 2. 计算 ATR (以百分比形式表示,方便横向对比不同股价的股票) | |
| df['ATR'] = calculate_atr(df, period=14) | |
| latest_atr = df['ATR'].iloc[-1] | |
| atr_pct = (latest_atr / latest_day['Close']) * 100 if latest_day['Close'] > 0 else 0 | |
| # 3. 计算跳空幅度 (Gap %) | |
| gap_pct = ((latest_day['Open'] - prev_day['Close']) / prev_day['Close']) * 100 | |
| watchlist.append({ | |
| 'Ticker': ticker, | |
| 'Price': round(latest_day['Close'], 2), | |
| 'RVol': round(rvol, 2), | |
| 'ATR_%': round(atr_pct, 2), | |
| 'Gap_%': round(gap_pct, 2), | |
| 'Volume_Millions': round(latest_volume / 1_000_000, 2) | |
| }) | |
| except Exception as e: | |
| print(f"获取 {ticker} 数据失败: {str(e)}") | |
| # 转为 DataFrame 方便处理和展示 | |
| results_df = pd.DataFrame(watchlist) | |
| # 过滤与排序: | |
| # 1. 过滤:波动率 ATR_% 必须大于 1.5%(波动太小的股我们不做日内) | |
| # 2. 排序:按 RVol (相对成交量) 降序排列,成交量放大的股票才是热点 | |
| results_df = results_df.sort_values(by='RVol', ascending=False) | |
| print("【候选股票扫描结果列表】:") | |
| print(results_df.to_string(index=False)) | |
| print("\n" + "-" * 60) | |
| # 选出今天最合适做 Day Trading 的股票 | |
| # 推荐标准:RVol > 1.2 且 ATR_% > 1.5% | |
| recommended = results_df[(results_df['RVol'] > 1.2) & (results_df['ATR_%'] > 1.5)] | |
| print("【AI 盘前交易推荐】:") | |
| if not recommended.empty: | |
| for idx, row in recommended.iterrows(): | |
| print(f"★ 推荐交易 {row['Ticker']}:") | |
| print(f" - 理由:今日成交量放大到平时的 {row['RVol']} 倍 (RVol={row['RVol']}),波动率达 {row['ATR_%']}%。") | |
| print(f" - 操作策略:根据日内K线走势进行突破或回调买入/做空,单笔最大止损控制在账户的 1%。") | |
| else: | |
| # 如果没有符合高波动和高成交量的股票,宁可观望 | |
| top_stock = results_df.iloc[0] if not results_df.empty else None | |
| print("⚠ 警报:今天市场整体成交量萎缩或波动较低。") | |
| print(" - 建议:【观望/不交易】。频繁交易将产生巨大的佣金损耗!") | |
| if top_stock is not None: | |
| print(f" - 若强行操作,可关注相对最活跃的 {top_stock['Ticker']} (RVol={top_stock['RVol']})。") | |
| print("=" * 60) | |
| if __name__ == "__main__": | |
| # 我们扫描 TSLA(特斯拉), NVDA(英伟达), AAPL(苹果), MSFT(微软), AMD(超威半导体) 等大盘股 | |
| popular_stocks = ["TSLA", "NVDA", "AAPL", "MSFT", "AMD"] | |
| scan_stocks(popular_stocks) | |