水激石则鸣,人激志则宏。
· ·
这个量化策略的核心在于5个因子(总市值,流通市值,最新价格,5日平均成交量,60日涨幅)加权打分选股,然后通过牛熊来控制仓位,牛市全仓,熊市30%仓位,通过仓位控制实现低回撤,每日进行调仓。
回测数据如下:
*回测数据只作测试用,不代表未来实际收益
1、策略初始化配置
主要定义了牛熊市分界的参数以及仓位参数,5因子权重参数,择时参数等等
g.isbull = False # 是否牛市
g.chosen_stock_list = [] # 目标股票池
g.nohold = True # 是否空仓
g.sold_stock = {} # 近期卖出的股票及卖出天数
g.stocknum = 4 # 理想持股数量
g.bearpercent = 0.3 # 熊市仓位
g.bearposition = True # 熊市是否持仓
# 初始筛选
g.increase1d = 0.087 # 前一日涨幅
# 排名条件及权重,正数代表从小到大,负数表示从大到小
# 各因子权重:总市值,流通市值,最新价格,5日平均成交量,60日涨幅
g.weights = [5,5,8,4,10]
# 配置择时
g.MA = ['000001.XSHG', 10] # 均线择时
g.choose_time_signal = True # 启用择时信号
g.threshold = 0.003 # 牛熊切换阈值
g.buyagain = 5 # 再次买入的间隔时间
2、选股逻辑
(1)判断牛熊市
默认以上证指数10日线为依据,0.3%是过滤日线级别以内的随机波动
现价 > 10日均线*(1+0.3%) → 牛市
现价 < 10日均线*(1-0.3%) → 熊市
def get_bull_bear_signal_minute():
nowindex = get_close_price(g.MA[0], 1, '1m')
MAold = (attribute_history(g.MA[0], g.MA[1] - 1, '1d', 'close', True)['close'].sum() + nowindex) / g.MA[1]
if g.isbull:
if nowindex * (1 + g.threshold) <= MAold:
g.isbull = False
else:
if nowindex > MAold * (1 + g.threshold):
g.isbull = True
(2)基础过滤
过滤创业板、ST、停牌、当日涨停、次新股、昨日涨幅过高8.7%
stock_list = filter_gem_stock(context, stock_list)
stock_list = filter_st_stock(stock_list)
stock_list = filter_paused_stock(stock_list)
stock_list = filter_limitup_stock(context, stock_list)
stock_list = filter_new_stock(context, stock_list)
stock_list = filter_increase1d(stock_list)
stock_list = filter_buyagain(stock_list)
(3)5因子加权打分
得分 = 5 x (最小总市值/当前总市值) +5 x (最小流通市值/当前流通市值) + 8 x (最低价/当前价)+ 4 x (最小成交量/当前成交量) +10 x (最小60日涨幅/当前60日涨幅)
所有比值采用最小值/当前值,当前值越小,得分越高,说明有较大的价格发现空间
rank_stock_list = get_fundamentals(query(
valuation.code, valuation.market_cap, valuation.circulating_market_cap
).filter(valuation.code.in_(stock_list)
).order_by(valuation.circulating_market_cap.asc()).limit(100))
# 5日成交量
volume5d = [attribute_history(stock, 1200, '1m', 'volume', df=False)['volume'].sum() for stock in rank_stock_list['code']]
# 60日涨幅
increase60d = [get_growth_rate60(stock) for stock in rank_stock_list['code']]
# 当前价格
current_price = [get_close_price(stock, 1, '1m') for stock in rank_stock_list['code']]
min_price = min(current_price)
min_increase60d = min(increase60d)
min_circulating_market_cap = min(rank_stock_list['circulating_market_cap'])
min_market_cap = min(rank_stock_list['market_cap'])
min_volume = min(volume5d)
totalcount = [[i, math.log(min_volume / volume5d[i]) * g.weights[3] + math.log(min_price / current_price[i]) * g.weights[2] + math.log(min_circulating_market_cap / rank_stock_list['circulating_market_cap'][i]) * g.weights[1] + math.log(min_market_cap / rank_stock_list['market_cap'][i]) * g.weights[0] + math.log(min_increase60d / increase60d[i]) * g.weights[4]] for i in rank_stock_list.index]
totalcount.sort(key=lambda x:x[1])
3、调仓逻辑
(1)调仓卖出,仓位调整
熊市仓位调整为总仓位的30%,个股最大仓位不超过个股平均仓位的130%,牛市则为全仓
卖出不在目标股票池的股票,超过个股最大仓位限制时,调整为限制仓位值
if g.choose_time_signal and (not g.isbull):
free_value = context.portfolio.total_value * g.bearpercent # 熊市可用资金=总资产*30%
maxpercent = 1.3 / g.stocknum * g.bearpercent # 个股最大仓位=1.3/4*0.3≈9.75%
else:
free_value = context.portfolio.total_value # 牛市用全部资金
maxpercent = 1.3 / g.stocknum # 正常最大仓位32.5%
buycash = free_value / g.stocknum
...
current_percent = context.portfolio.positions[stock].value / context.portfolio.total_value
# 超过最大仓位限制,调整到目标仓位
if current_percent > maxpercent:order_target_value(stock, buycash)
(2)买入股票
熊市仓位调整为总仓位的30%,个股最小仓位不低于个股平均仓位的70%,牛市则为全仓
0.7设置的目的是防止因短期波动触发强制平仓,允许优质股票自然突破理论仓位下限
if g.choose_time_signal and (not g.isbull):
free_value = context.portfolio.total_value * g.bearpercent # 可用资金
minpercent = 0.7 / g.stocknum * g.bearpercent # 最小持仓比例 0.7/4*0.3 ≈5.25%
else:
free_value = context.portfolio.total_value # 全仓操作
minpercent = 0.7 / g.stocknum # 最小持仓比例 0.7/4 = 17.5%
buycash = free_value / g.stocknum # 每支股票理论仓位
...
if hold_stocks[i] in context.portfolio.positions.keys(): # 实时可用资金
current_percent = context.portfolio.positions[hold_stocks[i]].value / context.portfolio.total_value
if current_percent >= minpercent:continue # 当前仓位 ≥ minpercent,跳过
# 补仓金额 = min(可用资金, 理论仓位-当前仓位)
tobuy = min(free_cash, buycash - context.portfolio.positions[hold_stocks[i]].value)
else:
tobuy = min(buycash, free_cash)
order_value(hold_stocks[i], tobuy)
(3)再次买入的间隔时间
for stock in g.sold_stock.keys():
if g.sold_stock[stock] >= g.buyagain - 1:
del g.sold_stock[stock]
else:
g.sold_stock[stock] += 1
这篇文章主要分享5因子加权选股以及牛熊控制仓位策略,主要的逻辑在因子加权选股和牛熊市仓位控制上面,量化交易的回测和实盘,可以在量化交易软件中进行,大家可以去体验下量化交易的魅力
如果有不懂的,欢迎找我一起交流,加入量化交易大家庭