# 风险及免责提示:该策略由聚宽用户分享,仅供学习交流使用。
# 原文一般包含策略说明,如有疑问建议到原文和作者交流讨论。
# 克隆自聚宽文章:https://www.joinquant.com/post/28499
# 标题:市值,研发支出,roe,三因子,跑赢大盘
# 作者:zyljq
# 克隆自聚宽文章:https://www.joinquant.com/post/1399
# 标题:【量化课堂】多因子策略入门
# 作者:JoinQuant量化课堂
#多因子策略入门
# 2015-01-01 到 2016-03-08, ¥2000000, 每天
'''
================================================================================
总体回测前
================================================================================
'''
import talib
#总体回测前要做的事情
def initialize(context):
set_params() #1设置策参数
set_variables() #2设置中间变量
set_backtest() #3设置回测条件
#1
#设置策参数
def set_params():
'''
g.tc=15 # 调仓频率
g.yb=63 # 样本长度
g.N=20 # 持仓数目
'''
g.tc=15 # 调仓频率
g.yb=63 # 样本长度
g.N=9 # 持仓数目
g.use_dynamic_target_market = True # 是否动态改变大盘热度参考指标
# g.target_market = '000300.XSHG'
g.target_market = '399001.XSHE'
g.empty_keep_stock = '511880.XSHG' # 闲时买入的标的
# g.empty_keep_stock = '601318.XSHG'#闲时买入的标的
g.signal = 'BUY' # 交易信号初始化
g.emotion_rate = 0 # 市场热度
g.lag = 5 # 大盘成交量连续跌破均线的天数,发出空仓信号 #5
g.lag0 = 7 # 大盘成交量监控周期 #7
g.lag1 = 13 # 比价均线周期 #13
g.lag2 = 13 # 价格涨幅计算周期 #13
'''
g.factors=["market_cap","roe"] # 用户选出来的因子
# 因子等权重里1表示因子值越小越好,-1表示因子值越大越好
g.weights=[[1],[-1]]
'''
g.factors=["market_cap","development_expenditure","roe"] # 用户选出来的因子
# 因子等权重里1表示因子值越小越好,-1表示因子值越大越好
g.weights=[[-1],[-1],[-1]]
#2
#设置中间变量
def set_variables():
g.t=0 #记录回测运行的天数
g.if_trade=False #当天是否交易
#3
#设置回测条件
def set_backtest():
set_option('use_real_price', True)#用真实价格交易
log.set_level('order', 'error')
'''
================================================================================
每天开盘前
================================================================================
'''
#每天开盘前要做的事情
def before_trading_start(context):
if g.t%g.tc==0:
#每g.tc天,交易一次行
g.if_trade=True
# 设置手续费与手续费
set_slip_fee(context)
# 设置可行股票池:获得当前开盘的沪深300股票池并剔除当前或者计算样本期间停牌的股票
g.all_stocks = set_feasible_stocks(get_index_stocks('000300.XSHG'),g.yb,context)
# 查询所有财务因子
g.q = query(valuation,balance,cash_flow,income,indicator).filter(valuation.code.in_(g.all_stocks))
#print(g.q)
g.t+=1
#4
# 设置可行股票池
# 过滤掉当日停牌的股票,且筛选出前days天未停牌股票
# 输入:stock_list为list类型,样本天数days为int类型,context(见API)
# 输出:list
def set_feasible_stocks(stock_list,days,context):
# 得到是否停牌信息的dataframe,停牌的1,未停牌得0
suspened_info_df = get_price(list(stock_list), start_date=context.current_dt, end_date=context.current_dt, frequency='daily', fields='paused')['paused'].T
# 过滤停牌股票 返回dataframe
unsuspened_index = suspened_info_df.iloc[:,0]<1 # 得到当日未停牌股票的代码list: unsuspened_stocks = suspened_info_df[unsuspened_index].index # 进一步,筛选出前days天未曾停牌的股票list: feasible_stocks=[] current_data=get_current_data() for stock in unsuspened_stocks: if sum(attribute_history(stock, days, unit='1d',fields=('paused'),skip_paused=False))[0]==0: feasible_stocks.append(stock) return feasible_stocks #5 # 根据不同的时间段设置滑点与手续费 def set_slip_fee(context): # 将滑点设置为0 set_slippage(FixedSlippage(0)) # 根据不同的时间段设置手续费 dt=context.current_dt log.info(type(context.current_dt)) if dt>datetime.datetime(2013,1, 1):
set_commission(PerTrade(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
elif dt>datetime.datetime(2011,1, 1):
set_commission(PerTrade(buy_cost=0.001, sell_cost=0.002, min_cost=5))
elif dt>datetime.datetime(2009,1, 1):
set_commission(PerTrade(buy_cost=0.002, sell_cost=0.003, min_cost=5))
else:
set_commission(PerTrade(buy_cost=0.003, sell_cost=0.004, min_cost=5))
'''
================================================================================
每天收盘后
================================================================================
'''
# 每日收盘后要做的事情(本策略中不需要)
def after_trading_end(context):
return
def EmotionMonitor():
_cnt = g.lag0 + max(g.lag, 3)
#volume = attribute_history(security=g.target_market, count=_cnt, unit='1d', fields='volume')['volume']
volume = attribute_history(security=g.target_market, count=_cnt, unit='1d', fields='volume')['volume']
v_ma_lag0 = talib.MA(volume, g.lag0) # 前 g.lag0 - 1 个会变成nan
#
g.emotion_rate = round((volume[-1] / v_ma_lag0[-1] - 1) * 100, 2) # 最后一天的成交量比成交量均值高%
#
vol_diff = (volume - v_ma_lag0)
if vol_diff[-1] >= 0:
ret_val = 1 if (vol_diff[-3:] >= 0).all() else 0 # 大盘成交量,最近3天都站在均线之上
else:
ret_val = -1 if (vol_diff[-g.lag:] < 0).all() else 0 # 大盘成交量,最近g.lag天都在均线之下 # return ret_val ''' ================================================================================ 每天交易时 ================================================================================ ''' def handle_data(context, data): if g.if_trade==True: # 计算现在的总资产,以分配资金,这里是等额权重分配 g.everyStock=context.portfolio.portfolio_value/g.N # 获得今天日期的字符串 todayStr=str(context.current_dt)[0:10] # 获得因子排序 a,b=getRankedFactors(g.factors,todayStr) # 计算每个股票的得分 points=np.dot(a,g.weights) # 复制股票代码 stock_sort=b[:] # 对股票的得分进行排名 points,stock_sort=bubble(points,stock_sort) # 取前N名的股票 toBuy=stock_sort[0:g.N].values # 对于不需要持仓的股票,全仓卖出 order_stock_sell(context,data,toBuy) # 对于不需要持仓的股票,按分配到的份额买入 order_stock_buy(context,data,toBuy) g.if_trade=False #6 #获得卖出信号,并执行卖出操作 #输入:context, data,toBuy-list #输出:none def order_stock_sell(context,data,toBuy): #如果现有持仓股票不在股票池,清空 list_position=context.portfolio.positions.keys() for stock in list_position: if stock not in toBuy : order_target(stock, 0) #7 #获得买入信号,并执行买入操作 #输入:context, data,toBuy-list #输出:none def order_stock_buy(context,data,toBuy): # 对于不需要持仓的股票,按分配到的份额买入 for i in range(0,len(g.all_stocks)): if indexOf(g.all_stocks[i],toBuy)>-1 :
order_target_value(g.all_stocks[i], g.everyStock)
#8
#查找一个元素在数组里面的位置,如果不存在,则返回-1
#输入:元素,对应数组
#输出:-1
def indexOf(e,a):
for i in range(0,len(a)):
if e==a[i]:
return i
return -1
#9
#取因子数据
#输入:f-全局通用的查询,d-str
#输出:因子数据,股票的代码-dataframe
def getRankedFactors(f,d):
# 获得股票的基本面数据,这个API里面有,g.q是一个全局通用的查询
df = get_fundamentals(g.q,d)
#print(df.shape)
for i in range(0,df.shape[1],10):
print( df.columns[i:i+10] )
# 为了防止Python里面的浅复制现象,采用循环来定义二维数组
res = [([0] * len(f)) for i in range(len(df))]
# 把数据填充到刚才定义的数组里面
for i in range(0,len(df)):
for j in range(0,len(f)):
res[i][j]=df[f[j]][i]
# 用均值填充NaN值
fillNan(res)
'''
for i in range(len(res)):
res[i][0]=res[i][1]/res[i][0]
del res[i][0]
'''
# 将数据变成排名
#print(res)
getRank(res)
# 返回因子数据和股票的代码(这个是因为沪深300指数成分股一直在变,如果用未来的沪深300指数成分股在之前可能有一些股票还没上市)
return res,df['code']
⚠️
本站资源大多来自网络,仅供网友学习交流,未经作者或上传书面授权,请勿作他用。
站长 vx: xiangyin615 或者 留言反馈 ,我们将尽快处理。
Notice: When you of the legal rights be violate, please stir to vx: xiangyin615
站长 vx: xiangyin615 或者 留言反馈 ,我们将尽快处理。
Notice: When you of the legal rights be violate, please stir to vx: xiangyin615
