
思否收录 · 智能投研与算法交易系列
2023年,一家头部量化私募的AI团队在内部复盘会上投出一张PPT——过去三年,他们的AI模型贡献了65%的超额收益,而传统多因子模型的贡献从70%骤降至30%。
这不是孤例。
从Two Sigma到Citadel,从幻方到九坤,AI正在以惊人的速度重塑量化交易的底层逻辑。传统的"量价因子 + 线性回归"时代正在落幕,"深度学习 + 强化学习 + 另类数据"的新范式正在崛起。
但一个残酷的现实是:大量关于"AI量化"的文章要么停留在"用LSTM预测股价"这种幼儿园级别,要么就是机构内部秘而不宣的黑箱。
本文将从工程实战角度,系统梳理AI量化交易的数据工程、因子挖掘、模型训练、策略回测和实盘部署全链路,全文约8000字,覆盖从传统机器学习到深度强化学习的完整技术栈。
text
┌─────────────────────────────────────────────────────────────────────┐
│ 策略层(Alpha生成) │
│ 深度学习预测 → 强化学习决策 → 组合优化 → 风险控制 │
└───────────────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 模型层(特征工程与建模) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 传统ML模型 │ │ 深度学习模型 │ │ 强化学习模型 │ │
│ │ XGBoost/LightGBM│ │ Transformer │ │ DQN/PPO │ │
│ │ 随机森林 │ │ GNN/图网络 │ │ SAC/A3C │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└───────────────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 数据层(核心基础设施) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 行情数据 │ │ 基本面数据 │ │ 另类数据 │ │
│ │ Tick/分钟/K线│ │ 财报/研报 │ │ 舆情/卫星 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 数据仓库:ClickHouse + Parquet + Delta Lake │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘层级 | 技术选型 | 用途 |
|---|---|---|
数据存储 | ClickHouse / TimescaleDB | 时序数据存储与查询 |
数据湖 | Delta Lake / Iceberg | 大规模数据版本管理 |
特征工程 | Polars / Dask | 高效数据处理(替代Pandas) |
传统ML | XGBoost / LightGBM / CatBoost | 树模型因子挖掘 |
深度学习 | PyTorch / TensorFlow 2.x | Transformer/GNN训练 |
强化学习 | Stable-Baselines3 / Ray RLlib | 强化学习策略训练 |
回测引擎 | VectorBT / Backtrader / 自研 | 策略回测与评估 |
实盘交易 | 券商API(CTP/XTP/IB) | 订单执行 |
数据类型 | 数据量级 | 更新频率 | 存储方案 |
|---|---|---|---|
Tick级别行情 | 数TB/年 | 毫秒级 | ClickHouse(压缩比高) |
1分钟K线 | TB级/年 | 分钟级 | ClickHouse + 分区 |
日线数据 | GB级/年 | 日级 | Parquet + Delta |
财报数据 | MB级/季 | 季度 | PostgreSQL |
舆情数据 | TB级/年 | 实时 | Elasticsearch |
卫星图像 | PB级/年 | 日级 | 对象存储 + 特征提取后存向量 |
python
# data_pipeline.py - 数据采集与清洗
import polars as pl
from clickhouse_driver import Client
from datetime import datetime, timedelta
import requests
import json
class MarketDataPipeline:
def __init__(self):
self.ch_client = Client(host='clickhouse.db', port=9000)
def fetch_minute_bars(self, symbols, start_date, end_date):
"""从行情源获取分钟级数据(模拟)"""
# 实际使用:万得/聚宽/通联等数据API
bars = []
for symbol in symbols:
raw = requests.get(
f'https://api.marketdata.com/minutes',
params={'symbol': symbol, 'start': start_date, 'end': end_date}
).json()
bars.extend(raw['data'])
df = pl.DataFrame(bars)
return self._clean_data(df)
def _clean_data(self, df):
"""数据清洗:去极值、填充缺失、复权处理"""
# 1. 去极值(MAD方法)
median = df['close'].median()
mad = (df['close'] - median).abs().median()
df = df.filter(pl.col('close').is_between(
median - 5 * mad, median + 5 * mad
))
# 2. 填充缺失(前向填充)
df = df.fill_null(strategy='forward')
# 3. 复权处理(后复权)
df = df.with_columns([
(pl.col('close') * pl.col('adjust_factor')).alias('close_adj'),
(pl.col('open') * pl.col('adjust_factor')).alias('open_adj'),
])
return df
def write_to_clickhouse(self, df, table_name='minute_bars'):
"""写入ClickHouse"""
# 将Polars DataFrame转换为ClickHouse插入格式
records = df.to_dicts()
self.ch_client.execute(
f'INSERT INTO {table_name} (symbol, timestamp, open, high, low, close, volume) VALUES',
records
)
# 每日调度:增量更新
if __name__ == '__main__':
pipeline = MarketDataPipeline()
symbols = ['000001.SZ', '600000.SH', '600036.SH'] # 沪深股票示例
yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d')
df = pipeline.fetch_minute_bars(symbols, yesterday, yesterday)
pipeline.write_to_clickhouse(df)坑一:时间戳不对齐
不同数据源的时间戳精度不同(毫秒/微秒/纳秒),合并时出现错位。
方案:统一使用Unix纳秒时间戳,所有数据在写入时强制转换为同一精度。
坑二:数据存在未来信息
在回测中,不小心用到了"未来数据"(比如用当天的收盘价预测当天的交易信号)。
方案:构建严格的时间戳索引,确保所有特征在t时刻只能使用< t的数据。
python
# 时间戳验证函数
def validate_no_lookahead(df, feature_cols, timestamp_col='timestamp'):
"""验证没有未来信息"""
for col in feature_cols:
# 检查特征的最大时间是否超过了标签的时间
assert df[col].timestamp.max() < df['label'].timestamp.min()坑三:数据噪声干扰模型
高频数据中包含大量微观噪声(报价波动、虚假成交),直接使用会干扰模型。
方案:
因子类别 | 描述 | 示例 | 数据来源 |
|---|---|---|---|
量价因子 | 基于价格和成交量的统计特征 | 动量、波动率、换手率 | 行情数据 |
基本面因子 | 公司财务指标 | PE、PB、ROE、营收增速 | 财报 |
情绪因子 | 市场情绪度量 | 北向资金、融资余额、舆情情绪 | 另类数据 |
宏观因子 | 宏观经济指标 | PMI、CPI、利率、汇率 | 宏观经济数据 |
另类因子 | 非传统数据 | 卫星图像、电商销量、招聘数据 | 独特数据源 |
传统手工因子需要domain knowledge和大量测试。现在可以用自编码器和图神经网络自动学习。
python
# autoencoder_factor.py - 用变分自编码器(VAE)自动挖掘因子
import torch
import torch.nn as nn
import torch.nn.functional as F
class FactorAutoEncoder(nn.Module):
"""用VAE从原始量价数据中自动学习因子表示"""
def __init__(self, input_dim=50, latent_dim=16, hidden_dim=128):
super().__init__()
# Encoder
self.encoder = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.BatchNorm1d(hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
)
self.mu = nn.Linear(hidden_dim, latent_dim)
self.log_var = nn.Linear(hidden_dim, latent_dim)
# Decoder
self.decoder = nn.Sequential(
nn.Linear(latent_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, input_dim),
)
def encode(self, x):
h = self.encoder(x)
return self.mu(h), self.log_var(h)
def reparameterize(self, mu, log_var):
std = torch.exp(0.5 * log_var)
eps = torch.randn_like(std)
return mu + eps * std
def forward(self, x):
mu, log_var = self.encode(x)
z = self.reparameterize(mu, log_var) # z就是学习到的因子表示
recon = self.decoder(z)
return recon, mu, log_var
def factor_loss(self, x):
"""提取因子表示并计算重构损失"""
recon, mu, log_var = self.forward(x)
# 重构损失 + KL散度
recon_loss = F.mse_loss(recon, x)
kl_loss = -0.5 * torch.sum(1 + log_var - mu.pow(2) - log_var.exp())
return recon_loss + 0.001 * kl_loss, mu # mu可以作为因子输出指标 | 含义 | 合格线 | 优秀线 |
|---|---|---|---|
IC(信息系数) | 因子值与未来收益的相关系数 | >0.02 | >0.05 |
IR(信息比率) | IC均值 / IC标准差 | >0.3 | >0.7 |
换手率 | 因子组合的周转率 | <100%(月度) | <50%(月度) |
python
# factor_evaluation.py - 因子评估工具
import pandas as pd
import numpy as np
from scipy import stats
def evaluate_factor(df, factor_col, return_col='future_return', period=20):
"""
评估因子的IC、IR和分组收益
df: 包含因子值和未来收益的DataFrame
"""
# 1. 计算IC(Spearman相关性更稳健)
ic_series = df.groupby('date').apply(
lambda g: stats.spearmanr(g[factor_col], g[return_col])[0]
)
avg_ic = ic_series.mean()
ir = avg_ic / ic_series.std()
# 2. 分组收益(将因子从大到小分为10组)
df['group'] = df.groupby('date')[factor_col].transform(
lambda x: pd.qcut(x, 10, labels=False)
)
group_returns = df.groupby(['date', 'group'])[return_col].mean().unstack()
# Top组 - Bottom组的收益差(多头-空头收益)
long_short_returns = group_returns[9] - group_returns[0]
print(f"IC均值: {avg_ic:.4f}")
print(f"IR: {ir:.4f}")
print(f"Top-Bottom年化收益: {long_short_returns.mean()*252:.2%}")
return {
'avg_ic': avg_ic,
'ir': ir,
'long_short_returns': long_short_returns
}场景 | 推荐模型 | 优势 | 劣势 |
|---|---|---|---|
因子挖掘(传统基本面) | XGBoost/LightGBM | 可解释性高、训练快 | 对时序依赖建模弱 |
量价预测(分钟级) | LSTM/Transformer | 捕捉时序依赖 | 数据需求大、训练慢 |
多资产组合优化 | GNN(图神经网络) | 捕捉资产间关联 | 复杂、难解释 |
高频做市 | 强化学习(PPO/SAC) | 自适应能力强 | 训练不稳定 |
python
# transformer_model.py - 基于Transformer的收益率预测
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
class PositionalEncoding(nn.Module):
"""位置编码 - 保留序列顺序信息"""
def __init__(self, d_model, max_len=252):
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)
def forward(self, x):
return x + self.pe[:x.size(1), :]
class StockTransformer(nn.Module):
"""
输入:过去N天的量价特征 (batch, seq_len, features)
输出:未来收益率预测 (batch, 1)
"""
def __init__(self, input_dim=20, d_model=64, nhead=8, num_layers=4):
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,
activation='gelu',
batch_first=True
)
self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)
# 输出层:用最后一个时间步的表示做预测
self.output_proj = nn.Sequential(
nn.Linear(d_model, 64),
nn.GELU(),
nn.Dropout(0.2),
nn.Linear(64, 32),
nn.GELU(),
nn.Linear(32, 1)
)
def forward(self, x):
# x: (batch, seq_len, input_dim)
x = self.input_proj(x) # (batch, seq_len, d_model)
x = self.pos_encoder(x) # 加位置编码
x = self.transformer(x) # (batch, seq_len, d_model)
# 使用最后一个时间步的表示
last_step = x[:, -1, :] # (batch, d_model)
return self.output_proj(last_step) # (batch, 1)特点一:信噪比极低
金融数据的夏普信噪比通常在0.01-0.1之间,远低于图像识别(>1.0)等任务。
解决方案:
python
# 稳健损失函数
def huber_loss(pred, target, delta=0.5):
diff = pred - target
abs_diff = torch.abs(diff)
loss = torch.where(
abs_diff < delta,
0.5 * diff.pow(2),
delta * (abs_diff - 0.5 * delta)
)
return loss.mean()特点二:非平稳性严重
市场规律在变化——2018年和2023年的市场结构完全不同。
解决方案:
特点三:标签噪声大
未来收益包含大量随机成分,"正确"标签永远未知。
解决方案:
传统监督学习回答的是"明天涨多少",而强化学习回答的是"现在该买多少"——这是交易的本质问题。
text
┌─────────────────────────────────────────────────────────────┐
│ 强化学习交易框架 │
│ │
│ 状态State ──▶ Agent(策略网络) ──▶ 动作Action│
│ (当前持仓/价格/因子) (深度神经网络) (买卖数量) │
│ ▲ │ │
│ │ ▼ │
│ │ ┌─────────────────────────┐ │ │
│ └─────────│ 环境Environment │◀───────────┘ │
│ │ (市场 + 交易成本 + 滑点) │ │
│ └─────────────────────────┘ │
│ │ │
│ ▼ │
│ 奖励Reward │
│ (收益率 - 交易成本) │
└─────────────────────────────────────────────────────────────┘python
# ppo_trader.py - PPO算法实现交易策略
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
from collections import deque
import gym
from gym import spaces
# ============ 交易环境定义 ============
class TradingEnv(gym.Env):
"""自定义交易环境"""
def __init__(self, data, initial_capital=1000000, max_position=0.9):
super().__init__()
self.data = data # 股票数据
self.current_step = 0
self.max_step = len(data) - 1
self.initial_capital = initial_capital
self.max_position = max_position
# 动作空间:仓位比例 [-1, 1](负数为做空)
self.action_space = spaces.Box(low=-1, high=1, shape=(1,))
# 状态空间:特征维度
self.observation_space = spaces.Box(
low=-np.inf, high=np.inf,
shape=(data.shape[1] + 1,), # 行情特征 + 当前持仓
dtype=np.float32
)
def reset(self):
self.current_step = 0
self.capital = self.initial_capital
self.position = 0 # 当前持仓(股数)
self.portfolio_value = self.initial_capital
self.trades = []
return self._get_state()
def _get_state(self):
# 获取当前时间步的特征 + 持仓状态
features = self.data[self.current_step].values
state = np.concatenate([features, [self.position / self.initial_capital]])
return state.astype(np.float32)
def step(self, action):
# 1. 执行交易
price = self.data.loc[self.current_step, 'close']
target_position = np.clip(action[0], -self.max_position, self.max_position)
target_shares = target_position * self.portfolio_value / price
# 计算交易成本(冲击成本 + 佣金)
trade_amount = abs(target_shares - self.position) * price
cost = trade_amount * 0.0003 + trade_amount * 0.00005 # 佣金 + 滑点
# 更新持仓
self.position = target_shares
# 2. 转移到下一时间步
self.current_step += 1
done = self.current_step >= self.max_step
# 3. 计算新市值
new_price = self.data.loc[self.current_step, 'close'] if not done else price
self.portfolio_value = self.position * new_price + self.capital - cost
# 4. 计算收益
reward = (self.portfolio_value - self.initial_capital) / self.initial_capital
return self._get_state(), reward, done, {'portfolio': self.portfolio_value}
# ============ PPO Agent实现 ============
class PPOAgent:
def __init__(self, state_dim, action_dim, lr=3e-4, gamma=0.99, clip_ratio=0.2):
self.gamma = gamma
self.clip_ratio = clip_ratio
# Actor网络:输出动作分布
self.actor = nn.Sequential(
nn.Linear(state_dim, 256),
nn.ReLU(),
nn.Linear(256, 128),
nn.ReLU(),
nn.Linear(128, action_dim),
nn.Tanh() # 动作范围 [-1, 1]
)
# Critic网络:输出状态价值
self.critic = nn.Sequential(
nn.Linear(state_dim, 256),
nn.ReLU(),
nn.Linear(256, 128),
nn.ReLU(),
nn.Linear(128, 1)
)
self.actor_optimizer = torch.optim.Adam(self.actor.parameters(), lr=lr)
self.critic_optimizer = torch.optim.Adam(self.critic.parameters(), lr=lr)
def get_action(self, state):
"""根据当前状态选择动作(带探索)"""
state = torch.FloatTensor(state).unsqueeze(0)
action = self.actor(state)
# 添加探索噪声
noise = torch.randn_like(action) * 0.1
action = torch.clamp(action + noise, -1, 1)
return action.detach().numpy()[0]
def update(self, states, actions, rewards, next_states, dones):
"""PPO更新(简化的单步更新)"""
states = torch.FloatTensor(np.array(states))
actions = torch.FloatTensor(np.array(actions))
rewards = torch.FloatTensor(np.array(rewards))
# 计算优势函数
values = self.critic(states).squeeze()
next_values = self.critic(torch.FloatTensor(next_states)).squeeze()
td_target = rewards + self.gamma * next_values * (1 - dones)
advantages = td_target - values.detach()
# Actor更新(PPO的clipped objective)
new_actions = self.actor(states)
ratio = torch.exp(torch.distributions.Normal(new_actions, 0.1).log_prob(actions) -
torch.distributions.Normal(actions, 0.1).log_prob(actions))
clipped_ratio = torch.clamp(ratio, 1 - self.clip_ratio, 1 + self.clip_ratio)
actor_loss = -torch.min(ratio * advantages, clipped_ratio * advantages).mean()
# Critic更新
critic_loss = F.mse_loss(self.critic(states).squeeze(), td_target.detach())
# 反向传播
self.actor_optimizer.zero_grad()
actor_loss.backward()
self.actor_optimizer.step()
self.critic_optimizer.zero_grad()
critic_loss.backward()
self.critic_optimizer.step()
return {'actor_loss': actor_loss.item(), 'critic_loss': critic_loss.item()}风险 | 表现 | 应对策略 |
|---|---|---|
过拟合历史路径 | 在回测中完美,实盘中崩盘 | 增加随机性(Dropout)、多环境训练 |
奖励设计不当 | 模型学会钻空子(如高频刷单) | 加入交易成本惩罚、夏普比率作为奖励 |
训练不稳定 | 策略突然崩溃 | 使用PPO/SAC等稳定算法、添加正则化 |
错误 | 描述 | 如何避免 |
|---|---|---|
未来函数 | 回测使用了未来的数据 | 严格时序切分 |
幸存者偏差 | 只包含当前存在的股票 | 使用全量历史股票池 |
前视偏差 | 根据全样本确定参数 | 滚动窗口训练 |
过拟合 | 策略在样本外失效 | 严格的交叉验证 |
交易成本忽略 | 未考虑佣金/滑点 | 加入合理成本模型 |
分红拆分处理 | 未处理除权除息 | 使用后复权数据 |
极端行情 | 熔断/停牌未处理 | 加入停牌过滤逻辑 |
python
# backtest_engine.py - 回测引擎核心
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
class BacktestEngine:
def __init__(self, data, initial_capital=1_000_000, commission=0.0003, slippage=0.00005):
"""
data: 包含价格数据的DataFrame,必须包含日期、股票代码、价格
"""
self.data = data
self.initial_capital = initial_capital
self.commission = commission
self.slippage = slippage
def run(self, model, start_date, end_date, rebalance_freq='daily'):
"""
运行回测
"""
# 1. 日期切分
dates = pd.date_range(start_date, end_date, freq=rebalance_freq)
# 2. 初始化组合
portfolio = {
'capital': self.initial_capital,
'positions': {}, # {symbol: shares}
'cash': self.initial_capital,
'value_history': [],
'trade_history': []
}
for date in dates:
# 获取当日数据
daily_data = self.data[self.data['date'] == date]
if daily_data.empty:
continue
# 生成交易信号
signals = model.predict(daily_data)
# 执行交易
self._execute_trades(daily_data, signals, portfolio, date)
# 记录组合价值
portfolio['value_history'].append({
'date': date,
'value': self._calc_portfolio_value(portfolio, daily_data)
})
# 3. 计算绩效指标
return self._calc_metrics(portfolio['value_history'])
def _calc_metrics(self, value_history):
"""计算绩效指标:年化收益、夏普、最大回撤等"""
df = pd.DataFrame(value_history)
df['return'] = df['value'].pct_change()
# 年化收益
total_return = df['value'].iloc[-1] / df['value'].iloc[0] - 1
n_years = len(df) / 252
annual_return = (1 + total_return) ** (1 / n_years) - 1
# 夏普比率
risk_free = 0.03
excess_returns = df['return'] - risk_free / 252
sharpe = np.sqrt(252) * excess_returns.mean() / excess_returns.std()
# 最大回撤
cummax = df['value'].cummax()
drawdown = (df['value'] - cummax) / cummax
max_drawdown = drawdown.min()
# 胜率
win_rate = (df['return'] > 0).mean()
return {
'total_return': total_return,
'annual_return': annual_return,
'sharpe_ratio': sharpe,
'max_drawdown': max_drawdown,
'win_rate': win_rate,
'n_trades': len(self.trade_history)
}指标 | 含义 | 目标值 |
|---|---|---|
夏普比率 | 超额收益 / 风险 | >1.5(优秀) |
卡玛比率 | 年化收益 / 最大回撤 | >1.0 |
胜率 | 盈利交易占比 | >50% |
盈亏比 | 平均盈利 / 平均亏损 | >1.5 |
滚动IC衰减 | IC随时间衰减速度 | 保持稳定 |
差异项 | 回测 | 实盘 |
|---|---|---|
成交价格 | 理想价格(收盘价/开盘价) | 滑点 + 冲击成本 |
成交数量 | 不限 | 受流动性限制 |
市场影响 | 无 | 大单会推动价格 |
延迟 | 无 | 网络 + 系统延迟 |
突发事件 | 无 | 新闻、政策等 |
必须一:样本外测试
至少保留最近6个月的数据作为样本外测试,不参与任何调参。
必须二:滚动回测
用前N个月训练,预测后N个月,不断滚动,模拟真实场景。
必须三:考虑成本
实盘的交易成本(佣金 + 滑点)必须纳入模型和回测。成本假设应偏保守而非乐观。
必须四:压力测试
在极端行情下测试策略表现:
必须五:风控先行
python
# 实盘风控规则
class RiskControl:
def __init__(self):
self.max_drawdown = 0.15 # 最大回撤15%
self.max_position = 0.8 # 最大仓位80%
self.max_concentration = 0.2 # 单只股票最大20%
self.daily_loss_limit = 0.05 # 单日最大损失5%
def check(self, portfolio, current_value):
"""风控检查,返回是否通过"""
# 回撤检查
if current_value < portfolio.peak * (1 - self.max_drawdown):
return False, "触发最大回撤止损"
# 单日损失检查
if current_value < portfolio.yesterday_value * (1 - self.daily_loss_limit):
return False, "触发单日损失止损"
return True, "通过"text
┌─────────────────────────────────────────────────────────────────┐
│ 实盘系统架构 │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 行情订阅 │────▶│ 信号生成 │────▶│ 风控检查 │ │
│ │ (WebSocket)│ │ (模型推理)│ │ (规则引擎)│ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 数据缓存 │ │ 日志记录 │ │ 订单执行 │ │
│ │ (Redis) │ │ (数据库) │ │ (券商API)│ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │
│ ▼ │
│ ┌─────────┐ │
│ │ 交易记录 │ │
│ │ (ClickHouse)│ │
│ └─────────┘ │
└─────────────────────────────────────────────────────────────────┘AI量化交易从来不是"有了AI就能赚钱"的童话故事。它是一场关于数据、算法、工程、风控的系统工程。
给同行的一句真心话:AI量化不要追求"完美的模型",而要追求"稳定赚钱的系统"。一个夏普1.5且持续稳定的策略,远比一个夏普3但时好时坏的策略有价值。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。