import tushare as ts
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pyecharts.charts import *
from pyecharts import options as opts
from pyecharts.globals import ThemeType
pd.set_option('expand_frame_repr', False)
pd.set_option('display.max_rows',None)
token = 'd6e7a61d3655208dd2cf86180344ae804df9661be085a7c3233f957c'
pro = ts.pro_api(token)
df_price = pro.daily(ts_code='600519.SH', start_date='20110101', end_date='20211008',
fields='ts_code,trade_date,close,open,high,low')
df_price.index = pd.to_datetime(df_price.trade_date)
df_price['year'] = df_price.index.year
df_price = df_price.sort_index()
# print(df_price.iloc[0:5,:])
# print(df_price)
# exit()
# 列名flag 索引为10
# 列名position 索引为9
# 列名close 索引为5
def Strategy(data_price, window_short=5, window_long=10, loss_ratio=0.20):
# df_price:价格数据;
# window_short:短均线周期,默认为5;
# window_long:长均线周期,默认为10;
# lossratio:止损率,默认为1%,即开仓后下跌超过1%止损。
##2.1绘制K线和均线
data_price = data_price.copy()
data_price.index = data_price.index.strftime('%Y%m%d')
data_price['sma'] = data_price.close.rolling(window_short).mean()
data_price['lma'] = data_price.close.rolling(window_long).mean()
data_price['position'] = 0 # 记录仓位
data_price['flag'] = 0 # 记录买卖
kline = Kline(init_opts=opts.InitOpts(width='1200px', height='600px', theme=ThemeType.DARK))
kline.add_xaxis(data_price.index.tolist())
y = list(data_price.loc[:, ['open', 'close', 'low', 'high']].round(2).values) # 现在里面的单个元素是数组
y = [i.tolist() for i in y] # 里面的单个数组也必须转换成list
kline.add_yaxis('K线', y)
# kline.extend_axis(yaxis=opts.AxisOpts( axislabel_opts=opts.LabelOpts(formatter="{value}") ))
kline.set_series_opts(label_opts=opts.LabelOpts(is_show=False)) # 是否显示数据标签
kline.set_global_opts(
xaxis_opts=opts.AxisOpts(is_scale=True, axislabel_opts=opts.LabelOpts(rotate=60)),
yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value}")),
datazoom_opts=[opts.DataZoomOpts(type_='inside')], # 内部滑动
title_opts=opts.TitleOpts(title="贵州茅台(600519.SH)K线及均线", pos_left='45%'), # 题目位置
legend_opts=opts.LegendOpts(pos_right="35%", pos_top="5%"), # 图例位置
tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="cross") # 添加趋势线
)
line = Line()
line.add_xaxis(data_price.index.tolist())
line.add_yaxis('MA5', data_price.sma.round(2).tolist(), is_smooth=True)
line.add_yaxis('MA10', data_price.lma.round(2).tolist(), is_smooth=True)
line.set_series_opts(label_opts=opts.LabelOpts(is_show=False)) # 是否显示数据标签
line.set_global_opts(
datazoom_opts=[opts.DataZoomOpts(type_='inside')], # 内部滑动
legend_opts=opts.LegendOpts(pos_right="20%", pos_top="5%"), # 图例位置
tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="cross") # 添加趋势线
)
kline.overlap(line)
kline.render("16.1 贵州茅台(600519.SH)K线及均线.html")
##2.2均线策略的交易记录
Buy = [] # 保存买入记录
Sell = [] # 保存卖出记录
price_in = 1 # 初始买入价设置为1
for i in range(max(1, window_long), data_price.shape[0] - 1):
# 情形一:当前无仓位且短均线上穿长均线(金叉),则买入股票
if (data_price['position'][i] == 0) and (data_price['sma'][i - 1] < data_price['lma'][i - 1]) and (
data_price['sma'][i] > data_price['lma'][i]):
data_price.iloc[i, 10] = 1
data_price.iloc[i + 1, 9] = 1
date_in = data_price.index[i]
price_in = data_price.iloc[i, 5]
Buy.append([date_in, price_in, '金叉买入'])
# 情形二:当前持仓且下跌超过止损率,则平仓止损
elif (data_price['position'][i] == 1) & (1 - data_price['close'][i] / price_in > loss_ratio):
data_price.iloc[i, 10] = -1
data_price.iloc[i + 1, 9] = 0
date_out = data_price.index[i]
price_out = data_price.iloc[i, 5]
Sell.append([date_out, price_out, '止损平仓'])
# 情形三:当前持仓且短均线下穿长均线(死叉),则卖出股票
elif (data_price['position'][i] == 1) & (data_price['sma'][i - 1] > data_price['lma'][i - 1]) & (
data_price['sma'][i] < data_price['lma'][i]):
data_price.iloc[i, 10] = -1
data_price.iloc[i + 1, 9] = 0
date_out = data_price.index[i]
price_out = data_price.iloc[i, 5]
Sell.append([date_out, price_out, '死叉卖出'])
# 其他情形:保持之前的仓位不变
else:
data_price.iloc[i + 1, 9] = data_price.iloc[i, 9]
p1 = pd.DataFrame(Buy, columns=['买入日期', '买入价格', '备注'])
p2 = pd.DataFrame(Sell, columns=['卖出日期', '卖出价格', '备注'])
transactions = pd.concat([p1, p2], axis=1) # 交易记录
data_price = data_price.iloc[window_long:, :]
data_price['ret'] = data_price.close.pct_change(1).fillna(0)
data_price['nav'] = (1 + data_price.ret * data_price.position).cumprod()
data_price['benchmark'] = data_price.close / data_price.close[0]
##2.3返回交易记录和全过程数据
return transactions, data_price
trans, data = Strategy(df_price, window_short=25, window_long=50, loss_ratio=0.10)
print('交易记录:\n', trans)
print('结果展示:\n', data)
def performance(transactions, strategy):
##3.1策略评价指标
# 年化收益率
N = 250
rety = strategy.nav[strategy.shape[0] - 1] ** (N / strategy.shape[0]) - 1
# 夏普比
Sharp = (strategy.ret * strategy.position).mean() / (strategy.ret * strategy.position).std() * np.sqrt(N)
# 胜率
VictoryRatio = ((transactions['卖出价格'] - transactions['买入价格']) > 0).mean()
# 最大回撤率
DD = 1 - strategy.nav / strategy.nav.cummax()
MDD = max(DD)
# 单次最大亏损
maxloss = min(transactions['卖出价格'] / transactions['买入价格'] - 1)
# 月均交易次数
trade_count = strategy.flag.abs().sum() / strategy.shape[0] * 20
print('------------------------------')
print('夏普比率为:', round(Sharp, 2))
print('年化收益率为:{}%'.format(round(rety * 100, 2)))
print('胜率为:{}%'.format(round(VictoryRatio * 100, 2)))
print('最大回撤率为:{}%'.format(round(MDD * 100, 2)))
print('单次最大亏损为:{}%'.format(round(-maxloss * 100, 2)))
print('月均交易次数为:{}(买卖合计)'.format(round(trade_count, 2)))
print('------------------------------')
result = {'Sharp': Sharp,
'RetYearly': rety,
'WinRate': VictoryRatio,
'MDD': MDD,
'maxlossOnce': -maxloss,
'num': round(strategy.flag.abs().sum() / strategy.shape[0], 1)}
result = pd.DataFrame.from_dict(result, orient='index').T
print(result)
##3.2策略逐年表现
nav_peryear = strategy.nav.groupby(strategy.year).last() / strategy.nav.groupby(strategy.year).first() - 1
benchmark_peryear = strategy.benchmark.groupby(strategy.year).last() / strategy.benchmark.groupby(
strategy.year).first() - 1
excess_ret = nav_peryear - benchmark_peryear
result_peryear = pd.concat([nav_peryear, benchmark_peryear, excess_ret], axis=1)
result_peryear.columns = ['strategy_ret', 'bench_ret', 'excess_ret']
result_peryear = result_peryear.T
print('------------------------------')
print(result_peryear)
print('------------------------------')
##3.3策略净值可视化
line1 = Line(init_opts=opts.InitOpts(width='1200px', height='600px', theme=ThemeType.DARK))
line1.add_xaxis(strategy.index.tolist())
line1.add_yaxis('策略净值', strategy.nav.round(2).to_list(), yaxis_index=0, is_smooth=True)
line1.add_yaxis('基准净值', strategy.benchmark.round(2).to_list(), yaxis_index=0, is_smooth=True)
line1.extend_axis(yaxis=opts.AxisOpts(min_=0.8, axislabel_opts=opts.LabelOpts(formatter="{value}")))
line1.set_series_opts(label_opts=opts.LabelOpts(is_show=True)) # 是否显示数据标签
line1.set_global_opts(
xaxis_opts=opts.AxisOpts(is_scale=True, axislabel_opts=opts.LabelOpts(rotate=60)),
yaxis_opts=opts.AxisOpts(min_=0.75, axislabel_opts=opts.LabelOpts(formatter="{value}")),
datazoom_opts=[opts.DataZoomOpts(type_='inside')], # 内部滑动
title_opts=opts.TitleOpts(title="双均线择时策略回测", pos_left='45%'), # 题目位置
legend_opts=opts.LegendOpts(pos_right="35%", pos_top="5%"), # 图例位置
tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="cross") # 添加趋势线
)
line2 = Line()
line2.add_xaxis(strategy.index.tolist())
line2.add_yaxis('净值之比', (strategy.nav / strategy.benchmark).round(2).tolist(), yaxis_index=1, is_smooth=True)
line2.set_global_opts(
datazoom_opts=[opts.DataZoomOpts(type_='inside')], # 内部滑动
legend_opts=opts.LegendOpts(pos_right="20%", pos_top="5%"), # 图例位置
tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="cross") # 添加趋势线
)
line1.overlap(line2)
line1.render("16.2 双均线择时策略回测.html")
return result, result_peryear
performance(trans, data)
标签:index,pyecharts,记录,data,price,strategy,print,绘制,opts From: https://www.cnblogs.com/yuyanc/p/17718708.html