1.3计算均线突破策略的sharpe比率, 最大回撤

前言: 采用新的策略, 简单均线突破策略, 以5日均线和10日均线判断标准, 5日均线向上突破10日均线的时候买入, 5日均线向下突破10日均线的时候卖出.

代码如下:

import numpy as np
import pandas as pd
import datetime
from matplotlib import pyplot as plt

#读取股票数据, 格式为Stkcd,Trddt,Opnprc,Hiprc,Loprc,Clsprc,Dretwd,Adjprcwd,一共10784个数据
data = pd.read_csv("TRD_Dalyr.csv")
#将时间转换为标准格式xx-xx-xx
data.Trddt = pd.to_datetime(data.Trddt, format = "%Y%m%d")
#print(data)

cls = data[data['Stkcd'] == 1]['Clsprc']
adjcls = data[data['Stkcd'] == 1]['Adjprcwd']
adjcls = adjcls / (adjcls.iloc[-1] / cls.iloc[-1])

#plt.plot(cls)
#plt.plot(adjcls)
#plt.show()

stk = data['Stkcd']
#剔除重复的代码
stk = stk.drop_duplicates()
for row in stk:
    print(row)

#cls代表取股票代码为000001(其实是stk的第一行)的股票交易日期和收盘价
cls = data[data['Stkcd'] == stk.iloc[0]][['Trddt', 'Clsprc']]
#构建一个pandas数据结构DataFrame,将交易日期作为行、股票代码作为列
cls2 = pd.DataFrame(cls['Clsprc'].tolist(), index = cls['Trddt'].tolist(), columns = [stk.iloc[0]])
print(cls2)

#如法炮制,取股票代码stk第二行的代码对应的数据
cls3 = data[data['Stkcd'] == stk.iloc[1]][['Trddt', 'Clsprc']]
cls4 = pd.DataFrame(cls3['Clsprc'].tolist(), index = cls3['Trddt'].tolist(), columns = [stk.iloc[1]])
print(cls4)

#将两个合并, axis = 1表示列对齐。
df = pd.concat([cls2, cls4], axis = 1)
print(df)

#查找空值,并且填补空值, np.where返回的是一个list,其中第一个元素为空值所处的行号
nan_fill = np.where(np.isnan(df))[0][0]
print(nan_fill)
print(df.iloc[nan_fill])
print(df.iloc[nan_fill - 2: nan_fill + 1])


#用pad的方式填补空值,即取空值后的第一个数字,填补以前的空值
df = df.fillna(method = 'pad')
print(df.iloc[nan_fill - 2: nan_fill + 1])

df.plot()
#plt.show()
#重新拷贝一份df, 可以用bool变量赋予参数deep, 默认为True, 即temp_df改变不影响df的值, 如果是false则会影响df的值
temp_df = df.copy()
params = [5, 10, 20]
for p in params:
    #以window长度为p, 计算移动平均值, 也就是计算均线
    temp_df["ma" + str(p)] = temp_df[stk.iloc[0]].rolling(p).mean()
#截取2017年9月1日之后的数据
temp_df = temp_df[temp_df.index >= np.datetime64(datetime.date(2017, 9, 1))]
figure, axis = plt.subplots()
param_colors = [(1, 0.7, 0.2), (0, 0.7, 0.9), (0.9, 0.5, 0.9)]

for (i, p) in enumerate(params):
    temp_df[['ma' + str(p)]].plot(kind = 'line', ax = axis, color = param_colors[i], use_index = True)
#plt.show()

def back_test(p, stk):
    result = pd.DataFrame(index = [p.index])
    result['Position'] = 0
    result['Action'] = np.nan
    result['Profit'] = 0
    result['Accumulate_profit'] = 0
    result['Net_value'] = 0
    result['Daily_return'] = 0
    performance = {
        'Count': 0,
        'Win_rate': 0,
        'Return': 0,
        'Sharpe': 0,
        #最大回撤
        'Max_drawdown': 0
            }
    #len(p)指的是DataFrame的行数, 引用DataFrame的列标号, 可以用p.ma5, 也可以用p["ma5"]
    row_index = p.index.strftime("%Y-%m-%d")
    #print("begin")
    #print(result)
    #print(p)
    #print(len(row_index))
    for index in range(len(p)):
        if index == 0:
            continue
        #从index = 1开始
        #print(len(p), index,  result.loc[row_index[index - 1], "Position"])
        result.loc[p.index[index], "Position"] = result.loc[row_index[index - 1], "Position"]
        ma5 = p.ma5[index]
        ma10 = p.ma10[index]
        prema5 = p.ma5[index - 1]
        prema10 = p.ma10[index - 1]
        #如果index = p的长度 - 1, 那么index就是最后一个元素的下标
        if index == len(p) - 1:
            if result['Position'][index] == 1:
                result["Position"][index] = 0
                result['Action'][index] = 1
        else:
            if result['Position'][index] == 0:
                #判断5日均线是否上穿10日均线, 如果是, 那么position = 1, action = 1
                if ma5 > ma10 and prema5 < ma10:
                    result['Position'][index] = 1
                    result['Action'][index] = 1
            else:
                #position != 0, 说明已经持仓, 那么只有在5日均线下穿10日均线的时候, 才会卖出
                if ma5 < ma10 and prema5 > ma10:
                    result.loc[row_index[index], "Position"] = 0
                    result.loc[row_index[index], "Action"] = -1
    #至此,已经得出了该投资策略的买入、卖出信号点,可以依据这个1、-1、0的变化,确定是否买卖
    #p[stk][1 : -1].values表示从stk = 1, 即000001上证综指下标为1的项开始,一直到倒数第二项为止(-1)
    print(result)
    print(p[stk][1:-1].values)
    print(p[stk][0:-2].values)
    print()
    c = list(map(lambda x: x[0] - x[1], zip(p[stk][1:-1].values,p[stk][0:-2].values)))
    print(c)
    print(np.array(c))
    print(result['Position'][0:-2].values)
    c = np.multiply(np.array(c), np.array(result['Position'][0: -2].values)).tolist()
    print(c)
    result.loc[1 : -1, 'Profit'] = c
    result["Accumulate_profit"] = result["Profit"].values.cumsum()
    result["Net_value"] = (result["Accumulate_profit"].values + p[stk][0]) / p[stk][0]
    result.loc[1 : -1, 'Daily_return'] = (result['Net_value'][1 : -1].values - result["Net_value"][0 : -2].values) / result['Net_value'][1 : -1].values
    performance['Count'] = (result['Action'] == 1).sum()
    performance['Return'] = sharpe_ratio(result['Daily_return'].values)
    performance['Max_drawdown'] = Max_drawdown(result['Net_value'].values)
    return result, performance


def sharpe_ratio(return_list):
    #计算sharpe比率
    average_return = np.mean(return_list)
    annual_return = average_return * 252
    return_stdev = np.std(return_list)
    annual_volume = return_stdev * np.sqrt(252)
    #默认一共有252个工作日, 无风险利率为0.02
    sharpe_ratio = (annual_return - 0.02) / annual_volume
    return sharpe_ratio


def Max_drawdown(value_list):
    print(value_list)
    #计算最大回撤
    i = np.argmax((np.maximum.accumulate(value_list) - value_list) / np.maximum.accumulate(value_list))  # 结束位置
    #开始位置
    j = np.argmax(value_list[:i])
    return(value_list[j] - value_list[i]) / (value_list[j])

print(back_test(temp_df, stk.iloc[0]))
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值