欢迎光临散文网 会员登陆 & 注册

简单回测程序

2022-10-05 23:10 作者:Katsura大肚贵公子  | 我要投稿

# -*- coding: utf-8 -*-

"""

Created on Fri Apr  9 22:49:09 2021


@author: ASUS

"""


import talib

import pandas as pd

import numpy as np

import matplotlib.pyplot as plt

import tushare as ts





def shizhixuangu(riqi):

    pro = ts.pro_api()

    shuju = pro.daily_basic(ts_code='',trade_date=riqi,fields='ts_code,trade_date,pe,pe_ttm,pb,ps,total_mv,circ_mv')

                               #由于接口不同,只能在函数内部实现市值数据的提取

    lx1 = ['市值大于1000亿']

    lx2 = ['市值大于500亿']

    lx3 = ['市值大于200亿']

    qita = []

    for i in range(len(shuju)):

        shizhi = float(shuju.iloc[i]['total_mv'])

        #print(shizhi)      #经验证,可以得到市值的数据并输出

        if shizhi >10000000.0:

            lx1.append(shuju.iloc[i]['ts_code'])

        elif shizhi>=5000000 and shizhi<10000000:

            lx2.append(shuju.iloc[i]['ts_code'])

        elif shizhi>=2000000 and shizhi<5000000:

            lx3.append(shuju.iloc[i]['ts_code'])

        else:

            qita.append(shuju.iloc[i]['ts_code'])

    return lx1,lx2,lx3,qita


def pandingzhibiao(shuju):     #输出当前股票的买卖点

    '''金叉买入,但是由于指标数据是按交易日的‘散点’,所以导致‘金叉’难以与当天对应,

    所以,判断标准是‘前一天DIF<=DEA,当天DIF>=DEA’,同样,卖出标准是‘前天DIF>=DEA,

    当天DIF<=DEA’;'''

    shuju1 = shuju.reindex(index=shuju.index[::-1])    

    DIF,DEA,MACD = talib.MACD(shuju1['close'],fastperiod=12,slowperiod=26,signalperiod=9)  

    DIF[np.isnan(DIF)] = 0

    DEA[np.isnan(DEA)] = 0

    MACD[np.isnan(MACD)] = 0      

    maimai = {}

                            

    for i in range(len(shuju)):

        if i > 32:                       #因为MACD函数输出指标数据的都是比行情数据少33个数的                  

           DIF1 = DIF.iloc[i]

           DIF0 = DIF.iloc[i-1]

           DEA1 = DEA.iloc[i]

           DEA0 = DEA.iloc[i-1]

           if DIF0 <= DEA0:

               if DIF1 >= DEA1:

                   maimai.update({i:[shuju1.iloc[i]['trade_date'],shuju1.iloc[i]['close'],'买入']})  

                   #注意,要用已经倒过来的行情数据close,才对应指标

           elif DIF0 >= DEA0:

               if DIF1 <= DEA1:

                   maimai.update({i:[shuju1.iloc[i]['trade_date'],shuju1.iloc[i]['close'],'卖出']})

                   #或者可以直接用MACD来判断指标,更简单

   #买卖点将会是一个买点,接着一个卖点,接着一个买点...但是,在其他的指标判定中却不一定了,还可能是连续几个买点或卖点

   

           if i >= 19:     #循环中i是从0开始的,当i=19时表示此时是shuju中的第20个数据

              twenty = shuju1.iloc[(i-19):(i+1)]['vol'].mean()   #以切片的方法,取shuju中以当前日期开始往回的20天的成交量数据的平均值

              if shuju1.iloc[i]['vol'] >= 3*twenty:    #我们要的是比20日平均成交量还高2倍的,也就是20日成交量3倍以上的

                    maimai.update({i:[shuju1.iloc[i]['trade_date'],shuju1.iloc[i]['close'],'卖出']})

   # print(maimai)         #注意,此时的买入卖出点的价格是‘字符串’类型

    return maimai    

    

def jiaoyi(d,benjin,maimai):

    shuju1 = d.reindex(index=d.index[::-1])

    shoushu = 0

    jiaoyicishu = 0

    shouyilv = []

    zongshouyilv = []

    shouyishijian = []

    kuisun = ['亏损交易的日期']


    for shijian in maimai:

        if shoushu == 0:

            if maimai[shijian][2] == '买入' :

               mrujia = float(maimai[shijian][1])

               shoushu = benjin // (mrujia*100.0)

               shengyu = benjin % (mrujia*100.0)

               benjin = shengyu

               mairushijian = int(shuju1.iloc[shijian]['trade_date'])

            else:

                continue

        else:

            if maimai[shijian][2] == '卖出':

              mchujia = float(maimai[shijian][1])

              benjin = benjin + (mchujia*shoushu*100.0*0.999)

              x = ((mchujia-mrujia)*shoushu*100.0)/(mrujia*shoushu*100.0)

              shouyilv.append(x)

              if x < 0:

                  kuisun.append(mairushijian)      #如果此次交易结果亏损,则把买入时间加入列表,输出

              jiaoyicishu = jiaoyicishu + 1

              shoushu = 0

