Skip to content

AI 选股模型 ​

🤖 AI 不是预测水晶球,而是模式识别工具 —— 用机器学习从历史数据中寻找统计规律。

🎯 AI 选股的现实 ​

✅ AI 擅长的 ​

  • 模式识别:从数据中发现统计规律
  • 多因子综合:同时处理几十个因子
  • 高频迭代:每天/分钟更新预测
  • 情绪中立:不受贪婪/恐惧影响

❌ AI 不擅长的 ​

  • 预测黑天鹅:模型对极端事件无能为力
  • 因果推断:只能找相关,不能找因果
  • 应对市场变化:模型会失效(过拟合)
  • 替代基本面研究:财务分析仍需人工

📊 主流 AI 选股方法 ​

方法原理难度数据需求
XGBoost / LightGBM梯度提升树⭐⭐中
LSTM / GRU循环神经网络⭐⭐⭐大
Transformer注意力机制⭐⭐⭐⭐大
CNN卷积神经网络⭐⭐⭐大
强化学习试错学习⭐⭐⭐⭐⭐大
图神经网络关系建模⭐⭐⭐⭐大

🛠️ 1. XGBoost 选股(最实用) ​

📌 原理 ​

XGBoost 是 梯度提升决策树(GBDT)的优化实现。

核心思想:

  • 多棵决策树逐步拟合残差
  • 每棵树纠正前一棵的错误
  • 最后所有树的预测加权平均

AI 选股流程图 ​

数据采集特征工程模型训练回测评估实盘交易行情/财报/舆情100+ 因子XGBoost/LSTM年化/夏普/回撤每日调仓

🔧 实战代码 ​

python
"""
XGBoost 多因子选股模型
"""
import pandas as pd
import numpy as np
import akshare as ak
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, roc_auc_score

# ============ 1. 准备数据 ============
def get_data():
    """获取股票池 + 因子数据"""
    # 股票池(沪深 300 成分股)
    stocks = ak.index_stock_cons_weight_csindex(symbol='000300')
    print(f'股票池: {len(stocks)} 只')
    
    # 此处简化为示例:取 10 只股票
    sample_stocks = stocks['成分券代码'].head(10).tolist()
    
    data = []
    for code in sample_stocks:
        try:
            df = ak.stock_zh_a_hist(
                symbol=code,
                period='daily',
                start_date='20200101',
                end_date='20241231',
                adjust='qfq'
            )
            if not df.empty:
                df['代码'] = code
                data.append(df)
        except:
            continue
    
    df_all = pd.concat(data, ignore_index=True)
    return df_all

# ============ 2. 特征工程 ============
def compute_features(df):
    """计算技术因子"""
    df = df.sort_values(['代码', '日期']).reset_index(drop=True)
    
    # 收益率
    df['return_1d'] = df.groupby('代码')['收盘'].pct_change(1)
    df['return_5d'] = df.groupby('代码')['收盘'].pct_change(5)
    df['return_20d'] = df.groupby('代码')['收盘'].pct_change(20)
    
    # 均线
    df['ma5'] = df.groupby('代码')['收盘'].transform(lambda x: x.rolling(5).mean())
    df['ma20'] = df.groupby('代码')['收盘'].transform(lambda x: x.rolling(20).mean())
    
    # 均线偏离度
    df['ma_dev_5'] = (df['收盘'] - df['ma5']) / df['ma5']
    df['ma_dev_20'] = (df['收盘'] - df['ma20']) / df['ma20']
    
    # 量能
    df['volume_ratio'] = df.groupby('代码')['成交量'].transform(
        lambda x: x / x.rolling(5).mean()
    )
    
    # 波动率
    df['volatility'] = df.groupby('代码')['return_1d'].transform(
        lambda x: x.rolling(20).std()
    )
    
    # RSI
    delta = df.groupby('代码')['收盘'].diff()
    gain = delta.where(delta > 0, 0)
    loss = (-delta).where(delta < 0, 0)
    avg_gain = gain.groupby(df['代码']).transform(lambda x: x.rolling(14).mean())
    avg_loss = loss.groupby(df['代码']).transform(lambda x: x.rolling(14).mean())
    rs = avg_gain / (avg_loss + 1e-9)
    df['rsi'] = 100 - 100 / (1 + rs)
    
    # 目标:未来 5 日收益
    df['target'] = df.groupby('代码')['收盘'].pct_change(5).shift(-5)
    df['target'] = (df['target'] > 0.02).astype(int)  # 5 日涨 > 2% 标记为 1
    
    return df.dropna()

