切换菜单
搜索
个人笔记云
首页
java
spring
springmvc
python
使用教程
笔记管理
搜索
登录/注册
好物分享
退出
搜索
做交易,一根均线上多下空,能做到稳定盈利?是“大道至简”,还是嘴盘忽悠?Python量化交易均线策略测试二
2021-10-11
734
**参考视频教程:** [**首门程序员理财课 Python量化交易系统实战 **](http://www.notescloud.top/goods/detail/1348) 交易,一根均线上多下空,能做到稳定盈利?是"大道至简",还是嘴盘忽悠?Python量化交易均线策略测试一中,我们用python程序量化测试了10日均线,50日均线作为单根均线策略,测试发现收益十分不理想。 今天我们继续对单根均线策略做量化测试,今天突然想起昨天的测试还有60日均线没有做量化测试,为什么要测试60日均线,因为60日均线太有名了,外号有牛熊分界线,万能均线,生命线等。 仅仅以股价大于60均线作为买入条件,最近三年收益如下:
![](images/4597/1633936578251.png) 60均线最近三年收益 我们再把昨天python量化交易测试的10日均线,50日均线收益图贴在下面,很明显60日均线收益确实整体要稍微好一些。
![](images/4597/1633936578506.png) 10日均线,最近三年收益
![](images/4597/1633936578823.png) 50日均线,最近三年收益 我们对60日均线策略买点做一些优化 1.股价大于60日均线,且均线趋势向上 2.股价大于30日均线,且均线趋势向上 3.股价大于10日均线,且均线趋势向上 回测最近三年收益如下:
![](images/4597/1633936579097.png) 擦,貌似越优化收益越差,这也是意料之外的事情,这个优化策略,是我在百度找的一篇洋洋洒洒写了1万多字,图文并茂,貌似,看起来大神给的策略,看起来大神给的策略,量化交易回测不行啊,未完待续。。。。。。 如果你有策略愿意让我量化测试一下,请加公众号:Python量化交易探索,留言告诉我。 60日均线策略,python量化交易代码如下: # -\*- coding: utf-8 -\*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import os import shutil import time import matplotlib def danjunxian(start,end): mairuhou_mark = 0 zhengshouyi_num = 0 fushouyi_num = 0 cur_dir = os.getcwd() # get current path folder_name = 'result' dir_new = os.path.join(cur_dir, folder_name) end_date = \['2019/12/31','2019/12/30','2019/12/29','2019/12/28'\] #删掉结果 if os.path.exists(dir_new + "\\\\" + start.replace("/","_") + "__" + end.replace("/","_") + "celie_xiangxi" + '.txt'): os.remove(dir_new + "\\\\" + start.replace("/","_") + "__" + end.replace("/","_") + "celie_xiangxi" + '.txt') if os.path.exists(dir_new + "\\\\" + start.replace("/","_") + "__" + end.replace("/","_") + "dangtian_buy" +'.txt'): os.remove(dir_new + "\\\\" + start.replace("/","_") + "__" + end.replace("/","_") + "dangtian_buy" +'.txt') if os.path.exists(dir_new + "\\\\" + start.replace("/","_") + "__" + end.replace("/","_") + '"dangtian_sell"' +'.txt'): os.remove(dir_new + "\\\\" + start.replace("/","_") + "__" + end.replace("/","_") + '"dangtian_sell"' +'.txt') #设置路径 dir_list = \[\] lujing = r'C:\\gupiao\\gupiaoci' for i in os.listdir(r'C:\\gupiao\\gupiaoci'): a = i.split('.')\[0\] if a\[0\] != '3': dir_list.append(lujing+'\\\\'+i) #个股 total_shouyi=1 total_date_buy = \[\] total_date_sell = \[\] buy_date_zhengshouyi = \[\] buy_date_fushouyi = \[\] for j in dir_list: #获取数据 name = (j.split('\\\\')\[-1\]).split('.')\[0\] df = pd.read_table(j,header=1,usecols=range(6), parse_dates=\[0\], index_col=0,encoding='gb2312') df.index.rename('date', inplace=True) df.rename(columns={' 开盘':'open', ' 最高':'high', ' 最低':'low', ' 收盘':'close',' 成交量':'vol'}, inplace=True) df = df.drop('数据来源:通达信') df.close = df.close.astype(np.float32)#设置为32位,4字节,默认64位,8字节,append到list之后就会多小数位 df.low = df.low.astype(np.float32)#设置为32位,4字节,默认64位,8字节,append到list之后就会多小数位 df.vol = df.vol.astype(np.int64) df2 = df\[start:end\]\[:len(df.vol)-1\] df = df\[start:end\] #均线 ma5 = df2.close.rolling(window=5,center=False).mean() ma5= ma5\[start:end\] ma3 = df2.close.rolling(window=3,center=False).mean() ma3= ma3\[start:end\] ma8 = df2.close.rolling(window=8, center=False).mean() ma8 = ma8\[start:end\] ma15 = df2.close.rolling(window=15, center=False).mean() ma15 = ma15\[start:end\] ma10 = df2.close.rolling(window=10,center=False).mean() ma10= ma10\[start:end\] ma12 = df2.close.rolling(window=12, center=False).mean() ma12 = ma12\[start:end\] ma20 = df2.close.rolling(window=20,center=False).mean() ma20= ma20\[start:end\] ma30 = df2.close.rolling(window=30,center=False).mean() ma30 = ma30\[start:end\] ma60 = df2.close.rolling(window=60,center=False).mean() ma60 = ma60\[start:end\] ma120 = df2.close.rolling(window=120,center=False).mean() ma120 = ma120\[start:end\] ma200 = df2.close.rolling(window=200, center=False).mean() ma200 = ma200\[start:end\] ma250 = df2.close.rolling(window=250,center=False).mean() ma250 = ma250\[start:end\] #均量线 vol5 = df2.vol.rolling(window=5,center=False).mean() vol5 = vol5\[start:end\] vol3 = df2.vol.rolling(window=3,center=False).mean() vol3 = vol3\[start:end\] vol8 = df2.vol.rolling(window=8,center=False).mean() vol8 = vol8\[start:end\] vol10 = df2.vol.rolling(window=10,center=False).mean() vol10 = vol10\[start:end\] vol20 = df2.vol.rolling(window=20,center=False).mean() vol20 = vol20\[start:end\] vol15 = df2.vol.rolling(window=15,center=False).mean() vol15 = vol15\[start:end\] vol30 = df2.vol.rolling(window=30,center=False).mean() vol30 = vol30\[start:end\] vol60 = df2.vol.rolling(window=60, center=False).mean() vol60 = vol60\[start:end\] #设置初始化数据 #买入条件,buy_status = True,其次是chicang_status = False chicang_status = False#chicang_status==False的时候表示空仓状态,可以买入,买入之后需要将其设置为True,表示股票为持有状态 buy_status = False#初始化buy的状态为False,当遇到买点出现时,设置状态为True,表示之后可以买入 buy_price = \[\] buy_date = \[\] sell_price = \[\] sell_date = \[\] low_vol = \[\] low_vol_index = \[\]
fengexian_mark = 0 #low_vol df_temp = df temp_vol = df.vol temp_index = df.index ma3_temp = ma3 ma5_temp = ma5 ma8_temp = ma8 ma15_temp = ma15 ma10_temp = ma10 ma12_temp = ma12 ma20_temp = ma20 ma30_temp = ma30 ma60_temp = ma60 ma120_temp = ma120 ma200_temp = ma200 ma250_temp = ma250 vol5_temp = vol5 vol3_temp = vol3 vol8_temp = vol8 vol15_temp = vol15 vol10_temp = vol10 vol20_temp = vol20 vol30_temp = vol30 vol60_temp = vol60 temp_vol_max = 0
for j in range(60,len(temp_vol)): if buy_status == False and chicang_status == False: buy_status = True#买点出现时,设置状态为True,表示之后可以买入 vol_max_dangtian_index = temp_index\[j\] close_min_new = df_temp.close\[j\] elif buy_status == True and chicang_status == False: if df_temp.at\[temp_index\[j-1\],'close'\] \>= 300 or (df_temp.high\[j\]-df_temp.close\[j-1\])/df_temp.close\[j-1\] \< -0.09: chicang_status = False buy_status = False break elif df_temp.close\[j\] \> ma60_temp\[j\]:#股价大于60均线,买入 if len(gupiaochichang) \>= 1: for gupiaochichang_item in gupiaochichang: if gupiaochichang_item\[0\] == temp_index\[j\] and gupiaochichang_item\[1\] \>= 1: #print(gupiaochichang_item) chicang_status = False buy_status = False if chicang_status == False and buy_status == False: continue chicang_status = True buy_status = False#买入之后设置状态为False buy_price_m = df_temp.at\[temp_index\[j\],'close'\] buy_date_temp = temp_index\[j\] buy_price.append(df_temp.at\[temp_index\[j\],'close'\]) buy_date.append(temp_index\[j\]) total_date_buy.append(\[name,temp_index\[j\]\]) fengexian_mark = 1 close_max = df_temp.close\[j\]#加入买入当天就是当前最高价 #股票持仓,买日期加1,买日期不在list,则加入 for gupiaochichuang_item in gupiaochichang: if gupiaochichuang_item\[0\] == temp_index\[j\]: gupiaochichuang_item\[1\] += 1 if len(gupiaochichang) == 0: gupiaochichang.append(\[temp_index\[j\],1\]) else: for i22 in range(len(gupiaochichang)): if len(gupiaochichang) != 0 and i22 == len(gupiaochichang) -1 and gupiaochichang\[i22\]\[0\] != temp_index\[j\]:#找到最后一个还没有找到买日期,加将买日期加入 gupiaochichang.append(\[temp_index\[j\],1\]) #存结果 with open(dir_new + "\\\\" + start.replace("/","_") + "__" +end.replace("/","_") + "celie_xiangxi" + '.txt','a') as f: f.write("股票名称--" + name + '\\n' + "开始日期--" + start + '\\n' + "结束日期--" + end + '\\n' ) f.write("最大vol/当天vol 大于20当天日期-----\>" + str(vol_max_dangtian_index) + '\\n') f.write('\\n' + "股票名称--" + name + "--买入价格--" + "--步长--" + "--" + "--j--" + str(j) + "--" + str(df_temp.at\[temp_index\[j\],'close'\]) + "--买入日期--" + str(temp_index\[j\])) elif chicang_status == True: if df_temp.close\[j\] \< ma10_temp\[j\]:#股价小于10日均线卖出 chicang_status = False sell_price.append(df_temp.close\[j\]) sell_date.append(temp_index\[j\]) total_date_sell.append(\[name,temp_index\[j\]\]) if (df_temp.close\[j\]-buy_price_m)/buy_price_m \> 0: zhengshouyi_num += 1#正收益次数加1 buy_date_zhengshouyi.append(buy_date_temp) else: fushouyi_num += 1#负收益次数加1 buy_date_fushouyi.append(buy_date_temp) total_shouyi \*= (1 + (df_temp.close\[j\]-buy_price_m)/buy_price_m) mairuhou_mark = 0 #存结果 with open(dir_new + "\\\\" + start.replace("/","_") + "__" +end.replace("/","_") + "celie_xiangxi" + '.txt','a') as f: f.write('\\n' + "股票名称--" + name + "--最高点下跌10%,卖出价格--" + "--步长--" + "--" + "--j--" + str(j) + "--" + str(df_temp.close\[j\]) + "--卖出日期--" + str(temp_index\[j\])) elif (df_temp.close\[j\] - buy_price_m)/buy_price_m \< -0.05: chicang_status = False sell_price.append(df_temp.close\[j\]) sell_date.append(temp_index\[j\]) total_date_sell.append(\[name,temp_index\[j\]\]) fushouyi_num += 1#负收益次数加1 total_shouyi \*= (1 - 0.05) mairuhou_mark = 0 # buy_date_fushouyi.append(\[name,buy_date_temp\]) buy_date_fushouyi.append(buy_date_temp) #存结果 with open(dir_new + "\\\\" + start.replace("/","_") + "__" +end.replace("/","_") + "celie_xiangxi" + '.txt','a') as f: f.write('\\n' + "股票名称--" + name + "--止损-0.05,卖出价格--" + "--步长--" + "--" + "--j--" + str(j) + "--" + str(df_temp.close\[j\]) + "--卖出日期--" + str(temp_index\[j\])) elif mairuhou_mark \>= 10: total_shouyi \*= (1 + (df_temp.close\[j\] - buy_price_m)/buy_price_m) chicang_status = False sell_price.append(df_temp.close\[j\]) sell_date.append(temp_index\[j\]) total_date_sell.append(\[name,temp_index\[j\]\]) mairuhou_mark = 0 if (df_temp.close\[j\] - buy_price_m)/(buy_price_m) \> 0: zhengshouyi_num += 1 buy_date_zhengshouyi.append(buy_date_temp) #print("持有超过10天卖出:",(df_temp.close\[j\] - buy_price_m)/(buy_price_m)) #存结果 with open(dir_new + "\\\\" + start.replace("/","_") + "__" +end.replace("/","_") + "celie_xiangxi" + '.txt','a') as f: f.write('\\n' + "股票名称--" + name + "--持有超过5天卖出,大于0.01,卖出价格--" + "--" + "--j--" + str(j) + "--" + str(df_temp.close\[j\]) + "--卖出日期--" + str(temp_index\[j\])) else: fushouyi_num += 1 buy_date_fushouyi.append(buy_date_temp) #print("持有超过10天卖出:",(df_temp.close\[j\] - buy_price_m) / (buy_price_m )) #存结果 with open(dir_new + "\\\\" + start.replace("/","_") + "__" +end.replace("/","_") + "celie_xiangxi" + '.txt','a') as f: f.write('\\n' + "股票名称--" + name + "--持有超过15天卖出,小于0.01,大于0,卖出价格--" + "--j--" + str(j) + "--" + str(df_temp.close\[j\]) + "--卖出日期--" + str(temp_index\[j\])) else: mairuhou_mark += 1 gupiaochichang.sort(key=lambda x:x\[0\]) #if zhengshouyi_num+fushouyi_num != 0: #print(start,"----",end,"total_shouyi=",'%.2f'%(total_shouyi),"概率",'%.2f'%(zhengshouyi_num/(zhengshouyi_num+fushouyi_num)),"正收益次数-\>",zhengshouyi_num,"负收益次数-\>",fushouyi_num) #存结果 cur_dir = os.getcwd() # get current path folder_name = 'result' dir_new = os.path.join(cur_dir, folder_name) #存买入,卖出价格,日期 if len(buy_price) \> len(sell_price): if buy_date\[-1\] in end_date: with open(dir_new + "\\\\" + start.replace("/","_") + "__" +end.replace("/","_") + "dangtian_buy" +'.txt','a') as f: f.writelines('\\n' + name + "--" + str(buy_date\[-1\]) + '\\n' + 'buy: ' + str(buy_price\[-1\]) + '\\n') if len(sell_price) != 0: if sell_date\[-1\] in end_date: with open(dir_new + "\\\\" + start.replace("/","_") + "__" +end.replace("/","_") + "dangtian_sell" +'.txt','a') as f: for rr in range(len(sell_price)): if rr == 0: f.writelines('\\n' + name + '\\n' + 'buy: ' + str(buy_price\[rr\]) + str(buy_date\[rr\]) + '\\n' + 'sell: ' + str(sell_price\[rr\]) + str(sell_date\[rr\]) + '\\n') else: f.writelines( 'buy: ' +str(buy_price\[rr\]) + str(buy_date\[rr\]) + '\\n' + 'sell: ' + str(sell_price\[rr\]) + str(sell_date\[rr\]) + '\\n') if zhengshouyi_num+fushouyi_num != 0: zshouyi = float(zhengshouyi_num/(zhengshouyi_num+fushouyi_num)) fshouyi = float(fushouyi_num/(zhengshouyi_num+fushouyi_num)) total_num = zhengshouyi_num+fushouyi_num total_date_buy.sort(key=lambda x:x\[1\]) total_date_sell.sort(key=lambda x:x\[1\]) x = \[\] y = \[\] for i in buy_date_zhengshouyi: if i not in x: x.append(i) for i in buy_date_fushouyi: if i not in y: y.append(i) if fengexian_mark == 1: with open(dir_new + "\\\\" + start.replace("/","_") + "__" + end.replace("/","_") + "celie_xiangxi" + '.txt','a') as f: f.write('\\n' + '\\n' + "--------------------分割线----------------------" + '\\n' + '\\n') buy_date_zhengshouyi_count = \[\] buy_date_fushouyi_count = \[\] i = 0 x.sort() y.sort() for i in x: if buy_date_zhengshouyi.count(i) \>= 0: with open(dir_new + "\\\\" + start.replace("/","_") + "__" +end.replace("/","_") + "celie_xiangxi" + '.txt','a') as f: f.write('\\n' + "正收益买日期--" + str(buy_date_zhengshouyi.count(i)) + "--" +str(i)) buy_date_zhengshouyi_count.append(buy_date_zhengshouyi.count(i)) with open(dir_new + "\\\\" + start.replace("/","_") + "__" +end.replace("/","_") + "celie_xiangxi" + '.txt','a') as f: f.write('\\n' ) for i in y: if buy_date_fushouyi.count(i) \>= 0: with open(dir_new + "\\\\" + start.replace("/","_") + "__" +end.replace("/","_") + "celie_xiangxi" + '.txt','a') as f: f.write('\\n' + "负收益买日期--" + str(buy_date_fushouyi.count(i)) + "--" +str(i)) buy_date_fushouyi_count.append(buy_date_fushouyi.count(i)) if zhengshouyi_num+fushouyi_num != 0: print(start,"----",end,"total_shouyi=",'%.2f'%(total_shouyi),"概率",'%.2f'%(zhengshouyi_num/(zhengshouyi_num+fushouyi_num)),"正收益次数-\>",zhengshouyi_num,"负收益次数-\>",fushouyi_num) with open(dir_new + "\\\\" + start.replace("/","_") + "__" +end.replace("/","_") + "celie_xiangxi" + '.txt','a') as f: f.write('\\n' +'\\n' + "正收益买日期count--" + str(len(buy_date_zhengshouyi_count)) + "--" + str(buy_date_zhengshouyi_count)) f.write('\\n' + "负收益买日期count--" + str(len(buy_date_fushouyi_count)) + "--" + str(buy_date_fushouyi_count)) f.write('\\n' + "买卖总次数" + str(zhengshouyi_num+fushouyi_num) + "--正收益买概率--" + str('%.2f'%(zhengshouyi_num/(zhengshouyi_num + fushouyi_num))) + "--正收益次数--" + str(zhengshouyi_num)) for i in range(len(gupiaochichang)): if i == 0: f.write('\\n' + "买日期count:" + '\\n' + str(gupiaochichang\[i\])) else: f.write('\\n' + str(gupiaochichang\[i\])) shutil.copy(dir_new + "\\\\" + start.replace("/","_") + "__" +end.replace("/","_") + "celie_xiangxi" + '.txt',dir_new + "\\\\" + start.replace("/","_") + "__" +end.replace("/","_") + '_' + "--正收益买概率--" + str('%.2f'%(zhengshouyi_num / (zhengshouyi_num + fushouyi_num))) + "--倍数--" + str('%.2f'%(total_shouyi))+ "--正收益次数--" + str(zhengshouyi_num) + "--负收益次数--" + str(fushouyi_num)+ '.txt') return \[total_shouyi,zhengshouyi_num / (zhengshouyi_num + fushouyi_num)\] if __name__ == '__main__': print('start',time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) cur_dir = os.getcwd() # get current path folder_name = 'result' dir_new = os.path.join(cur_dir, folder_name) start = \['2016/09/01','2017/09/01','2018/09/01'\] end = \['2017/12/31','2018/12/31','2019/12/31'\] gupiaochichang = \[\] total_shouyi_gailv = \[\] shouyi_huizong = \[\] gailv_huizong = \[\] for i in range(len(start)): total_shouyi_gailv.append(danjunxian(start\[i\],end\[i\])) for i in range(len(total_shouyi_gailv)): shouyi_huizong.append(total_shouyi_gailv\[i\]\[0\]) gailv_huizong.append(total_shouyi_gailv\[i\]\[1\]) #绘图 matplotlib.rcParams\['font.family'\] = 'SimHei' # SimHei黑体 matplotlib.rcParams\['font.size'\] = 10 dir_new = os.path.join(cur_dir, folder_name) file_name = dir_new + r'/' + 'shouyi' #收益图 plt.subplots_adjust(hspace=0.5) fig1 = plt.subplot(211) fig1.set_title("收益") # 设置坐标轴范围 fig1.set_xlim(-1, 3) fig1.set_ylim(0, 50) # 设置坐标轴名称 fig1.set_xlabel('日期') fig1.set_ylabel('收益') # 设置坐标轴刻度 fig1.set_xticks = np.arange(-1, 4, 1) for a, b in zip(end, shouyi_huizong): fig1.text(a, b + 0.1, '%.2f' % b, ha='center', va='bottom', color='red', fontsize=20) fig1.plot(end, shouyi_huizong, color='blue', marker='o') # 正收益概率图 fig2 = plt.subplot(212) fig2.set_title("收益概率") # 设置坐标轴范围 fig2.set_xlim(-1, 3) fig2.set_ylim(0, 1.2) # 设置坐标轴名称 fig2.set_xlabel('日期') fig2.set_ylabel('收益概率') # 设置坐标轴刻度 fig2.set_xticks = np.arange(-1, 4, 1) for a, b in zip(end, gailv_huizong): fig2.text(a, b + 0.1, '%.2f' % b, ha='center', va='bottom', color='blue', fontsize=20) fig2.plot(end, gailv_huizong, color='blue', marker='o') plt.savefig(file_name, dpi=300) print('end',time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
教程分类
热门视频教程
热门文章
热门书籍推荐