import pandas as pd
from jqdata import *
from datetime import datetime, timedelta
from jqlib.technical_analysis import *
today = datetime.now().date()
yesterday = today - timedelta(days=1)
TRADE_DATE = today
MA_SHORT = 150 # 短期均线周期
MA_LONG = 200 # 长期均线周期
LOOKBACK_DAYS = 365 # 获取历史数据的天数(需大于最大均线周期)
def filter_stocks():
# ==================== 获取所有A股股票列表 ====================
# 获取所有股票,排除ST、退市等
stocks = get_all_securities(types=['stock'], date=TRADE_DATE)
stock_list = stocks.index.tolist()
name_map = stocks['display_name'].to_dict()
# ==================== 获取历史行情数据 ====================
# 计算需要回溯的起始日期(往前推LOOKBACK_DAYS个交易日)
# 使用get_trade_days获取交易日列表,确保只取交易日
trade_days = get_trade_days(end_date=TRADE_DATE, count=LOOKBACK_DAYS)
start_date = trade_days[0]
print(f"数据起始日期: {start_date}, 截止日期: {TRADE_DATE}")
# 批量获取所有股票的历史收盘价
# fields='close' 只获取收盘价,skip_paused=True跳过停牌日
price_data = get_price(
stock_list,
start_date=start_date,
end_date=TRADE_DATE,
frequency='daily',
fields=['high', 'low', 'close'],
fill_paused=True,
fq='pre' # 前复权
)
# 提取收盘价数据(DataFrame格式:行=日期,列=股票代码)
close_prices = price_data['close']
high_prices = price_data['high']
low_prices = price_data['low']
# ==================== 计算均线并筛选 ====================
# 计算MA50、MA150、MA200
ma_50 = close_prices.rolling(window=50).mean().iloc[-1]
ma_150 = close_prices.rolling(window=150).mean().iloc[-1]
ma_200 = close_prices.rolling(window=200).mean().iloc[-1]
ma_200_30d_ago = close_prices.rolling(window=200).mean().iloc[-30]
# 计算一年最高价
max_250 = high_prices.rolling(window=250).max().iloc[-1]
# 计算一年最低价
min_250 = low_prices.rolling(window=250).min().iloc[-1]
# 计算差值并生成逐只股票的条件
ma200_series = close_prices.rolling(window=200).mean()
ma200_diff = ma200_series.diff()
# 最近30个差值是否全部大于0(逐股票)
ma200_up30_condition = (ma200_diff.iloc[-30:] > 0).all(axis=0)
# 获取最新一天的收盘价、150日均线、200日均线
latest_close = close_prices.iloc[-1]
# 计算相对强度
close_250_ago = close_prices.iloc[-250] # 250个交易日前的收盘价(按位置索引)
returns_250 = (close_prices.iloc[-1] / close_250_ago) - 1 # 涨跌幅
# 计算相对强度(百分位排名,涨幅越小排名越靠前)
# rank(ascending=False, pct=True) 返回0~1,乘以100得到0~100
relative_strength = 100 * returns_250.rank(ascending=True, pct=True)
condition = (
(latest_close > ma_150) & # 1. 当前股价在150日线和200日线上方
(latest_close > ma_200) & # 1. 当前股价在150日线和200日线上方
(latest_close > ma_50) & # 5. 当前股价高于50日线
(ma_150 > ma_200) & # 2. 150日线在200日线上方
(ma_50 > ma_150) & # 4. 50日线高于150日线和200日线
(ma_50 > ma_200) & # 4. 50日线高于150日线和200日线
(latest_close > max_250 * 0.75) & # 7. 当前价格至少处在最近一年最高价的75%以内
(latest_close > min_250 * 0.3) & # 6. 当前股价比最近一年最低股价至少高30%
ma200_up30_condition &
(relative_strength > 70) & # 8. 相对强度大于70
(ma_50.notna()) &
(ma_150.notna()) &
(ma_150.notna()) &
(max_250.notna()) &
(min_250.notna()) &
(latest_close.notna())
)
selected_codes = latest_close[condition].index.tolist()
selected_names = [name_map.get(code, code) for code in selected_codes] # 若未找到则保留代码
print(selected_names)
filter_stocks()