簡(jiǎn)單回測(cè)程序
# -*- 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')
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#由于接口不同,只能在函數(shù)內(nèi)部實(shí)現(xiàn)市值數(shù)據(jù)的提取
? ? lx1 = ['市值大于1000億']
? ? lx2 = ['市值大于500億']
? ? lx3 = ['市值大于200億']
? ? qita = []
? ? for i in range(len(shuju)):
? ? ? ? shizhi = float(shuju.iloc[i]['total_mv'])
? ? ? ? #print(shizhi)? ? ? #經(jīng)驗(yàn)證,可以得到市值的數(shù)據(jù)并輸出
? ? ? ? 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):? ? ?#輸出當(dāng)前股票的買賣點(diǎn)
? ? '''金叉買入,但是由于指標(biāo)數(shù)據(jù)是按交易日的‘散點(diǎn)’,所以導(dǎo)致‘金叉’難以與當(dāng)天對(duì)應(yīng),
? ? 所以,判斷標(biāo)準(zhǔn)是‘前一天DIF<=DEA,當(dāng)天DIF>=DEA’,同樣,賣出標(biāo)準(zhǔn)是‘前天DIF>=DEA,
? ? 當(dāng)天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:? ? ? ? ? ? ? ? ? ? ? ?#因?yàn)镸ACD函數(shù)輸出指標(biāo)數(shù)據(jù)的都是比行情數(shù)據(jù)少33個(gè)數(shù)的? ? ? ? ? ? ? ? ??
? ? ? ? ? ?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'],'買入']})??
? ? ? ? ? ? ? ? ? ?#注意,要用已經(jīng)倒過(guò)來(lái)的行情數(shù)據(jù)close,才對(duì)應(yīng)指標(biāo)
? ? ? ? ? ?elif DIF0 >= DEA0:
? ? ? ? ? ? ? ?if DIF1 <= DEA1:
? ? ? ? ? ? ? ? ? ?maimai.update({i:[shuju1.iloc[i]['trade_date'],shuju1.iloc[i]['close'],'賣出']})
? ? ? ? ? ? ? ? ? ?#或者可以直接用MACD來(lái)判斷指標(biāo),更簡(jiǎn)單
? ?#買賣點(diǎn)將會(huì)是一個(gè)買點(diǎn),接著一個(gè)賣點(diǎn),接著一個(gè)買點(diǎn)...但是,在其他的指標(biāo)判定中卻不一定了,還可能是連續(xù)幾個(gè)買點(diǎn)或賣點(diǎn)
? ?
? ? ? ? ? ?if i >= 19:? ? ?#循環(huán)中i是從0開始的,當(dāng)i=19時(shí)表示此時(shí)是shuju中的第20個(gè)數(shù)據(jù)
? ? ? ? ? ? ? twenty = shuju1.iloc[(i-19):(i+1)]['vol'].mean()? ?#以切片的方法,取shuju中以當(dāng)前日期開始往回的20天的成交量數(shù)據(jù)的平均值
? ? ? ? ? ? ? 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)? ? ? ? ?#注意,此時(shí)的買入賣出點(diǎn)的價(jià)格是‘字符串’類型
? ? 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)? ? ? #如果此次交易結(jié)果虧損,則把買入時(shí)間加入列表,輸出
? ? ? ? ? ? ? jiaoyicishu = jiaoyicishu + 1
? ? ? ? ? ? ? shoushu = 0
#? ? ? ? ? ? ? print('買入時(shí)間%d,買入價(jià)%.4f,賣出價(jià)%.4f,本金%.2f,此次收益率%.4f' %(mairushijian,mrujia,mchujia,benjin,x))
? ? ? ? ? ? ? zongshouyilv.append((benjin-1000000) / 1000000)
? ? ? ? ? ? ? shouyishijian.append(shuju1.iloc[shijian]['trade_date'])? #這里想把交易的時(shí)間打出去,但是shuju是沒有倒過(guò)來(lái)的,要倒過(guò)來(lái)
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? continue
? ? geguchenggonglv = 1 - ((len(kuisun)-1)/jiaoyicishu)? ?#個(gè)股成功率
#? ? print(zongshouyilv[len(zongshouyilv)-1],jiaoyicishu,kuisun,geguchenggonglv)? #輸出個(gè)股最后總收益率和交易次數(shù)和虧損時(shí)間
? ? ? ? ?
? ? 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:? ?#因?yàn)閘x1等列表第一個(gè)元素是市值提示標(biāo)簽
? ? ? ? ? ? ? ? ? daima = lx[i]? ? ? ? ?
? ? ? ? ? ? ? ? ? shuju = ts.pro_bar(ts_code=daima,adj='qfq',start_date=kaishiriqi,end_date=jieshuriqi)? #導(dǎo)入數(shù)據(jù)
? ? ? ? ? ? ? ? ? benjin = 1000000
? ? ? ? ? ? ? ? ? maimaidian = pandingzhibiao(shuju)? ? #得到買賣點(diǎn)
? ? ? ? ? ? ? ? ? shouyishijian,gegushouyilv,geguchenggonglv = jiaoyi(shuju,benjin,maimaidian)
? ? ? ? ? ? ? ? ? #print(gegushouyilv)
? ? ? ? ? ? ? ? ? geguzongshouyi = gegushouyilv[-1]
? ? ? ? ? ? ? ? ? lxzongshouyilv.append([lx[i],geguzongshouyi])
? ? ? ? ? ? ? ? ? lxgeguchenggonglv.append(geguchenggonglv)
? ? ? ?#以列表[[代碼,收益率],...]的格式把每個(gè)個(gè)股的交易結(jié)果集合起來(lái)
? ? ? ??
? ? ? ? ? ?except:
? ? ? ? ? ? ? ?bufuhe = bufuhe + 1? ?#用來(lái)記錄發(fā)生錯(cuò)誤的次數(shù),也就是用來(lái)記錄股票未在期間內(nèi)上市的個(gè)數(shù);
? ? ? ? ? ? ? ?#交易不成功的原因包括:是期間未上市、期間上市
? ? ? ? ? ? ? ?buzaiqijiandegupiao.append(lx[i])? ?#把不在期間的股票代碼輸出來(lái),以便后面核對(duì)
? ? ? ? ? ? ? ?continue
? ? ? ?print('不在期間的股票數(shù):%d'%bufuhe,'成功交易的股票數(shù):%d'%len(lxzongshouyilv),buzaiqijiandegupiao)? ?
? ? ? ?#print(lxgeguchenggonglv)? ?#驗(yàn)證是否成功得到個(gè)股成功率列表
? ? ? ?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('請(qǐng)輸入選股依據(jù)的日期:')? ?#注意不能是節(jié)假日,節(jié)假日得不到數(shù)據(jù)
dangqianriqi = input()
lx1,lx2,lx3,qita = shizhixuangu(dangqianriqi)
#print(len(qita))
print('請(qǐng)輸入開始時(shí)間:')
kaishiriqi = input()
print('請(qǐng)輸入結(jié)束時(shí)間:')
jieshuriqi = input()
'''
del lx2[0]
lx1 += lx2'''
#經(jīng)驗(yàn)證,將lx2和lx1合并后280左右只股票,可以運(yùn)行程序
lx1pjshouyi,lx1shouyiliebiao,pjchenggonglv = xunhuanjiaoyi(lx1,kaishiriqi,jieshuriqi)
print('1000億市值以上個(gè)股平均收益率:%.4f'%lx1pjshouyi,'平均成功率:%.4f'%pjchenggonglv)
#lx2pjshouyi,lx2shouyiliebiao,pjchenggonglv = xunhuanjiaoyi(lx2,kaishiriqi,jieshuriqi)
#print('500億--1000億市值個(gè)股平均收益率:%.4f'%lx2pjshouyi,'平均成功率:%.4f'%pjchenggonglv)
#lx3pjshouyi,lx3shouyiliebiao,pjchenggonglv = xunhuanjiaoyi(lx3,kaishiriqi,jieshuriqi)
#print('200億--500億市值個(gè)股平均收益率:%.4f'%lx3pjshouyi,'平均成功率:%.4f'%pjchenggonglv)
#qitapjshouyi,qitashouyiliebiao,pjchenggonglv = xunhuanjiaoyi(qita,kaishiriqi,jieshuriqi)
#print('小于200億市值個(gè)股平均收益率:%.4f'%qitapjshouyi,)
? ? ? ?
? ? ? ?
? ? ? ?
? ? ? ?
? ? ? ?