# ============ 3. 训练模型 ============
def train_model(df):
    """训练 XGBoost 模型"""
    
    features = ['return_1d', 'return_5d', 'return_20d',
                'ma_dev_5', 'ma_dev_20', 'volume_ratio',
                'volatility', 'rsi']
    
    X = df[features]
    y = df['target']
    
    # 划分训练集 / 测试集(按时间)
    split_idx = int(len(df) * 0.8)
    X_train, X_test = X.iloc[:split_idx], X.iloc[split_idx:]
    y_train, y_test = y.iloc[:split_idx], y.iloc[split_idx:]
    
    # 训练
    model = xgb.XGBClassifier(
        n_estimators=200,
        max_depth=6,
        learning_rate=0.05,
        subsample=0.8,
        colsample_bytree=0.8,
        random_state=42,
        use_label_encoder=False,
        eval_metric='logloss'
    )
    
    model.fit(
        X_train, y_train,
        eval_set=[(X_test, y_test)],
        early_stopping_rounds=20,
        verbose=50
    )
    
    # 评估
    y_pred = model.predict(X_test)
    y_proba = model.predict_proba(X_test)[:, 1]
    
    print(f'准确率: {accuracy_score(y_test, y_pred):.2%}')
    print(f'AUC: {roc_auc_score(y_test, y_proba):.4f}')
    
    # 特征重要性
    importance = pd.DataFrame({
        '特征': features,
        '重要性': model.feature_importances_
    }).sort_values('重要性', ascending=False)
    print('\n特征重要性:')
    print(importance)
    
    return model

# ============ 4. 主流程 ============
if __name__ == '__main__':
    df = get_data()
    df_feat = compute_features(df)
    model = train_model(df_feat)

📊 特征重要性可视化 ​

python
import matplotlib.pyplot as plt
import xgboost as xgb

xgb.plot_importance(model, max_num_features=10)
plt.title('Top 10 特征重要性')
plt.tight_layout()
plt.savefig('feature_importance.png', dpi=200)
plt.show()

🧠 2. LSTM 选股(深度学习) ​

📌 原理 ​

LSTM(Long Short-Term Memory)是循环神经网络(RNN)的一种,能记忆长期依赖关系。

核心思想:

  • 用过去 N 天的价格 / 因子预测未来 M 天的收益
  • 通过"门"机制控制信息流动
  • 适合时间序列数据

🔧 实战代码 ​

python
"""
LSTM 时序预测选股模型
"""
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
from sklearn.preprocessing import StandardScaler
import akshare as ak

# ============ 1. 数据准备 ============
def prepare_lstm_data(stock_code='600519', seq_len=60, pred_len=5):
    """准备 LSTM 输入数据"""
    
    # 获取数据
    df = ak.stock_zh_a_hist(
        symbol=stock_code,
        period='daily',
        start_date='20180101',
        end_date='20241231',
        adjust='qfq'
    )
    
    # 计算特征
    df['return'] = df['收盘'].pct_change()
    df['ma5'] = df['收盘'].rolling(5).mean()
    df['ma20'] = df['收盘'].rolling(20).mean()
    df['volatility'] = df['return'].rolling(20).std()
    df['volume_ratio'] = df['成交量'] / df['成交量'].rolling(5).mean()
    df['target'] = df['收盘'].pct_change(pred_len).shift(-pred_len)
    
    df = df.dropna()
    
    # 标准化
    features = ['return', 'ma5', 'ma20', 'volatility', 'volume_ratio', '成交量']
    scaler = StandardScaler()
    df[features] = scaler.fit_transform(df[features])
    
    # 构建序列
    X, y = [], []
    for i in range(len(df) - seq_len - pred_len):
        X.append(df[features].iloc[i:i+seq_len].values)
        y.append(df['target'].iloc[i+seq_len])
    
    return np.array(X), np.array(y), scaler

