import akshare as ak import pandas as pd import datetime import time import logging # 配置日志 logging.basicConfig( filename='stock_signals.log', level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s', ) # 板块关键词 TARGET_SECTORS = ['互联网服务', '芯片', '消费', '房地产'] def fetch_sector_stocks(sector_name): """ 获取某个行业板块的股票列表 """ try: df_plates = ak.stock_board_industry_name_em() if not df_plates['板块名称'].isin([sector_name]).any(): logging.warning(f"{sector_name} not exists!") return pd.DataFrame() df = ak.stock_board_industry_cons_em(symbol=sector_name) return df[['代码', '名称']] except Exception as e: logging.error(f"获取板块 {sector_name} 股票失败: {e}") return pd.DataFrame() def compute_signals(df): """ 根据行情数据计算交易信号 """ signals = [] for _, row in df.iterrows(): try: code = row['代码'] name = row['名称'] pct_today = row['当日涨跌幅'] pct_year = row['年内涨跌幅'] pe = row['市盈率'] pb = row['市净率'] signal = '' if pct_today < -5: signal += '今日大跌; ' if pct_year < -20: signal += '年内大跌; ' if pe < 50: signal += '低市盈率; ' if signal: signals.append({ '代码': code, '名称': name, '当日涨跌幅': pct_today, '年内涨跌幅': pct_year, '市盈率': pe, '市净率': pb, '信号': signal.strip() }) except Exception as e: logging.warning(f"处理股票 {row} 时出错: {e}") return pd.DataFrame(signals) def fetch_and_analyze(): """ 获取行情并计算信号 """ logging.info("开始获取并分析行情数据") all_stocks = pd.DataFrame() for sector in TARGET_SECTORS: df = fetch_sector_stocks(sector) if df.empty: continue logging.info(f"获取到板块 [{sector}] {len(df)} 只股票") for code in df['代码']: try: # 获取日K线 kline = ak.stock_zh_a_hist(symbol=code, period='daily', adjust='qfq') kline['日期'] = pd.to_datetime(kline['日期']) kline.set_index('日期', inplace=True) today = kline.iloc[-1] close_today = today['收盘'] close_5d = kline.iloc[-5]['收盘'] if len(kline) >= 5 else today['收盘'] close_month = kline.iloc[-21]['收盘'] if len(kline) >= 21 else today['收盘'] close_year = kline.iloc[0]['收盘'] pct_today = (close_today / today['开盘'] - 1) * 100 pct_5d = (close_today / close_5d -1) * 100 pct_month = (close_today / close_month -1) * 100 pct_year = (close_today / close_year -1) *100 # 获取市盈率、市净率 fundamentals = ak.stock_a_lg_indicator(symbol=code) pe = fundamentals.iloc[-1]['市盈率(TTM)'] pb = fundamentals.iloc[-1]['市净率'] all_stocks = pd.concat([all_stocks, pd.DataFrame([{ '代码': code, '名称': df.loc[df['代码']==code, '名称'].values[0], '当日涨跌幅': pct_today, '5日涨跌幅': pct_5d, '本月涨跌幅': pct_month, '年内涨跌幅': pct_year, '市盈率': pe, '市净率': pb }])]) except Exception as e: logging.error(f"获取股票 {code} 数据失败: {e}") continue signals = compute_signals(all_stocks) if not signals.empty: signals.to_csv(f'stock_signals_{datetime.date.today()}.csv', index=False, encoding='utf-8-sig') logging.info(f"生成信号 {len(signals)} 条,已写入 CSV。") else: logging.info("未发现符合条件的交易信号") if __name__ == "__main__": fetch_and_analyze()