说到技术指标,想必不论新韭老韭都能随口念出几个来,是判断行情走势的衍生工具,也是行情软件中必备的板块内容,技术分析一直在大多数股民中备受好评,各个频道的股评专家也是乐此不疲。
股市参与者千万人,在同一市场中博弈,作为个人投资者获取行业或公司信息并无优势,然而关于市场所有的信息最终都会落到交易上,会体现在成交量和价格上,量价信息这个层面来讲,市场是公平的,这也是技术分析能够为大多数人使用的原因之一。
使用技术分析之前,我们需要了解到,所有技术分析能够成立,是建立在以下的三大基石之上
[(0, 'None'),(1, 'MA'),(2, 'MA1'),(3, 'EMA'),(4, 'EMA1'),(5, 'MACD'),(6, 'KDJ'),(7, 'CCI'),(8, 'RSI'),(9, 'BOLL'),(10, 'BIAS'),(11, 'TRIX'),(12, 'BBI'),(13, 'PSY')]
下面是指标在沪深300指数上的择时表现,以按收益进行排序
['10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','30']
通过上述的测试结果,我们初步发现如下的情况
本篇为了避免个别标的自身特性的影响,都是拿指数进行的测试,然而不同指数本身也有各自的特点,可以借助已有的代码进行更多标的枚举暴力测试,通过多回测方法进一步挖掘更为有效的指标参数。
20181225:感谢@宋一堆 的改进思路,已将可用做空版代码附在评论区
20181225:感谢评论区sailer 和 iamrobot 的留言,文章统计结果已替换为修正后的结果,代码已更改附在评论区
#1 先导入所需要的程序包
import datetime
import numpy as np
import pandas as pd
import time
from jqdata import *
from pandas import Series, DataFrame
import matplotlib.pyplot as plt
import seaborn as sns
import itertools
import copy
import pickle
# 定义类'参数分析'
class parameter_analysis(object):
# 定义函数中不同的变量
def __init__(self, algorithm_id=None):
self.algorithm_id = algorithm_id # 回测id
self.params_df = pd.DataFrame() # 回测中所有调参备选值的内容,列名字为对应修改面两名称,对应回测中的 g.XXXX
self.results = {} # 回测结果的回报率,key 为 params_df 的行序号,value 为
self.evaluations = {} # 回测结果的各项指标,key 为 params_df 的行序号,value 为一个 dataframe
self.backtest_ids = {} # 回测结果的 id
# 新加入的基准的回测结果 id,可以默认为空 '',则使用回测中设定的基准
self.benchmark_id = None
self.benchmark_returns = [] # 新加入的基准的回测回报率
self.returns = {} # 记录所有回报率
self.excess_returns = {} # 记录超额收益率
self.log_returns = {} # 记录收益率的 log 值
self.log_excess_returns = {} # 记录超额收益的 log 值
self.dates = [] # 回测对应的所有日期
self.excess_max_drawdown = {} # 计算超额收益的最大回撤
self.excess_annual_return = {} # 计算超额收益率的年化指标
self.evaluations_df = pd.DataFrame() # 记录各项回测指标,除日回报率外
# 定义排队运行多参数回测函数
def run_backtest(self, #
algorithm_id=None, # 回测策略id
running_max=10, # 回测中同时巡行最大回测数量
start_date='2006-01-01', # 回测的起始日期
end_date='2016-11-30', # 回测的结束日期
frequency='day', # 回测的运行频率
initial_cash='1000000', # 回测的初始持仓金额
param_names=[], # 回测中调整参数涉及的变量
param_values=[] # 回测中每个变量的备选参数值
):
# 当此处回测策略的 id 没有给出时,调用类输入的策略 id
if algorithm_id == None: algorithm_id=self.algorithm_id
# 生成所有参数组合并加载到 df 中
# 包含了不同参数具体备选值的排列组合中一组参数的 tuple 的 list
param_combinations = list(itertools.product(*param_values))
# 生成一个 dataframe, 对应的列为每个调参的变量,每个值为调参对应的备选值
to_run_df = pd.DataFrame(param_combinations)
# 修改列名称为调参变量的名字
to_run_df.columns = param_names
# 设定运行起始时间和保存格式
start = time.time()
# 记录结束的运行回测
finished_backtests = {}
# 记录运行中的回测
running_backtests = {}
# 计数器
pointer = 0
# 总运行回测数目,等于排列组合中的元素个数
total_backtest_num = len(param_combinations)
# 记录回测结果的回报率
all_results = {}
# 记录回测结果的各项指标
all_evaluations = {}
# 在运行开始时显示
print ('【已完成|运行中|待运行】:'),
# 当运行回测开始后,如果没有全部运行完全的话:
while len(finished_backtests)<total_backtest_num:
# 显示运行、完成和待运行的回测个数
print('[%s|%s|%s].' % (len(finished_backtests),
len(running_backtests),
(total_backtest_num-len(finished_backtests)-len(running_backtests)) )),
# 记录当前运行中的空位数量
to_run = min(running_max-len(running_backtests), total_backtest_num-len(running_backtests)-len(finished_backtests))
# 把可用的空位进行跑回测
for i in range(pointer, pointer+to_run):
# 备选的参数排列组合的 df 中第 i 行变成 dict,每个 key 为列名字,value 为 df 中对应的值
params = to_run_df.iloc[i].to_dict()
# 记录策略回测结果的 id,调整参数 extras 使用 params 的内容
backtest = create_backtest(algorithm_id = algorithm_id,
start_date = start_date,
end_date = end_date,
frequency = frequency,
initial_cash = initial_cash,
extras = params,
# 再回测中把改参数的结果起一个名字,包含了所有涉及的变量参数值
name = str(params)
)
# 记录运行中 i 回测的回测 id
running_backtests[i] = backtest
# 计数器计数运行完的数量
pointer = pointer+to_run
# 获取回测结果
failed = []
finished = []
# 对于运行中的回测,key 为 to_run_df 中所有排列组合中的序数
for key in running_backtests.keys():
# 研究调用回测的结果,running_backtests[key] 为运行中保存的结果 id
bt = get_backtest(running_backtests[key])
# 获得运行回测结果的状态,成功和失败都需要运行结束后返回,如果没有返回则运行没有结束
status = bt.get_status()
# 当运行回测失败
if status == 'failed':
# 失败 list 中记录对应的回测结果 id
failed.append(key)
# 当运行回测成功时
elif status == 'done':
# 成功 list 记录对应的回测结果 id,finish 仅记录运行成功的
finished.append(key)
# 回测回报率记录对应回测的回报率 dict, key to_run_df 中所有排列组合中的序数, value 为回报率的 dict
# 每个 value 一个 list 每个对象为一个包含时间、日回报率和基准回报率的 dict
all_results[key] = bt.get_results()
# 回测回报率记录对应回测结果指标 dict, key to_run_df 中所有排列组合中的序数, value 为回测结果指标的 dataframe
all_evaluations[key] = bt.get_risk()
# 记录运行中回测结果 id 的 list 中删除失败的运行
for key in failed:
running_backtests.pop(key)
# 在结束回测结果 dict 中记录运行成功的回测结果 id,同时在运行中的记录中删除该回测
for key in finished:
finished_backtests[key] = running_backtests.pop(key)
# 当一组同时运行的回测结束时报告时间
if len(finished_backtests) != 0 and len(finished_backtests) % running_max == 0 and to_run !=0:
# 记录当时时间
middle = time.time()
# 计算剩余时间,假设没工作量时间相等的话
remain_time = (middle - start) * (total_backtest_num - len(finished_backtests)) / len(finished_backtests)
# print 当前运行时间
print('[已用%s时,尚余%s时,请不要关闭浏览器].' % (str(round((middle - start) / 60.0 / 60.0,3)),
str(round(remain_time / 60.0 / 60.0,3)))),
# 5秒钟后再跑一下
time.sleep(30)
# 记录结束时间
end = time.time()
print ('')
print('【回测完成】总用时:%s秒(即%s小时)。' % (str(int(end-start)),
str(round((end-start)/60.0/60.0,2)))),
# 对应修改类内部对应
self.params_df = to_run_df
self.results = all_results
self.evaluations = all_evaluations
self.backtest_ids = finished_backtests
#7 最大回撤计算方法
def find_max_drawdown(self, returns):
# 定义最大回撤的变量
result = 0
# 记录最高的回报率点
historical_return = 0
# 遍历所有日期
for i in range(len(returns)):
# 最高回报率记录
historical_return = max(historical_return, returns[i])
# 最大回撤记录
drawdown = 1-(returns[i] + 1) / (historical_return + 1)
# 记录最大回撤
result = max(drawdown, result)
# 返回最大回撤值
return result
# log 收益、新基准下超额收益和相对与新基准的最大回撤
def organize_backtest_results(self, benchmark_id=None):
# 若新基准的回测结果 id 没给出
if benchmark_id==None:
# 使用默认的基准回报率,默认的基准在回测策略中设定
self.benchmark_returns = [x['benchmark_returns'] for x in self.results[0]]
# 当新基准指标给出后
else:
# 基准使用新加入的基准回测结果
self.benchmark_returns = [x['returns'] for x in get_backtest(benchmark_id).get_results()]
# 回测日期为结果中记录的第一项对应的日期
self.dates = [x['time'] for x in self.results[0]]
# 对应每个回测在所有备选回测中的顺序 (key),生成新数据
# 由 {key:{u'benchmark_returns': 0.022480100091729405,
# u'returns': 0.03184566700000002,
# u'time': u'2006-02-14'}} 格式转化为:
# {key: []} 格式,其中 list 为对应 date 的一个回报率 list
for key in self.results.keys():
self.returns[key] = [x['returns'] for x in self.results[key]]
# 生成对于基准(或新基准)的超额收益率
for key in self.results.keys():
self.excess_returns[key] = [(x+1)/(y+1)-1 for (x,y) in zip(self.returns[key], self.benchmark_returns)]
# 生成 log 形式的收益率
for key in self.results.keys():
self.log_returns[key] = [log(x+1) for x in self.returns[key]]
# 生成超额收益率的 log 形式
for key in self.results.keys():
self.log_excess_returns[key] = [log(x+1) for x in self.excess_returns[key]]
# 生成超额收益率的最大回撤
for key in self.results.keys():
self.excess_max_drawdown[key] = self.find_max_drawdown(self.excess_returns[key])
# 生成年化超额收益率
for key in self.results.keys():
self.excess_annual_return[key] = (self.excess_returns[key][-1]+1)**(252./float(len(self.dates)))-1
# 把调参数据中的参数组合 df 与对应结果的 df 进行合并
self.evaluations_df = pd.concat([self.params_df, pd.DataFrame(self.evaluations).T], axis=1)
# self.evaluations_df =
# 获取最总分析数据,调用排队回测函数和数据整理的函数
def get_backtest_data(self,
algorithm_id=None, # 回测策略id
benchmark_id=None, # 新基准回测结果id
file_name='results.pkl', # 保存结果的 pickle 文件名字
running_max=10, # 最大同时运行回测数量
start_date='2006-01-01', # 回测开始时间
end_date='2016-11-30', # 回测结束日期
frequency='day', # 回测的运行频率
initial_cash='1000000', # 回测初始持仓资金
param_names=[], # 回测需要测试的变量
param_values=[] # 对应每个变量的备选参数
):
# 调运排队回测函数,传递对应参数
self.run_backtest(algorithm_id=algorithm_id,
running_max=running_max,
start_date=start_date,
end_date=end_date,
frequency=frequency,
initial_cash=initial_cash,
param_names=param_names,
param_values=param_values
)
# 回测结果指标中加入 log 收益率和超额收益率等指标
self.organize_backtest_results(benchmark_id)
# 生成 dict 保存所有结果。
results = {'returns':self.returns,
'excess_returns':self.excess_returns,
'log_returns':self.log_returns,
'log_excess_returns':self.log_excess_returns,
'dates':self.dates,
'benchmark_returns':self.benchmark_returns,
'evaluations':self.evaluations,
'params_df':self.params_df,
'backtest_ids':self.backtest_ids,
'excess_max_drawdown':self.excess_max_drawdown,
'excess_annual_return':self.excess_annual_return,
'evaluations_df':self.evaluations_df}
# 保存 pickle 文件
pickle_file = open(file_name, 'wb')
pickle.dump(results, pickle_file)
pickle_file.close()
# 读取保存的 pickle 文件,赋予类中的对象名对应的保存内容
def read_backtest_data(self, file_name='results.pkl'):
pickle_file = open(file_name, 'rb')
results = pickle.load(pickle_file)
self.returns = results['returns']
self.excess_returns = results['excess_returns']
self.log_returns = results['log_returns']
self.log_excess_returns = results['log_excess_returns']
self.dates = results['dates']
self.benchmark_returns = results['benchmark_returns']
self.evaluations = results['evaluations']
self.params_df = results['params_df']
self.backtest_ids = results['backtest_ids']
self.excess_max_drawdown = results['excess_max_drawdown']
self.excess_annual_return = results['excess_annual_return']
self.evaluations_df = results['evaluations_df']
# 回报率折线图
def plot_returns(self):
# 通过figsize参数可以指定绘图对象的宽度和高度,单位为英寸;
fig = plt.figure(figsize=(20,8))
ax = fig.add_subplot(111)
# 作图
for key in self.returns.keys():
ax.plot(range(len(self.returns[key])), self.returns[key], label=key)
# 设定benchmark曲线并标记
ax.plot(range(len(self.benchmark_returns)), self.benchmark_returns, label='benchmark', c='k', linestyle='--')
ticks = [int(x) for x in np.linspace(0, len(self.dates)-1, 11)]
plt.xticks(ticks, [self.dates[i] for i in ticks])
# 设置图例样式
ax.legend(loc = 2, fontsize = 10)
# 设置y标签样式
ax.set_ylabel('returns',fontsize=20)
# 设置x标签样式
ax.set_yticklabels([str(x*100)+'% 'for x in ax.get_yticks()])
# 设置图片标题样式
ax.set_title("Strategy's performances with different parameters", fontsize=21)
plt.xlim(0, len(self.returns[0]))
# 超额收益率图
def plot_excess_returns(self):
# 通过figsize参数可以指定绘图对象的宽度和高度,单位为英寸;
fig = plt.figure(figsize=(20,8))
ax = fig.add_subplot(111)
# 作图
for key in self.returns.keys():
ax.plot(range(len(self.excess_returns[key])), self.excess_returns[key], label=key)
# 设定benchmark曲线并标记
ax.plot(range(len(self.benchmark_returns)), [0]*len(self.benchmark_returns), label='benchmark', c='k', linestyle='--')
ticks = [int(x) for x in np.linspace(0, len(self.dates)-1, 11)]
plt.xticks(ticks, [self.dates[i] for i in ticks])
# 设置图例样式
ax.legend(loc = 2, fontsize = 10)
# 设置y标签样式
ax.set_ylabel('excess returns',fontsize=20)
# 设置x标签样式
ax.set_yticklabels([str(x*100)+'% 'for x in ax.get_yticks()])
# 设置图片标题样式
ax.set_title("Strategy's performances with different parameters", fontsize=21)
plt.xlim(0, len(self.excess_returns[0]))
# log回报率图
def plot_log_returns(self):
# 通过figsize参数可以指定绘图对象的宽度和高度,单位为英寸;
fig = plt.figure(figsize=(20,8))
ax = fig.add_subplot(111)
# 作图
for key in self.returns.keys():
ax.plot(range(len(self.log_returns[key])), self.log_returns[key], label=key)
# 设定benchmark曲线并标记
ax.plot(range(len(self.benchmark_returns)), [log(x+1) for x in self.benchmark_returns], label='benchmark', c='k', linestyle='--')
ticks = [int(x) for x in np.linspace(0, len(self.dates)-1, 11)]
plt.xticks(ticks, [self.dates[i] for i in ticks])
# 设置图例样式
ax.legend(loc = 2, fontsize = 10)
# 设置y标签样式
ax.set_ylabel('log returns',fontsize=20)
# 设置图片标题样式
ax.set_title("Strategy's performances with different parameters", fontsize=21)
plt.xlim(0, len(self.log_returns[0]))
# 超额收益率的 log 图
def plot_log_excess_returns(self):
# 通过figsize参数可以指定绘图对象的宽度和高度,单位为英寸;
fig = plt.figure(figsize=(20,8))
ax = fig.add_subplot(111)
# 作图
for key in self.returns.keys():
ax.plot(range(len(self.log_excess_returns[key])), self.log_excess_returns[key], label=key)
# 设定benchmark曲线并标记
ax.plot(range(len(self.benchmark_returns)), [0]*len(self.benchmark_returns), label='benchmark', c='k', linestyle='--')
ticks = [int(x) for x in np.linspace(0, len(self.dates)-1, 11)]
plt.xticks(ticks, [self.dates[i] for i in ticks])
# 设置图例样式
ax.legend(loc = 2, fontsize = 10)
# 设置y标签样式
ax.set_ylabel('log excess returns',fontsize=20)
# 设置图片标题样式
ax.set_title("Strategy's performances with different parameters", fontsize=21)
plt.xlim(0, len(self.log_excess_returns[0]))
# 回测的4个主要指标,包括总回报率、最大回撤夏普率和波动
def get_eval4_bar(self, sort_by=[]):
sorted_params = self.params_df
for by in sort_by:
sorted_params = sorted_params.sort(by)
indices = sorted_params.index
fig = plt.figure(figsize=(20,7))
# 定义位置
ax1 = fig.add_subplot(221)
# 设定横轴为对应分位,纵轴为对应指标
ax1.bar(range(len(indices)),
[self.evaluations[x]['algorithm_return'] for x in indices], 0.6, label = 'Algorithm_return')
plt.xticks([x+0.3 for x in range(len(indices))], indices)
# 设置图例样式
ax1.legend(loc='best',fontsize=15)
# 设置y标签样式
ax1.set_ylabel('Algorithm_return', fontsize=15)
# 设置y标签样式
ax1.set_yticklabels([str(x*100)+'% 'for x in ax1.get_yticks()])
# 设置图片标题样式
ax1.set_title("Strategy's of Algorithm_return performances of different quantile", fontsize=15)
# x轴范围
plt.xlim(0, len(indices))
# 定义位置
ax2 = fig.add_subplot(224)
# 设定横轴为对应分位,纵轴为对应指标
ax2.bar(range(len(indices)),
[self.evaluations[x]['max_drawdown'] for x in indices], 0.6, label = 'Max_drawdown')
plt.xticks([x+0.3 for x in range(len(indices))], indices)
# 设置图例样式
ax2.legend(loc='best',fontsize=15)
# 设置y标签样式
ax2.set_ylabel('Max_drawdown', fontsize=15)
# 设置x标签样式
ax2.set_yticklabels([str(x*100)+'% 'for x in ax2.get_yticks()])
# 设置图片标题样式
ax2.set_title("Strategy's of Max_drawdown performances of different quantile", fontsize=15)
# x轴范围
plt.xlim(0, len(indices))
# 定义位置
ax3 = fig.add_subplot(223)
# 设定横轴为对应分位,纵轴为对应指标
ax3.bar(range(len(indices)),
[self.evaluations[x]['sharpe'] for x in indices], 0.6, label = 'Sharpe')
plt.xticks([x+0.3 for x in range(len(indices))], indices)
# 设置图例样式
ax3.legend(loc='best',fontsize=15)
# 设置y标签样式
ax3.set_ylabel('Sharpe', fontsize=15)
# 设置x标签样式
ax3.set_yticklabels([str(x*100)+'% 'for x in ax3.get_yticks()])
# 设置图片标题样式
ax3.set_title("Strategy's of Sharpe performances of different quantile", fontsize=15)
# x轴范围
plt.xlim(0, len(indices))
# 定义位置
ax4 = fig.add_subplot(222)
# 设定横轴为对应分位,纵轴为对应指标
ax4.bar(range(len(indices)),
[self.evaluations[x]['algorithm_volatility'] for x in indices], 0.6, label = 'Algorithm_volatility')
plt.xticks([x+0.3 for x in range(len(indices))], indices)
# 设置图例样式
ax4.legend(loc='best',fontsize=15)
# 设置y标签样式
ax4.set_ylabel('Algorithm_volatility', fontsize=15)
# 设置x标签样式
ax4.set_yticklabels([str(x*100)+'% 'for x in ax4.get_yticks()])
# 设置图片标题样式
ax4.set_title("Strategy's of Algorithm_volatility performances of different quantile", fontsize=15)
# x轴范围
plt.xlim(0, len(indices))
#14 年化回报和最大回撤,正负双色表示
def get_eval(self, sort_by=[]):
sorted_params = self.params_df
for by in sort_by:
sorted_params = sorted_params.sort(by)
indices = sorted_params.index
# 大小
fig = plt.figure(figsize = (20, 8))
# 图1位置
ax = fig.add_subplot(111)
# 生成图超额收益率的最大回撤
ax.bar([x+0.3 for x in range(len(indices))],
[-self.evaluations[x]['max_drawdown'] for x in indices], color = '#32CD32',
width = 0.6, label = 'Max_drawdown', zorder=10)
# 图年化超额收益
ax.bar([x for x in range(len(indices))],
[self.evaluations[x]['annual_algo_return'] for x in indices], color = 'r',
width = 0.6, label = 'Annual_return')
plt.xticks([x+0.3 for x in range(len(indices))], indices)
# 设置图例样式
ax.legend(loc='best',fontsize=15)
# 基准线
plt.plot([0, len(indices)], [0, 0], c='k',
linestyle='--', label='zero')
# 设置图例样式
ax.legend(loc='best',fontsize=15)
# 设置y标签样式
ax.set_ylabel('Max_drawdown', fontsize=15)
# 设置x标签样式
ax.set_yticklabels([str(x*100)+'% 'for x in ax.get_yticks()])
# 设置图片标题样式
ax.set_title("Strategy's performances of different quantile", fontsize=15)
# 设定x轴长度
plt.xlim(0, len(indices))
#14 超额收益的年化回报和最大回撤
# 加入新的benchmark后超额收益和
def get_excess_eval(self, sort_by=[]):
sorted_params = self.params_df
for by in sort_by:
sorted_params = sorted_params.sort(by)
indices = sorted_params.index
# 大小
fig = plt.figure(figsize = (20, 8))
# 图1位置
ax = fig.add_subplot(111)
# 生成图超额收益率的最大回撤
ax.bar([x+0.3 for x in range(len(indices))],
[-self.excess_max_drawdown[x] for x in indices], color = '#32CD32',
width = 0.6, label = 'Excess_max_drawdown')
# 图年化超额收益
ax.bar([x for x in range(len(indices))],
[self.excess_annual_return[x] for x in indices], color = 'r',
width = 0.6, label = 'Excess_annual_return')
plt.xticks([x+0.3 for x in range(len(indices))], indices)
# 设置图例样式
ax.legend(loc='best',fontsize=15)
# 基准线
plt.plot([0, len(indices)], [0, 0], c='k',
linestyle='--', label='zero')
# 设置图例样式
ax.legend(loc='best',fontsize=15)
# 设置y标签样式
ax.set_ylabel('Max_drawdown', fontsize=15)
# 设置x标签样式
ax.set_yticklabels([str(x*100)+'% 'for x in ax.get_yticks()])
# 设置图片标题样式
ax.set_title("Strategy's performances of different quantile", fontsize=15)
# 设定x轴长度
plt.xlim(0, len(indices))
#2 设定回测策略 id
# 注意!注意!注意!这里的id是在 我的策略里面的编译运行的algorithmId,在浏览器地址里面复制一下
pa = parameter_analysis('5473a8b9e878d36100307a7d1c0405ee')
#3 运行回测
pa.get_backtest_data(file_name = 'results1.pkl',
running_max = 10,
benchmark_id = None,
start_date = '2008-12-05',
end_date = '2018-12-05',
frequency = 'day',
initial_cash = '100000000',
param_names = ['tech'],
param_values = [['None','MA','MA1','EMA','EMA1','MACD','KDJ','CCI','RSI','BOLL','BIAS','TRIX','BBI','PSY']]
)
【已完成|运行中|待运行】: [0|0|14]. [0|10|4]. [0|10|4]. [8|2|4]. [已用0.031时,尚余0.012时,请不要关闭浏览器]. [10|4|0]. [10|4|0]. 【回测完成】总用时:206秒(即0.06小时)。
#4 数据读取
pa.read_backtest_data('results1.pkl')
#5 查看回测参数的df
pa.params_df
tech | |
---|---|
0 | None |
1 | MA |
2 | MA1 |
3 | EMA |
4 | EMA1 |
5 | MACD |
6 | KDJ |
7 | CCI |
8 | RSI |
9 | BOLL |
10 | BIAS |
11 | TRIX |
12 | BBI |
13 | PSY |
#6 查看回测结果指标
df = pa.evaluations_df
df
tech | __version | algorithm_return | algorithm_volatility | alpha | annual_algo_return | annual_bm_return | avg_position_days | avg_trade_return | benchmark_return | ... | max_drawdown_period | max_leverage | period_label | profit_loss_ratio | sharpe | sortino | trading_days | treasury_return | win_count | win_ratio | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | None | 101 | 0.649806 | 0.246126 | 0.000651047 | 0.0527908 | 0.052146 | 2433 | 0 | 0.639999 | ... | [2015-06-08, 2016-01-28] | 0 | 2018-12 | 0 | 0.0519684 | 0.0660195 | 2433 | 0.400219 | 0 | 0 |
1 | MA | 101 | 1.16138 | 0.158064 | 0.0374493 | 0.0824177 | 0.052146 | 1297 | 0.00877665 | 0.639999 | ... | [2015-06-08, 2018-12-05] | 0 | 2018-12 | 1.52665 | 0.268359 | 0.351814 | 2433 | 0.400219 | 37 | 0.308333 |
2 | MA1 | 101 | 0.362528 | 0.168506 | -0.0133998 | 0.0322966 | 0.052146 | 1307 | 0.00797548 | 0.639999 | ... | [2015-06-08, 2018-11-26] | 0 | 2018-12 | 1.17302 | -0.0457156 | -0.0566109 | 2433 | 0.400219 | 30 | 0.405405 |
3 | EMA | 101 | 1.07912 | 0.157455 | 0.0331647 | 0.0781108 | 0.052146 | 1305 | 0.00859248 | 0.639999 | ... | [2009-08-03, 2010-03-25] | 0 | 2018-12 | 1.62981 | 0.242043 | 0.317869 | 2433 | 0.400219 | 34 | 0.285714 |
4 | EMA1 | 101 | 0.848388 | 0.167936 | 0.0194674 | 0.0651579 | 0.052146 | 1285 | 0.0272402 | 0.639999 | ... | [2009-08-03, 2014-07-10] | 0 | 2018-12 | 1.59803 | 0.149806 | 0.189869 | 2433 | 0.400219 | 10 | 0.25641 |
5 | MACD | 101 | -0.248712 | 0.186899 | -0.075951 | -0.0289566 | 0.052146 | 1157 | -0.000632834 | 0.639999 | ... | [2009-08-03, 2018-08-06] | 0 | 2018-12 | 0.90209 | -0.368951 | -0.404536 | 2433 | 0.400219 | 72 | 0.679245 |
6 | KDJ | 101 | 1.19036 | 0.187656 | 0.0368768 | 0.0839002 | 0.052146 | 1176 | 0.00491715 | 0.639999 | ... | [2015-06-03, 2015-08-26] | 0 | 2018-12 | 1.3062 | 0.233939 | 0.297756 | 2433 | 0.400219 | 161 | 0.715556 |
7 | CCI | 101 | 0.297372 | 0.165 | -0.0183251 | 0.027112 | 0.052146 | 1296 | 0.00630609 | 0.639999 | ... | [2015-06-08, 2018-12-05] | 0 | 2018-12 | 1.17069 | -0.078109 | -0.09669 | 2433 | 0.400219 | 32 | 0.405063 |
8 | RSI | 101 | 1.03938 | 0.163683 | 0.0305914 | 0.0759747 | 0.052146 | 1247 | 0.0447027 | 0.639999 | ... | [2010-11-08, 2014-04-29] | 0 | 2018-12 | 1.87224 | 0.219782 | 0.284327 | 2433 | 0.400219 | 9 | 0.346154 |
9 | BOLL | 101 | 1.10888 | 0.125783 | 0.0364571 | 0.0796862 | 0.052146 | 790 | 0.0216967 | 0.639999 | ... | [2015-06-08, 2016-11-02] | 0 | 2018-12 | 2.20369 | 0.315514 | 0.429048 | 2433 | 0.400219 | 19 | 0.452381 |
10 | BIAS | 101 | 1.16048 | 0.169097 | 0.0366637 | 0.0823712 | 0.052146 | 1258 | 0.016247 | 0.639999 | ... | [2015-06-08, 2015-09-15] | 0 | 2018-12 | 1.43307 | 0.250573 | 0.319445 | 2433 | 0.400219 | 30 | 0.454545 |
11 | TRIX | 101 | 1.16048 | 0.169097 | 0.0366637 | 0.0823712 | 0.052146 | 1258 | 0.016247 | 0.639999 | ... | [2015-06-08, 2015-09-15] | 0 | 2018-12 | 1.43307 | 0.250573 | 0.319445 | 2433 | 0.400219 | 30 | 0.454545 |
12 | BBI | 101 | 0.858419 | 0.155386 | 0.0208905 | 0.0657505 | 0.052146 | 1278 | 0.00460358 | 0.639999 | ... | [2015-05-26, 2018-12-05] | 0 | 2018-12 | 1.32596 | 0.165719 | 0.221382 | 2433 | 0.400219 | 69 | 0.334951 |
13 | PSY | 101 | 0.335471 | 0.164411 | -0.015234 | 0.0301712 | 0.052146 | 1045 | 0.011718 | 0.639999 | ... | [2010-03-03, 2012-01-05] | 0 | 2018-12 | 1.4024 | -0.0597818 | -0.0815307 | 2433 | 0.400219 | 18 | 0.545455 |
14 rows × 27 columns
#7 回报率折线图
pa.plot_returns()
#8 超额收益率图
pa.plot_excess_returns()
#指标回测收益列表
df.index = df['tech'].values
del df['tech']
df = df[['algorithm_return','alpha','sharpe','win_ratio','max_drawdown_period']]
df.sort_values('algorithm_return',ascending=0)
algorithm_return | alpha | sharpe | win_ratio | max_drawdown_period | |
---|---|---|---|---|---|
KDJ | 1.19036 | 0.0368768 | 0.233939 | 0.715556 | [2015-06-03, 2015-08-26] |
MA | 1.16138 | 0.0374493 | 0.268359 | 0.308333 | [2015-06-08, 2018-12-05] |
BIAS | 1.16048 | 0.0366637 | 0.250573 | 0.454545 | [2015-06-08, 2015-09-15] |
TRIX | 1.16048 | 0.0366637 | 0.250573 | 0.454545 | [2015-06-08, 2015-09-15] |
BOLL | 1.10888 | 0.0364571 | 0.315514 | 0.452381 | [2015-06-08, 2016-11-02] |
EMA | 1.07912 | 0.0331647 | 0.242043 | 0.285714 | [2009-08-03, 2010-03-25] |
RSI | 1.03938 | 0.0305914 | 0.219782 | 0.346154 | [2010-11-08, 2014-04-29] |
BBI | 0.858419 | 0.0208905 | 0.165719 | 0.334951 | [2015-05-26, 2018-12-05] |
EMA1 | 0.848388 | 0.0194674 | 0.149806 | 0.25641 | [2009-08-03, 2014-07-10] |
None | 0.649806 | 0.000651047 | 0.0519684 | 0 | [2015-06-08, 2016-01-28] |
MA1 | 0.362528 | -0.0133998 | -0.0457156 | 0.405405 | [2015-06-08, 2018-11-26] |
PSY | 0.335471 | -0.015234 | -0.0597818 | 0.545455 | [2010-03-03, 2012-01-05] |
CCI | 0.297372 | -0.0183251 | -0.078109 | 0.405063 | [2015-06-08, 2018-12-05] |
MACD | -0.248712 | -0.075951 | -0.368951 | 0.679245 | [2009-08-03, 2018-08-06] |
#11 回测的4个主要指标,包括总回报率、最大回撤夏普率和波动
# get_eval4_bar(self, sort_by=[])
pa.get_eval4_bar()
#2 设定回测策略 id
# 注意!注意!注意!这里的id是在 我的策略里面的编译运行的algorithmId,在浏览器地址里面复制一下
pa = parameter_analysis('5473a8b9e878d36100307a7d1c0405ee')
#3 运行回测
pa.get_backtest_data(file_name = 'results1.pkl',
running_max = 10,
benchmark_id = None,
start_date = '2008-12-05',
end_date = '2018-12-05',
frequency = 'day',
initial_cash = '100000000',
param_names = ['stock','tech'],
param_values = [['000016.XSHG'],['None','MA','MA1','EMA','EMA1','MACD','KDJ','CCI','RSI','BOLL','BIAS','TRIX','BBI','PSY']]
)
【已完成|运行中|待运行】: [0|0|14]. [0|10|4]. [0|10|4]. [1|9|4]. [1|10|3]. [5|6|3]. [11|3|0]. [11|3|0]. 【回测完成】总用时:287秒(即0.08小时)。
#数据读取
pa.read_backtest_data('results1.pkl')
#查看回测结果指标
df1 = pa.evaluations_df
df1
stock | tech | __version | algorithm_return | algorithm_volatility | alpha | annual_algo_return | annual_bm_return | avg_position_days | avg_trade_return | ... | max_drawdown_period | max_leverage | period_label | profit_loss_ratio | sharpe | sortino | trading_days | treasury_return | win_count | win_ratio | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 000016.XSHG | None | 101 | 0.642979 | 0.250999 | 0.000786761 | 0.0523422 | 0.0515543 | 2433 | 0 | ... | [2009-08-03, 2014-03-20] | 0 | 2018-12 | 0 | 0.0491725 | 0.0656579 | 2433 | 0.400219 | 0 | 0 |
1 | 000016.XSHG | MA | 101 | 0.739057 | 0.164764 | 0.0135366 | 0.0585056 | 0.0515543 | 1225 | 0.00678877 | ... | [2009-08-03, 2010-09-09] | 0 | 2018-12 | 1.38853 | 0.112316 | 0.156047 | 2433 | 0.400219 | 31 | 0.236641 |
2 | 000016.XSHG | MA1 | 101 | 0.08402 | 0.16995 | -0.0369882 | 0.00832426 | 0.0515543 | 1203 | 0.00501458 | ... | [2009-08-03, 2014-11-06] | 0 | 2018-12 | 1.07069 | -0.186382 | -0.228336 | 2433 | 0.400219 | 26 | 0.351351 |
3 | 000016.XSHG | EMA | 101 | 0.408567 | 0.16615 | -0.00916891 | 0.0358275 | 0.0515543 | 1242 | 0.00482895 | ... | [2009-08-03, 2014-07-10] | 0 | 2018-12 | 1.28927 | -0.0251127 | -0.0346964 | 2433 | 0.400219 | 35 | 0.263158 |
4 | 000016.XSHG | EMA1 | 101 | 0.381043 | 0.175459 | -0.011881 | 0.0337293 | 0.0515543 | 1273 | 0.0131946 | ... | [2009-08-03, 2014-07-10] | 0 | 2018-12 | 1.33819 | -0.0357391 | -0.0477358 | 2433 | 0.400219 | 12 | 0.272727 |
5 | 000016.XSHG | MACD | 101 | -0.0861159 | 0.18631 | -0.0555538 | -0.00921046 | 0.0515543 | 1185 | 0.00108833 | ... | [2009-08-03, 2014-03-10] | 0 | 2018-12 | 0.981093 | -0.264132 | -0.266894 | 2433 | 0.400219 | 72 | 0.679245 |
6 | 000016.XSHG | KDJ | 101 | 0.609182 | 0.185087 | 0.00385646 | 0.0500971 | 0.0515543 | 1186 | 0.00339378 | ... | [2015-06-05, 2015-08-25] | 0 | 2018-12 | 1.22866 | 0.0545535 | 0.0700506 | 2433 | 0.400219 | 154 | 0.681416 |
7 | 000016.XSHG | CCI | 101 | 0.434146 | 0.171199 | -0.00763085 | 0.0377448 | 0.0515543 | 1240 | 0.00808786 | ... | [2009-11-18, 2014-07-11] | 0 | 2018-12 | 1.22096 | -0.0131728 | -0.0174062 | 2433 | 0.400219 | 30 | 0.375 |
8 | 000016.XSHG | RSI | 101 | 0.757592 | 0.168756 | 0.0144082 | 0.0596593 | 0.0515543 | 1259 | 0.0369311 | ... | [2009-08-03, 2014-07-11] | 0 | 2018-12 | 1.69349 | 0.116495 | 0.160392 | 2433 | 0.400219 | 7 | 0.259259 |
9 | 000016.XSHG | BOLL | 101 | 0.767735 | 0.135782 | 0.0168802 | 0.060286 | 0.0515543 | 783 | 0.0172371 | ... | [2015-04-27, 2018-10-11] | 0 | 2018-12 | 1.54801 | 0.149402 | 0.215418 | 2433 | 0.400219 | 16 | 0.347826 |
10 | 000016.XSHG | BIAS | 101 | 0.640877 | 0.169366 | 0.00689045 | 0.0522038 | 0.0515543 | 1233 | 0.0106898 | ... | [2015-06-08, 2016-01-05] | 0 | 2018-12 | 1.25445 | 0.0720561 | 0.0968489 | 2433 | 0.400219 | 31 | 0.418919 |
11 | 000016.XSHG | TRIX | 101 | 0.640877 | 0.169366 | 0.00689045 | 0.0522038 | 0.0515543 | 1233 | 0.0106898 | ... | [2015-06-08, 2016-01-05] | 0 | 2018-12 | 1.25445 | 0.0720561 | 0.0968489 | 2433 | 0.400219 | 31 | 0.418919 |
12 | 000016.XSHG | BBI | 101 | 0.534281 | 0.164124 | 6.30206e-05 | 0.0449667 | 0.0515543 | 1209 | 0.00368511 | ... | [2009-10-26, 2012-09-18] | 0 | 2018-12 | 1.23422 | 0.0302619 | 0.042997 | 2433 | 0.400219 | 66 | 0.30137 |
13 | 000016.XSHG | PSY | 101 | -0.0858294 | 0.182729 | -0.055268 | -0.00917855 | 0.0515543 | 1261 | 0.00110837 | ... | [2009-05-13, 2016-01-28] | 0 | 2018-12 | 0.943645 | -0.269134 | -0.333688 | 2433 | 0.400219 | 19 | 0.558824 |
14 rows × 28 columns
#7 回报率折线图
pa.plot_returns()