#              print('买入时间%d,买入价%.4f,卖出价%.4f,本金%.2f,此次收益率%.4f' %(mairushijian,mrujia,mchujia,benjin,x))

              zongshouyilv.append((benjin-1000000) / 1000000)

              shouyishijian.append(shuju1.iloc[shijian]['trade_date'])  #这里想把交易的时间打出去,但是shuju是没有倒过来的,要倒过来

            else:

                continue

    geguchenggonglv = 1 - ((len(kuisun)-1)/jiaoyicishu)   #个股成功率

#    print(zongshouyilv[len(zongshouyilv)-1],jiaoyicishu,kuisun,geguchenggonglv)  #输出个股最后总收益率和交易次数和亏损时间

         

    return shouyishijian,zongshouyilv,geguchenggonglv


    

def xunhuanjiaoyi(lx,kaishiriqi,jieshuriqi):

       lxzongshouyilv = []

       lxgeguchenggonglv = []

       bufuhe = 0    

       buzaiqijiandegupiao = ['不在期间的股票:']

       shouyi = 0

       chenggonglv = 0

       for i in range(len(lx)):

           try:

               if i > 0:   #因为lx1等列表第一个元素是市值提示标签

                  daima = lx[i]         

                  shuju = ts.pro_bar(ts_code=daima,adj='qfq',start_date=kaishiriqi,end_date=jieshuriqi)  #导入数据

                  benjin = 1000000

                  maimaidian = pandingzhibiao(shuju)    #得到买卖点

                  shouyishijian,gegushouyilv,geguchenggonglv = jiaoyi(shuju,benjin,maimaidian)

                  #print(gegushouyilv)

                  geguzongshouyi = gegushouyilv[-1]

                  lxzongshouyilv.append([lx[i],geguzongshouyi])

                  lxgeguchenggonglv.append(geguchenggonglv)

       #以列表[[代码,收益率],...]的格式把每个个股的交易结果集合起来

        

           except:

               bufuhe = bufuhe + 1   #用来记录发生错误的次数,也就是用来记录股票未在期间内上市的个数;

               #交易不成功的原因包括:是期间未上市、期间上市

               buzaiqijiandegupiao.append(lx[i])   #把不在期间的股票代码输出来,以便后面核对

               continue


       print('不在期间的股票数:%d'%bufuhe,'成功交易的股票数:%d'%len(lxzongshouyilv),buzaiqijiandegupiao)   

       #print(lxgeguchenggonglv)   #验证是否成功得到个股成功率列表

       for i in range(len(lxzongshouyilv)):

           shouyi = shouyi + lxzongshouyilv[i][1]

           chenggonglv = chenggonglv + lxgeguchenggonglv[i]

       pingjunshouyi = shouyi/(len(lx)-bufuhe)

       pingjunchenggonglv = chenggonglv/(len(lx)-bufuhe)

    #print(lxzongshouyilv)

     

       return pingjunshouyi,lxzongshouyilv,pingjunchenggonglv


print('请输入选股依据的日期:')   #注意不能是节假日,节假日得不到数据

dangqianriqi = input()

lx1,lx2,lx3,qita = shizhixuangu(dangqianriqi)

#print(len(qita))

print('请输入开始时间:')

kaishiriqi = input()

print('请输入结束时间:')

jieshuriqi = input()

'''

del lx2[0]

lx1 += lx2'''

#经验证,将lx2和lx1合并后280左右只股票,可以运行程序


lx1pjshouyi,lx1shouyiliebiao,pjchenggonglv = xunhuanjiaoyi(lx1,kaishiriqi,jieshuriqi)

print('1000亿市值以上个股平均收益率:%.4f'%lx1pjshouyi,'平均成功率:%.4f'%pjchenggonglv)

#lx2pjshouyi,lx2shouyiliebiao,pjchenggonglv = xunhuanjiaoyi(lx2,kaishiriqi,jieshuriqi)

#print('500亿--1000亿市值个股平均收益率:%.4f'%lx2pjshouyi,'平均成功率:%.4f'%pjchenggonglv)

#lx3pjshouyi,lx3shouyiliebiao,pjchenggonglv = xunhuanjiaoyi(lx3,kaishiriqi,jieshuriqi)

#print('200亿--500亿市值个股平均收益率:%.4f'%lx3pjshouyi,'平均成功率:%.4f'%pjchenggonglv)

#qitapjshouyi,qitashouyiliebiao,pjchenggonglv = xunhuanjiaoyi(qita,kaishiriqi,jieshuriqi)

#print('小于200亿市值个股平均收益率:%.4f'%qitapjshouyi,)

       



       

       

       

       


简单回测程序的评论 (共 条)

分享到微博请遵守国家法律