上一篇我们实现了本书中的简策略的回测:学习《深入浅出python量化交易交易实战》第二章(笔记1)
本片文章是本书第二章平移策略的相关内容
1.学习《深入浅出python量化交易交易实战》第二章(笔记2)
记录学习过程中的代码、疑问和心得
2. 经典策略----移动平均策略 Single Moving Average, SMA
2.1 单一移动平均指数
移动平均策略的核心思想非常简单,且十分容易理解:
-
当股价上升且向上穿过N日的均线时,说明股价在向上突破,此时下单买入;
当股价下降且乡下穿过N日均线时,说明股价整体出现下跌趋势,此时卖出; -
或当M日均价上升穿过N日的均线时(M<N),说明股票处于上升趋势,应下单买入;
反之,当M日均价格下降且穿过N日均线时,说明股票处于下降趋势,应卖出。
下面是单一平均策略的代码实现:
import pandas as pd
import numpy as np
from chapter_2_get import gen_stock_data_table
import matplotlib.pyplot as plt
stock_data = gen_stock_data_table('002419', '20220101', '20221231')
stock_002419 = stock_data['stock']
# 使用10日均线
period = 10
# 设置一个空表,用来存储每10天的价格
avg_10 = []
# 设置一个空列表,用来存储每10天价格的均值
avg_value = []
# 设置一个循环
for price in stock_002419['close']:
# 每天的价格传入avg_10
avg_10.append(price)
# 当列表中存储的数多余10个
if len(avg_10) > period:
# 就把前面传入的价格数据删除,确保列表中最多只有10天的数据
del avg_10[0]
# 将计算好的每个10日均价写入股票价格数据表中
# np.mean() 求平均值
avg_value.append(np.mean(avg_10))
# pd.Series创建一维数组,index 为stock_002419的index
# stock_002419.assign() 增加一个列
stock_002419_avg = stock_002419.assign(
avg_10=pd.Series(avg_value, index=stock_002419.index)
)
print('avg:', stock_002419_avg)
# 可视化
plt.figure(figsize=(10, 6))
# 绘制股价变化
plt.plot(stock_002419_avg['close'], '-', lw=2, c='r', label='price')
# 绘制10日均线
plt.plot(stock_002419_avg['avg_10'], '--', lw=2, c='b', label='avg_10')
# 添加图注和网格
# plt.legend()
plt.grid()
plt.show()
2.2 双移动平均策略
顾名思义,双移动平均策略就是使用两条均线来判断股价未来的走势。
两条均线中,一条是长均线(如10日均线),另一条是短均线(如5日均线)。
这种策略基于一种假设:股价的动量回朝着短期均线的方向移动。当短期均线超过长期移动均线时,
动量向上,此时股价可能会上涨。然而,如果短期均线的移动方向相反,则股价可能下跌。
策略的代码实现:
chapter_2_2_DMA.py
import pandas as pd
import numpy as np
from chapter_2_get import gen_stock_data_table
# 双移动平均策略的封装
def gen_dma_strategy_data(symbol, start_date, end_date):
stock_data = gen_stock_data_table(symbol, start_date, end_date)
stock_002419 = stock_data['stock']
# 新建一个数据表 strategy
# 序号和原始数据保持一致
strategy = pd.DataFrame(index=stock_002419.index)
# signal,用来存储交易信号 卖出:0, 买入:1
strategy['price'] = stock_002419['close']
strategy['signal'] = 0
# 将5日均线保存到avg_5,10日均线保存到avg_10
# dataframe.rolling()函数提供滚动窗口计算的功能
strategy['avg_5'] = stock_002419['close'].rolling(5).mean()
strategy['avg_10'] = stock_002419['close'].rolling(10).mean()
# 当5日均价大于10日均价时,标记为1---买入
# 反之,标记为0---卖出
strategy['signal'] = np.where(strategy['avg_5'] > strategy['avg_10'], 1, 0)
# 根据信号的变化下单,当信号为0-->1时买入
# 当信号从1-->0时卖出
# 交易信号不变时不下单
strategy['order'] = strategy['signal'].diff()
order_cn_map = {
-1.0: '卖出',
0.0: '持有',
1.0: '买入',
}
strategy['order_cn'] = strategy['order'].map(order_cn_map)
# strategy = strategy.fillna('--')
return strategy
回测:
from chapter_2_2_DMA import gen_dma_strategy_data
import matplotlib.pyplot as plt
import pandas as pd
dma_strategy_data = gen_dma_strategy_data('002419', '20220101', '20221231')
print(dma_strategy_data)
'''
strategy_data: 策略的数据
initial_cash: 初始资金
'''
def draw_dma_stock_cash(data):
plt.figure(figsize=(10, 6))
plt.plot(data['stock_value'], lw=2, label='stock_value')
plt.plot(data['total'], lw=2, ls='--', label='total')
plt.legend()
plt.grid()
plt.show()
# 绘图 价格、5日均线和10日均线
def draw_dma_chart(data):
# 绘制
plt.figure(figsize=(50, 12))
# 绘制股价变化
plt.plot(data['price'], lw=1, c='y', label="price")
plt.plot(data['avg_5'], ls='--', c='r', lw=2, label="avg5")
plt.plot(data['avg_10'], ls='-.', c='b', lw=2, label="avg10")
# 买入卖出信号标记
plt.scatter(
data.loc[data.order == 1].index,
data['price'][data.order == 1],
marker='^', s=50, color='r', label='buy'
)
plt.scatter(
data.loc[data.order == -1].index,
data['price'][data.order == -1],
marker='v', s=50, color='g', label='sell'
)
plt.legend()
plt.grid()
plt.show()
draw_dma_chart(dma_strategy_data)
# 回测
def test(strategy_data, initial_cash):
print('============test DMA===============')
# 新建一个positions表,序号和strategy数据表保持一致
positions = pd.DataFrame(index=strategy_data.index).fillna(0)
print(positions)
# 因为A股都是最低100股
# 因此设置stock字段为交易信号的100倍
positions['stock'] = strategy_data['signal'] * 100
portfolio = pd.DataFrame(index=positions.index)
portfolio['stock_value'] = positions.multiply(strategy_data['price'], axis=0)
# 仓位变价就是下单的数量
order = positions.diff()
print('交易量')
print(order.tail(20))
portfolio['stock'] = positions['stock']
# 初始资金减去下单金额的总和就是剩余的资金
portfolio['cash'] = initial_cash - order.multiply(strategy_data['price'], axis=0).cumsum()
portfolio['total'] = portfolio['cash'] + portfolio['stock_value']
print(portfolio.tail(10))
draw_dma_stock_cash(portfolio)
test(dma_strategy_data, 20000)
双移动平均策略回测结果输出: