- 首先确定项目目的:
- 基于Tushare建立一个多组合的量化策略。
- 策略:1.趋势+择时
- 算法:选择SH300每月累积涨幅排名靠前的10只股票;然后择时,计算在金叉,死叉点进行买卖。
一、获取股票
df = pd.read_excel(’./沪深300.xlsx’,converters = {u’代码’:str}) #要加上,converters = {u’代码’:str} 不然 ‘000’就会被忽略掉啦
#然后遍历300只股票的收益率定义时间戳:这里选择20201220-2021220 然后预测2021320的收益排名; 注意这里要后复权,后复权做回测和计算利润率是用,前复权一般用来实盘比较好。
#这里利用tushare获取月收益
df_col = pd.DataFrame()
for code in df.loc[:,‘代码’]:
#给股票加上后缀sz sh
if code[0]‘6’ and code[1]‘0’:
code = code+’.SH’
#df = pro.monthly(ts_code=,start_date=‘20200401’, end_date=‘20200501’, fields=‘ts_code,pct_chg,trade_date’)
df = ts.pro_bar(ts_code=code, adj=‘hfq’, start_date=‘20200101’, end_date=‘20210101’) #还要判断此时是否还未上市,防止用到未来数据
if df is None :
continue
df = df[[‘ts_code’,‘open’,‘close’,‘pct_chg’]]
df[‘sum’]=df[‘pct_chg’].sum()
df_col = df_col.append(df[0:1])
df_col = df_col[[‘ts_code’,‘sum’]]
df_col .sort_values(by=‘sum’,inplace=True)
df_col.to_csv(‘12个月累积收益.csv’)
二、搭建策略(这里利用backtrader量化回测)
读取上述数据收益排名靠前的前十只股票和后十只股票(每日更新股票池)+择时利用backtrader进行回测查看收益。
def get_data(code=‘code’,strattime=‘2021-01-01’,endtime=‘2022-01-01’):
df = ts.get_k_data(code=code,start=strattime,end=endtime)
df.index = pd.to_datetime(df.date)
df[‘OpenInterest’]=0
df = df[[‘open’,‘high’,‘low’,‘close’,‘volume’,‘OpenInterest’]]
return df
#第二步,数据有了,就开始构建自己的策略
class Mystrategy(bt.Strategy): #定义一个Mystratrgy类,然后来继承bt.Strategy
params = dict(period1=20, look_back_days=30,printlog=True)
#或者使用字典的形式。 params = dict(period1=, period2= period3=,)
def __init__(self):
#定义参数 参数可以相互继承使用,这里只是需要申明变量
self.order = None #此时没有订单处理.
self.ma = dict()
for data in self.datas:
self.ma[data._name] = bt.indicators.SimpleMovingAverage(data.close,period=self.params.period1) # 计算20日均线
def next(self):
# 股票收益
interest=[]
if (self.order):#有交易订单的情况下待交易完。
return
for data in self.datas:
if len(data)>self.params.look_back_days:
p0=data.close[0]
pn=data.close[-self.params.look_back_days]
rate=(p0-pn)/pn
interest.append([data._name,rate])
stock_list=sorted(interest,key=lambda x:x[1],reverse=True)
stock_head_10=[i[0] for i in interest[:9]]
stock_back_10=[i[0] for i in interest[:-9]]
# 得到当前的账户价值
total_value = self.broker.getvalue()
p_value = total_value * 0.9 / 10
for data in self.datas:
# 获取仓位
pos = self.getposition(data).size
# 建仓
if not pos and data._name in stock_head_10 and \
self.ma[data._name][0] > data.close[0]:
size = int(p_value / 100 / data.close[0]) * 100
self.buy(data=data, size=size)
# 平仓
if pos != 0 and data._name not in stock_head_10 or \
self.ma[data._name][0] < data.close[0]:
self.close(data=data)
买入月收益排名靠后的10只股票
‘’‘for data in self.datas:
# 获取仓位
pos = self.getposition(data).size
# 建仓
if not pos and data._name in stock_back_10 and
self.ma[data._name][0] > data.close[0]:
size = int(p_value / 100 / data.close[0]) * 100
self.buy(data=data, size=size)
# 平仓
if pos != 0 and data._name not in stock_back_10 or
self.ma[data._name][0] < data.close[0]:
self.close(data=data)’’’
def log(self, txt, dt=None, doprint=True):
if self.params.printlog or doprint:
dt = dt or self.datas[0].datetime.date(0)
print(f’{dt.isoformat()},{txt}’)
# 记录交易执行情况(可省略,默认不输出结果)
def notify_order(self, order):
# 如果order为submitted/accepted,返回空
if order.status in [order.Submitted, order.Accepted]:
return
# 如果order为buy/sell executed,报告价格结果
if order.status in [order.Completed]:
if order.isbuy():
self.log(f'买入:\n价格:{order.executed.price:.2f},\
成本:{order.executed.value:.2f},\
手续费:{order.executed.comm:.2f}')
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else:
self.log(f'卖出:\n价格:{order.executed.price:.2f},\
成本: {order.executed.value:.2f},\
手续费{order.executed.comm:.2f}')
self.bar_executed = len(self)
# 如果指令取消/交易失败, 报告结果
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('交易失败')
self.order = None
# 记录交易收益情况(可省略,默认不输出结果)
def notify_trade(self, trade):
if not trade.isclosed:
return
self.log(f'策略收益:\n毛收益 {trade.pnl:.2f}, 净收益 {trade.pnlcomm:.2f}')
fromdate = dt(2021,1,1)
todate = dt(2022,2,1)
if name == ‘main’:
df=pd.read_csv(‘12个月累积收益.csv’)
# 策略设置
# 构建一个大脑
cerebro = bt.Cerebro()
# 给大脑输入数据
for code in (df[‘ts_code’]):
print(code)
code = ‘’.join(filter(str.isdigit,code))
stock_data = get_data(code,strattime=‘2021-01-01’,endtime=‘2022-02-01’)
data = bt.feeds.PandasData(dataname=stock_data, fromdate=fromdate, todate=todate)
cerebro.adddata(data)