代码拉取完成,页面将自动刷新
同步操作将从 Dylan Yang/股票量化回测系统 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
import tushare as ts
import pandas as pd
import numpy as np
import math
class ResultAnalysis:
initial_money = 100000 # 等待数据传入
start_date = '2010年1月4日'
end_date = '2019年12月31日'
def __init__(self, initial=100000, start_date='2010-01-04', end_date='2019-12-31'):
self.initial_money = initial
self.start_date = start_date # 可能需要将日期转换为统一格式
self.end_date = end_date
def get_initial_money(self):
return self.initial_money
def cal_gain_abs(self, return_list, charge=False):
'''
根据每日收益计算最后的总收益
也可用于计算基准收益
:param return_list:每日收益
:return: 总收益
'''
final_money = return_list[-1]
if charge:
# 如果卖出,就要扣手续费
selling_charge = final_money * 3e-4
final_money -= selling_charge
gain = final_money - self.initial_money
return gain
def cal_gain_ratio(self, return_list):
'''
根据每日收益计算最后的总收益率
也可用于计算基准收益率
:param return_list:每日收益
:return: 总收益率
'''
return self.cal_gain_abs(return_list) / self.initial_money
def cal_return_list_SSEC(self, charge=False):
'''
计算买入上证指数的每日资产,可考虑手续费(charge=Ture)
:return: days:日期列表,return_list:每日收益列表
'''
SSEC = pd.read_csv('上证指数历史数据.csv')
SSEC = SSEC[['日期', '收盘']]
SSEC = SSEC.reindex(index=SSEC.index[::-1])
SSEC = SSEC.reset_index(drop=True)
start_price = float(SSEC.loc[0, '收盘'].replace(',', ''))
end_price = float(SSEC.loc[SSEC.shape[0] - 1, '收盘'].replace(',', ''))
start_index = 0
end_index = SSEC.shape[0]
for i in range(SSEC.shape[0]):
if self.start_date <= SSEC.loc[i, '日期']: # 考虑开始和结束时间不是交易日的情况
start_price = float(SSEC.loc[i, '收盘'].replace(',', ''))
start_index = i
break
for i in range(start_index, SSEC.shape[0]):
if self.end_date >= SSEC.loc[i, '日期']: # 考虑开始和结束时间不是交易日的情况
end_price = float(SSEC.loc[i, '收盘'].replace(',', ''))
end_index = i
return_list = []
days = []
if charge:
buying_charge = self.initial_money * 3e-4
return_list.append(self.initial_money - buying_charge)
holding = (self.initial_money - buying_charge) / start_price # 持有份额
else:
return_list.append(self.initial_money)
holding = self.initial_money / start_price
days.append(SSEC.loc[start_index, '日期'])
for i in range(start_index + 1, end_index + 1):
days.append(SSEC.loc[i, '日期'])
return_list.append(float(SSEC.loc[i, '收盘'].replace(',', '')) * holding)
return days, return_list
def cal_return_list_CSI300(self, charge=False):
'''
计算买入沪深300指数的每日资产
:return: days:日期列表,return_list:每日收益列表
'''
CSI300 = pd.read_csv('沪深300指数历史数据.csv')
CSI300 = CSI300[['日期', '收盘']]
CSI300 = CSI300.reindex(index=CSI300.index[::-1])
CSI300 = CSI300.reset_index(drop=True)
# 根据需要 处理一下日期的格式
start_price = float(CSI300.loc[0, '收盘'].replace(',', ''))
end_price = float(CSI300.loc[CSI300.shape[0] - 1, '收盘'].replace(',', ''))
start_index = 0
end_index = CSI300.shape[0]
for i in range(CSI300.shape[0]):
if self.start_date <= CSI300.loc[i, '日期']: # 考虑开始和结束时间不是交易日的情况
start_price = float(CSI300.loc[i, '收盘'].replace(',', ''))
start_index = i
break
for i in range(start_index, CSI300.shape[0]):
if self.end_date >= CSI300.loc[i, '日期']: # 考虑开始和结束时间不是交易日的情况
end_price = float(CSI300.loc[i, '收盘'].replace(',', ''))
end_index = i
return_list = []
days = []
if charge:
buying_charge = self.initial_money * 3e-4
return_list.append(self.initial_money - buying_charge)
holding = (self.initial_money - buying_charge) / start_price # 持有份额
else:
return_list.append(self.initial_money)
holding = self.initial_money / start_price
days.append(CSI300.loc[start_index, '日期'])
for i in range(start_index + 1, end_index + 1):
days.append(CSI300.loc[i, '日期'])
return_list.append(float(CSI300.loc[i, '收盘'].replace(',', '')) * holding)
return days, return_list
def cal_gain_list_SSEC(self):
'''
计算买入上证指数的每日收益
:return: days:日期列表,gain_list:每日收益列表
'''
days, return_list = self.cal_return_list_SSEC()
gain_list = []
for i in range(len(return_list)):
gain_list.append(return_list[i] - self.initial_money)
return days, gain_list
def cal_gain_list_CSI300(self):
'''
计算买入沪深300指数的每日收益
:return: days:日期列表,gain_list:每日收益列表
'''
days, return_list = self.cal_return_list_CSI300()
gain_list = []
for i in range(len(return_list)):
gain_list.append(return_list[i] - self.initial_money)
return days, gain_list
def cal_MaxDrawdown(self, return_list):
'''
计算最大回撤、最大回撤率和对应的回撤持续天数
可理解为可能发生的最大亏损幅度,其值等于策略收益曲线上高点到后期最低点的回撤幅度的最大值。
return_list:是每日资金的变化曲线
np.maximum.accumulate(return_list):找到return_list中的累计最大值,例如:
d = np.array([2, 0, 3, -4, -2, 7, 9])
c = np.maximum.accumulate(d)
#c = array([2, 2, 3, 3, 3, 7, 9])
i:为最大回撤截止的时间
j:为最大回撤开始的时间
drawdown_max:最大回撤
drawdown_rate:最大回撤对应的回撤率
drawdown_tian:回撤持续天数
'''
i = np.argmax((np.maximum.accumulate(return_list) - return_list))
if i == 0:
return 0
j = np.argmax(return_list[:i]) # 开始位置
drawdown_max = return_list[j] - return_list[i]
drawdown_rate = (return_list[j] - return_list[i]) / return_list[j]
drawdown_tian = i - j
return drawdown_rate, drawdown_max, drawdown_tian, j, i
def beat_benchmark_ratio(self, return_list):
'''
计算击败基准比率(日胜率)
(当日策略收益跑赢当日基准收益的天数/总交易日天数)*100%
统计日收益率打败基准收益的概率。数值越大越好,表示策略收益能力越强。
:param return_list:
:return: 击败基准比率(日胜率)
'''
return_list_SSEC = self.cal_return_list_SSEC()
win_day = 0
for i in range(len(return_list)):
if return_list[i] > return_list_SSEC[i]:
win_day += 1
return win_day / len(return_list)
def annualized_rate_of_return(self, days, return_list):
'''
计算年化收益率
计算公式: (1 + 收益率) ^ (年平均交易日 / 策略执行总天数) - 1
:param days: 策略执行的总日期列表
:param return_list: 每日资金
:return: 年化收益率
'''
num_days = len(days)
trading_day_a_year = 243 # 根据计算,2010至2019年,每年平均交易日为243天
return math.pow(1 + self.cal_gain_ratio(return_list), trading_day_a_year / num_days) - 1
def cal_sharp_ratio(self, days, return_list):
'''
计算夏普比率
:param days: 策略执行的总日期列表
:param return_list: 每日资金
:return: 夏普比率
'''
E_Rp = self.annualized_rate_of_return(days, return_list) # 策略年化收益率
Rf = 4e-2 # 根据资料,可假设国债的年化收益率是 4%
num_days = len(days) # 回测时间段内的所有交易日
trading_day_a_year = 243 # 根据计算,2010至2019年,每年平均交易日为243天
diff_return = np.diff(return_list) # 每天相较于前一天的收益
gain_ratio = diff_return / return_list[:-1] # 每天相较于前一天的收益率
sum_ratio2 = 0
avg_gain_ratio = np.mean(gain_ratio)
for i in gain_ratio:
sum_ratio2 += math.pow(i - avg_gain_ratio, 2)
sigma_p = math.sqrt(sum_ratio2 * trading_day_a_year / num_days) # 每日收益率的标准差
return (E_Rp - Rf) / sigma_p
if __name__ == '__main__':
rs = ResultAnalysis(start_date='2013-04-12', end_date='2018-05-20')
days, return_list = rs.cal_return_list_SSEC()
print(len(days))
print(days)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。