双均线策略是比较经典的策略,股票的价格均线是投资参考的重要指标。均线有快线和慢线之分,当快线向上穿过慢线则是金叉,一般执行买入操作,当快线向下穿过慢线时则形成死叉,一般执行卖出操作。基于这个基本思路,出于兴趣爱好,便使用python复现了这个量化策略。代码封装如下。
在运行这个代码块时,请先运行以下代码:
pip install pandas
pip install numpy
pip install matplotlib
pip install tqdm
pip install qstock
在电脑上安装了这些库之后就可以运行下面的封装代码了,具体讲解在代码块下面。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from tqdm import tqdm
import qstock as qs
class Dual_moving_average_stra():
'''
code --> '000001' str
start_time --> '20220101' str
window0 --> 5 int
window1 --> 10 int
verbose --> bool default=True
plot --> bool default=True
init_money = 10000 一万块本金 看末期能有多少收益
'''
def __init__(self, code, start_time, window0, window1, verbose=True, plot=True):
self.code = code
self.start_time = start_time
self.window0 = window0
self.window1 = window1
self.verbose = verbose
self.plot = plot
def get_data(self):
#print(self.code, self.start_time)
df = qs.get_data(self.code, start=self.start_time, end=None, freq=101, fqt=1)
df['MA_' + str(self.window0)] = df.rolling(self.window0, min_periods=1).mean()['close']
df['MA_' + str(self.window1)] = df.rolling(self.window1, min_periods=1).mean()['close']
df['gold'] = np.nan
df.gold = df['MA_' + str(self.window0)] > df['MA_' + str(self.window1)]
signal = pd.DataFrame()
signal = df.gold.apply(lambda x:1 if x==True else 0)
df['gold_death_cha'] = signal - signal.shift(1).fillna(0)
return df
def strategy(self):
init_money = 10000
quant = 0
df = self.get_data()
signal = df.gold_death_cha
price_list = df.open
money_list = []
for i in tqdm(range(df.shape[0])):
if i+1 == df.shape[0]: # 因为是次日买卖 所以得提前一天结束代码
break
price = price_list.iloc[i+1]
if signal.iloc[i] == 1:
# 金叉全仓买入
quant += int(init_money / (price * 100))
init_money -= quant * price * 100
if self.verbose == True:
print('此次购买数量:', quant)
print('证券价格:', price)
print('本金还剩:',init_money)
print('金叉买入执行完毕----------------------------------')
if signal.iloc[i] == -1:
init_money += quant * price * 100
quant = 0 # 清仓
money_list.append(init_money)
if self.verbose == True:
print('清仓:', quant)
print('证券价格:', price)
print('本金还剩:',init_money)
print('死叉卖出执行完毕----------------------------------')
if self.plot == True:
plt.figure(figsize=(20,20))
plt.subplot(2,1,1)
plt.grid()
plt.plot(df.index, df.close, label='close', linewidth=3)
plt.plot(df.index, df['MA_' + str(self.window0)], c='red', label=('MA_' + str(self.window0)), linewidth=3)
plt.plot(df.index, df['MA_' + str(self.window1)], c='grey', label=('MA_' + str(self.window1)), linewidth=3)
plt.xticks(rotation=45)
plt.legend(fontsize=20)
plt.subplot(2,1,2)
plt.grid()
plt.plot(range(len(money_list)), money_list, linewidth=3, label='money')
plt.xticks(rotation=45)
plt.legend(fontsize=20)
plt.show()
这是一个金叉死叉的策略,在股价出现死叉时则全仓卖出,在股价出现金叉时则全仓买入,然后给予10000元的本金,查看最后一期能剩余多少本金。
首先实例化我们的对象:
model = Dual_moving_average_stra('600460', '20200101', 5, 20)
第一个参数是股票代码,第二个参数是提取数据的开始时间,例子中是从2020年开始的。5表示计算股票的5日均线,20表示计算股票的20日均线。然后就完成了模型的实例化。
model.strategy()
然后再运行这个代码就可以查看策略的效果了。
此次购买数量: 6
证券价格: 16.52
本金还剩: 88.0
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 13.63
本金还剩: 8266.0
死叉卖出执行完毕----------------------------------
此次购买数量: 4
证券价格: 18.67
本金还剩: 797.9999999999991
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 17.74
本金还剩: 7893.999999999998
死叉卖出执行完毕----------------------------------
此次购买数量: 5
证券价格: 14.7
本金还剩: 543.9999999999982
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 14.26
本金还剩: 7673.999999999998
死叉卖出执行完毕----------------------------------
此次购买数量: 5
证券价格: 14.67
本金还剩: 338.9999999999991
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 17.23
本金还剩: 8954.0
死叉卖出执行完毕----------------------------------
此次购买数量: 5
证券价格: 16.63
本金还剩: 639.0
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 16.28
本金还剩: 8779.0
死叉卖出执行完毕----------------------------------
此次购买数量: 5
证券价格: 15.78
本金还剩: 889.0000000000009
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 25.62
本金还剩: 13699.0
死叉卖出执行完毕----------------------------------
此次购买数量: 5
证券价格: 27.09
本金还剩: 154.00000000000182
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 25.66
本金还剩: 12984.000000000004
死叉卖出执行完毕----------------------------------
此次购买数量: 4
证券价格: 26.12
本金还剩: 2536.0000000000036
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 24.28
本金还剩: 12248.000000000004
死叉卖出执行完毕----------------------------------
此次购买数量: 4
证券价格: 30.48
本金还剩: 56.00000000000364
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 57.4
本金还剩: 23016.000000000004
死叉卖出执行完毕----------------------------------
此次购买数量: 3
证券价格: 63.35
本金还剩: 4011.0000000000036
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 61.9
本金还剩: 22581.000000000004
死叉卖出执行完毕----------------------------------
此次购买数量: 3
证券价格: 57.57
本金还剩: 5310.000000000004
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 53.4
本金还剩: 21330.0
死叉卖出执行完毕----------------------------------
此次购买数量: 3
证券价格: 61.11
本金还剩: 2997.0
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 54.7
本金还剩: 19407.000000000004
死叉卖出执行完毕----------------------------------
此次购买数量: 3
证券价格: 63.39
本金还剩: 390.00000000000364
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 65.1
本金还剩: 19920.000000000004
死叉卖出执行完毕----------------------------------
此次购买数量: 3
证券价格: 61.64
本金还剩: 1428.0000000000036
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 59.26
本金还剩: 19206.000000000004
死叉卖出执行完毕----------------------------------
此次购买数量: 3
证券价格: 51.92
本金还剩: 3630.0000000000036
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 50.55
本金还剩: 18795.0
死叉卖出执行完毕----------------------------------
此次购买数量: 3
证券价格: 55.29
本金还剩: 2208.0
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 54.35
本金还剩: 18513.0
死叉卖出执行完毕----------------------------------
此次购买数量: 4
证券价格: 42.49
本金还剩: 1517.0
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 45.58
本金还剩: 19749.0
死叉卖出执行完毕----------------------------------
此次购买数量: 4
证券价格: 46.08
本金还剩: 1317.0
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 45.45
本金还剩: 19497.0
死叉卖出执行完毕----------------------------------
此次购买数量: 3
证券价格: 50.79
本金还剩: 4260.0
金叉买入执行完毕----------------------------------
清仓: 0
证券价格: 46.77
本金还剩: 18291.0
。。。
模型可以打印每次买入和卖出的日志,模型中的参数 verbose 和plot是默认打开的,可以看需求关闭。同时Plot参数提供了可视化, 上方的图表示股价图,下方图则是本金变化图形。
从图形可以看出600460的股价从20年的低点到21年的高年翻了将近6倍,而均线策略最高只取得了两倍的收益。
我们可以继续换一组参数,用5日线和10日线来操作。
model = Dual_moving_average_stra('600460', '20200101', 5, 10)
model.strategy()
可以看出来效果会比5日线和20日线的组合好一点。个人感觉这个策略比较依赖标的。