1. 环境准备与数据获取

量化交易听起来高大上,但其实用Python搭建一个基础系统并不复杂。我们先从最基础的环境配置开始。我推荐使用Anaconda来管理Python环境,它集成了数据分析常用的库,避免了我们一个个手动安装的麻烦。

安装好Anaconda后,我们需要几个核心库:

  • pandas:数据处理神器
  • numpy:数值计算基础
  • mplfinance:专业的金融数据可视化
  • requests:网络请求库

这些库都可以通过pip一键安装:

pip install pandas numpy mplfinance requests

数据是量化交易的基础。我刚开始做量化时,最大的困扰就是找不到可靠的数据源。这里分享一个实用的方法:使用免费的财经数据API。比如我们可以通过Tushare或者AKShare获取股票数据,它们都提供了Python接口。

下面是一个获取股票数据的示例代码:

import akshare as ak

# 获取平安银行(000001)的日K线数据
stock_data = ak.stock_zh_a_daily(symbol="sz000001", adjust="hfq")
print(stock_data.head())

这个代码会返回包含开盘价、最高价、最低价、收盘价等信息的DataFrame。我建议把获取的数据保存到本地,避免每次都要重新下载:

stock_data.to_csv('pingan_bank.csv', index=False)

2. 数据清洗与特征工程

拿到原始数据后,我们需要进行清洗和处理。这是量化交易中最容易被忽视但极其重要的环节。我踩过的坑告诉我,脏数据会导致策略回测结果严重失真。

首先检查数据质量:

# 检查缺失值
print(stock_data.isnull().sum())

# 检查异常值
print(stock_data.describe())

常见的处理包括:

  • 填充或删除缺失值
  • 处理极端值
  • 统一时间格式

接下来我们要计算一些常用的技术指标。以移动平均线为例:

# 计算5日和20日均线
stock_data['MA5'] = stock_data['close'].rolling(5).mean()
stock_data['MA20'] = stock_data['close'].rolling(20).mean()

# 计算MACD指标
stock_data['EMA12'] = stock_data['close'].ewm(span=12).mean()
stock_data['EMA26'] = stock_data['close'].ewm(span=26).mean()
stock_data['DIF'] = stock_data['EMA12'] - stock_data['EMA26']
stock_data['DEA'] = stock_data['DIF'].ewm(span=9).mean()
stock_data['MACD'] = 2 * (stock_data['DIF'] - stock_data['DEA'])

这些指标会成为我们策略的信号来源。记得要处理好边界情况,比如前几天的数据不足计算均线时该怎么处理。

3. 策略设计与实现

现在进入最核心的部分——交易策略。我们先实现一个简单的双均线策略,这个策略虽然简单,但包含了量化交易的核心逻辑。

策略逻辑:

  • 当短期均线上穿长期均线时买入
  • 当短期均线下穿长期均线时卖出

代码实现:

# 生成交易信号
stock_data['Signal'] = 0  # 0表示无信号
stock_data.loc[stock_data['MA5'] > stock_data['MA20'], 'Signal'] = 1  # 买入信号
stock_data.loc[stock_data['MA5'] <= stock_data['MA20'], 'Signal'] = -1  # 卖出信号

# 计算持仓变化
stock_data['Position'] = stock_data['Signal'].diff()

这个策略看似简单,但实际应用中需要考虑很多细节:

  • 交易成本的影响
  • 滑点问题
  • 仓位管理
  • 止损止盈

我建议新手从这个基础策略开始,逐步添加更复杂的逻辑。比如可以加入成交量过滤:

# 只有当成交量大于20日均量时才交易
stock_data['ValidSignal'] = stock_data['Signal'] * (stock_data['volume'] > stock_data['volume'].rolling(20).mean())

4. 回测与绩效评估

策略设计好后,我们需要验证它的有效性。回测就是在历史数据上模拟交易过程。这里我们实现一个简单的回测框架:

# 初始化资金和持仓
initial_capital = 100000.0
position = 0
portfolio_value = []

for index, row in stock_data.iterrows():
    # 买入信号且当前无持仓
    if row['Signal'] == 1 and position == 0:
        position = initial_capital / row['close']
        initial_capital = 0
    
    # 卖出信号且当前有持仓
    elif row['Signal'] == -1 and position > 0:
        initial_capital = position * row['close']
        position = 0
    
    # 计算当前资产总值
    if position > 0:
        portfolio_value.append(position * row['close'])
    else:
        portfolio_value.append(initial_capital)

评估策略表现时,不能只看总收益,还要考虑风险。常用的指标包括:

  • 年化收益率
  • 最大回撤
  • 夏普比率
  • 胜率

计算这些指标的代码:

# 计算收益率
returns = pd.Series(portfolio_value).pct_change()

# 年化收益率
annual_return = returns.mean() * 252

# 最大回撤
max_drawdown = (pd.Series(portfolio_value).cummax() - pd.Series(portfolio_value)).max()

# 夏普比率
sharpe_ratio = returns.mean() / returns.std() * np.sqrt(252)

5. 可视化展示

好的可视化能让策略表现一目了然。我们用mplfinance来绘制专业的K线图:

import mplfinance as mpf

# 添加买卖信号标记
apds = [
    mpf.make_addplot(stock_data['MA5'], color='blue'),
    mpf.make_addplot(stock_data['MA20'], color='orange'),
    mpf.make_addplot(stock_data.loc[stock_data['Position'] == 1].index, 
                    stock_data['MA5'][stock_data['Position'] == 1],
                    type='scatter', markersize=100, marker='^', color='g'),
    mpf.make_addplot(stock_data.loc[stock_data['Position'] == -1].index,
                    stock_data['MA5'][stock_data['Position'] == -1],
                    type='scatter', markersize=100, marker='v', color='r')
]

mpf.plot(stock_data, type='candle', addplot=apds, volume=True, style='charles')

这张图会显示:

  • K线图(蜡烛图)
  • 成交量
  • 两条均线
  • 买卖信号标记(绿色上箭头表示买入,红色下箭头表示卖出)

对于更复杂的策略,我建议绘制资金曲线和回撤曲线:

plt.figure(figsize=(12,6))
plt.plot(portfolio_value, label='Portfolio Value')
plt.title('Strategy Performance')
plt.xlabel('Date')
plt.ylabel('Value')
plt.legend()
plt.grid()

6. 策略优化与改进

基础策略跑通后,我们可以考虑优化改进。但要注意避免过度拟合,这是我踩过的一个大坑。

合理的优化方法包括:

  • 参数网格搜索
  • 交叉验证
  • 样本外测试

以均线周期优化为例:

from itertools import product

# 定义参数范围
short_periods = range(3, 10)
long_periods = range(20, 60, 5)

best_sharpe = -np.inf
best_params = None

for short, long in product(short_periods, long_periods):
    # 计算均线
    stock_data['MA_short'] = stock_data['close'].rolling(short).mean()
    stock_data['MA_long'] = stock_data['close'].rolling(long).mean()
    
    # 生成信号
    stock_data['Signal'] = np.where(stock_data['MA_short'] > stock_data['MA_long'], 1, -1)
    
    # 计算收益率
    returns = stock_data['close'].pct_change() * stock_data['Signal'].shift(1)
    
    # 计算夏普比率
    sharpe = returns.mean() / returns.std() * np.sqrt(252)
    
    if sharpe > best_sharpe:
        best_sharpe = sharpe
        best_params = (short, long)

除了参数优化,我们还可以改进策略逻辑:

  • 加入止损机制
  • 引入多因子模型
  • 结合市场情绪指标

7. 实盘交易注意事项

从回测到实盘是一个巨大的跨越。根据我的经验,实盘中会遇到很多回测时没考虑到的问题:

  1. 交易延迟问题:

    • 网络延迟
    • 交易所API限制
    • 订单成交延迟
  2. 流动性问题:

    • 大单对市场的影响
    • 买卖价差
    • 成交量不足
  3. 心理因素:

    • 严格执行策略的纪律性
    • 面对亏损时的情绪控制

我建议先用模拟账户测试至少一个月,观察策略的实际表现。同时要设置严格的风险控制:

# 简单的止损逻辑
stop_loss = 0.95  # 5%止损
for index, row in stock_data.iterrows():
    if position > 0 and row['close'] < entry_price * stop_loss:
        # 触发止损
        initial_capital = position * row['close']
        position = 0

最后提醒一点:不要把所有资金投入到一个策略中。分散投资是控制风险的基本原则。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