# ============ 2. LSTM 模型 ============
class StockLSTM(nn.Module):
    def __init__(self, input_dim, hidden_dim=64, num_layers=2, output_dim=1):
        super().__init__()
        self.hidden_dim = hidden_dim
        self.num_layers = num_layers
        
        self.lstm = nn.LSTM(
            input_dim, hidden_dim, num_layers,
            batch_first=True,
            dropout=0.2
        )
        self.fc = nn.Linear(hidden_dim, output_dim)
    
    def forward(self, x):
        # x: (batch, seq_len, input_dim)
        h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_dim).to(x.device)
        c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_dim).to(x.device)
        
        out, _ = self.lstm(x, (h0, c0))
        # 取最后一个时间步
        out = self.fc(out[:, -1, :])
        return out

# ============ 3. 训练 ============
def train_lstm(stock_code='600519'):
    X, y, scaler = prepare_lstm_data(stock_code)
    
    # 划分
    split = int(len(X) * 0.8)
    X_train, X_test = X[:split], X[split:]
    y_train, y_test = y[:split], y[split:]
    
    # 转 tensor
    X_train = torch.FloatTensor(X_train)
    y_train = torch.FloatTensor(y_train).unsqueeze(1)
    X_test = torch.FloatTensor(X_test)
    y_test = torch.FloatTensor(y_test).unsqueeze(1)
    
    # DataLoader
    train_loader = DataLoader(
        TensorDataset(X_train, y_train),
        batch_size=32, shuffle=True
    )
    
    # 模型
    model = StockLSTM(input_dim=X.shape[2])
    criterion = nn.MSELoss()
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    
    # 训练循环
    for epoch in range(50):
        model.train()
        for X_batch, y_batch in train_loader:
            optimizer.zero_grad()
            y_pred = model(X_batch)
            loss = criterion(y_pred, y_batch)
            loss.backward()
            optimizer.step()
        
        if (epoch + 1) % 10 == 0:
            model.eval()
            with torch.no_grad():
                y_test_pred = model(X_test)
                test_loss = criterion(y_test_pred, y_test)
                print(f'Epoch {epoch+1}/50, Train Loss: {loss.item():.6f}, Test Loss: {test_loss.item():.6f}')
    
    return model

# ============ 4. 预测 + 回测 ============
def predict_top_stocks(model_pool, top_n=10):
    """预测 + 选股"""
    scores = []
    for code, model in model_pool.items():
        # 预测未来收益
        # ...
        scores.append((code, predicted_return))
    
    # 排序
    scores.sort(key=lambda x: x[1], reverse=True)
    return scores[:top_n]

🤖 3. Transformer 选股(前沿) ​

📌 原理 ​

Transformer 是 2017 年 Google 提出的注意力机制模型。

核心思想:

  • 用"自注意力"关注输入序列的所有位置
  • 比 LSTM 更擅长捕捉长程依赖
  • 可并行训练,效率高
  • GPT、BERT 都基于此

🔧 实战代码 ​

python
"""
Transformer 时序选股模型
"""
import torch
import torch.nn as nn
import math

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_len=5000):
        super().__init__()
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        self.register_buffer('pe', pe.unsqueeze(0))
    
    def forward(self, x):
        return x + self.pe[:, :x.size(1)]

class StockTransformer(nn.Module):
    def __init__(self, input_dim, d_model=64, nhead=4, num_layers=3, output_dim=1):
        super().__init__()
        self.input_proj = nn.Linear(input_dim, d_model)
        self.pos_encoder = PositionalEncoding(d_model)
        encoder_layer = nn.TransformerEncoderLayer(
            d_model=d_model, nhead=nhead, 
            dim_feedforward=256, dropout=0.1,
            batch_first=True
        )
        self.transformer = nn.TransformerEncoder(encoder_layer, num_layers)
        self.fc = nn.Linear(d_model, output_dim)
    
    def forward(self, x):
        # x: (batch, seq_len, input_dim)
        x = self.input_proj(x)
        x = self.pos_encoder(x)
        out = self.transformer(x)
        out = self.fc(out[:, -1, :])  # 取最后时间步
        return out

# 使用
model = StockTransformer(input_dim=6)

📊 模型效果评估 ​

📌 评估指标 ​

