InferRoute / external /Quant.ai /fetch_stock.py
Ypeng12's picture
feat: platform ecosystem showcase and UI upgrade
fa81843
Raw
History Blame Contribute Delete
4.63 kB
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)