指标含义优秀
准确率预测涨跌正确率> 60%
AUCROC 曲线下面积> 0.65
夏普比率风险调整后收益> 1.5
最大回撤历史最大亏损< 15%
年化收益平均年化> 15%
胜率盈利笔数比例> 55%
盈亏比平均盈利 / 亏损> 1.5

📌 常见问题 ​

问题解决方案
准确率高但回测差可能过拟合,加正则化
样本外效果差用 walk-forward 验证
牛市赚熊市亏训练数据需多周期
因子失效定期重训练

🛠️ 实战建议 ​

📌 数据处理 ​

python
# 数据清洗标准化流程
def clean_data(df):
    # 1. 缺失值
    df = df.fillna(method='ffill').fillna(method='bfill')
    
    # 2. 异常值
    for col in df.select_dtypes(include=[np.number]):
        mean = df[col].mean()
        std = df[col].std()
        df[col] = df[col].clip(mean - 3*std, mean + 3*std)
    
    # 3. 标准化
    from sklearn.preprocessing import RobustScaler
    scaler = RobustScaler()
    numeric_cols = df.select_dtypes(include=[np.number]).columns
    df[numeric_cols] = scaler.fit_transform(df[numeric_cols])
    
    return df

📌 避免过拟合 ​

python
# 1. 交叉验证
from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)

# 2. 正则化
xgb.XGBClassifier(
    reg_alpha=0.1,      # L1 正则
    reg_lambda=0.1,     # L2 正则
    max_depth=5,        # 限制深度
    min_child_weight=3  # 限制叶节点样本
)

# 3. 早停
model.fit(
    X_train, y_train,
    eval_set=[(X_test, y_test)],
    early_stopping_rounds=20
)

📌 样本外测试 ​

python
# 用最近 20% 数据做样本外测试
split_idx = int(len(df) * 0.8)
df_train = df.iloc[:split_idx]
df_test = df.iloc[split_idx:]

# 训练用训练集
model.fit(X_train, y_train)

# 评估用测试集
y_pred = model.predict(X_test)
print(f'样本外 AUC: {roc_auc_score(y_test, y_pred):.2%}')

🧠 模型选择建议 ​

📌 按场景选 ​

场景推荐模型
快速验证XGBoost / LightGBM
因子多(> 20)XGBoost / LightGBM
时间序列预测LSTM / Transformer
复杂模式Transformer
结构化数据XGBoost / Random Forest
非结构化数据(新闻、研报)BERT / GPT
图关系(供应链)GNN

📌 实战建议 ​

  1. 从简单开始:先用 XGBoost
  2. 多模型对比:XGBoost vs LSTM vs Transformer
  3. 样本外验证:必须做
  4. 定期重训练:市场变化快
  5. 融合多模型:投票 / 加权

⚠️ AI 选股的局限 ​

📌 常见陷阱 ​

陷阱解释
过拟合模型在历史有效,未来失效
数据泄漏用未来数据预测过去
幸存者偏差只看还在的股票
黑天鹅极端事件模型无能为力
市场变化因子会失效
过拟合回测回测好但实盘差

📌 实战建议 ​

  1. 永远做样本外测试
  2. 多模型集成:用投票 / 加权平均
  3. 定期重训练:每季度更新
  4. 风控优先:止损 / 仓位控制
  5. 不要过度信任:AI 是工具不是神

📊 完整工具链 ​

📌 Python 库 ​

bash
# 机器学习
pip install scikit-learn xgboost lightgbm catboost

# 深度学习
pip install torch torchvision torchaudio
pip install tensorflow keras

# 金融数据
pip install akshare tushare baostock

# 回测
pip install backtrader zipline-reloaded

# 可视化
pip install matplotlib seaborn plotly

# 时间序列
pip install statsmodels prophet

📌 推荐学习资源 ​

资源类型链接
《Advances in Financial Machine Learning》书Marcos López de Prado
《机器学习》课程Andrew Ng / Coursera
《深度学习》书Ian Goodfellow
Qlib开源微软 AI 量化平台
Kaggle竞赛<https://www.kaggle.com/>

📖 相关阅读 ​

来源 ​

💡 数据截至 2026-08;具体规则以交易所/监管机构最新公告为准。

本知识库内容仅供学习参考,不构成任何投资建议。
本站总访问量 ... 次 · 访客数 ... 人