几年前光伏锂电赛道股崩盘时,大家总结出带有一致性底色的反转因子——行业拥挤度。随着今年初微盘股暴跌暴露出小市值低流动性的特点,一致性信号的挖掘研究对小市值风控有很大意义。
调整处:
1、指数牛熊开关采用上证综指,考虑选股持仓为深市中小板,调整成全A指数。
2、清仓信号跌幅阈值调整。
效果:
年化从54.68%提高至66%,峰值回测从24.6%降低至21.4%。参考在23年11月后空仓时间较多,可能是影响收益的重要原因。
#一致性筛选 from jqdata import * from jqfactor import get_factor_values from jqlib.technical_analysis import * import numpy as np
import pandas as pd import statsmodels.api as sm import datetime import talib # 过滤停牌股票 def filter_paused_stock(stock_list,last_date): return [stock for stock in stock_list if get_price(stock,end_date = last_date, count = 1,fields = 'paused')['paused'][0]==0] # 2-2过滤ST及其他具有退市标签的股票 def filter_st_stock(stock_list,last_date): return [stock for stock in stock_list if True not in get_extras('is_st',stock, start_date=last_date, end_date=last_date, df=False).values() and 'ST' not in get_security_info(stock).display_name and '*' not in get_security_info(stock).display_name and '退' not in get_security_info(stock).display_name] #2-6 过滤科创北交股票 def filter_kcbj_stock(stock_list,last_date): for stock in stock_list[:]: #if stock[0] == '4' or stock[0] == '8' or stock[:2] == '68' or stock[:3] == '300' or stock[:3] == '301': if stock[0] == '4' or stock[0] == '8' or stock[:2] == '68': stock_list.remove(stock) return stock_list #2-7 过滤次新 def filter_new_stock(stock_list,days,last_date): return [stock for stock in stock_list if not last_date - get_security_info(stock).start_date < datetime.timedelta(days=days)] def min_consistency_check(date,signal,mini_cosi_list): today_date = date lastd_date = get_trade_days(end_date=today_date, count=2)[-2] #0,增加基准指数的牛(关)熊(开)判断,1-年线上下 #df_index = get_price('000001.XSHG', end_date=lastd_date, frequency='1d', fields='close',count=240, panel=False) #中证全指 df_index = get_price('000985.XSHG', end_date=lastd_date, frequency='1d', fields='close',count=250, panel=False) #国证2000 #df_index = get_price('399303.XSHE', end_date=last_date, frequency='1d', fields='close',count=240, panel=False) if df_index['close'].values[-1] >df_index['close'].values.mean(): print('牛市,关闭一致性检查') return False, mini_cosi_list else: print('熊市,打开一致性检查') #1,取昨天的30天以上Min500(10%),去除ST stocklist = list(get_all_securities(['stock']).index) #取all num1 = len(stocklist) #print('所有股票数:', num1) #stocklist = [stockcode for stockcode in stocklist if not all_data[stockcode].paused] #stocklist = [stockcode for stockcode in stocklist if not all_data[stockcode].is_st] #stocklist = [stockcode for stockcode in stocklist if'退' not in all_data[stockcode].name] #stocklist = [stockcode for stockcode in stocklist if stockcode[0:3] != '688'] #stocklist = [stockcode for stockcode in stocklist if (today_date-get_security_info(stockcode).start_date).days>20] stocklist = filter_paused_stock(stocklist,lastd_date) stocklist = filter_st_stock(stocklist,lastd_date) stocklist = filter_kcbj_stock(stocklist,lastd_date) stocklist = filter_new_stock(stocklist,250,lastd_date) #stocklist = [stockcode for stockcode in stocklist if (today_date-get_security_info(stockcode).start_date).days>250] num2 = len(stocklist) #print('实际交易股票数:', num2) df_all = get_price(stocklist, end_date=lastd_date, frequency='1d', fields='money',count=1, panel=False) q = query(valuation.code, valuation.market_cap).filter(valuation.code.in_(stocklist)).order_by(valuation.market_cap.asc()) df = get_fundamentals(q) #num3 = round(0.05*num1) #原作数据 num3 = round(0.2*num2) stocklist = list(df['code'])[:num3] print('总样本数:', num3) #2,计算昨天的涨幅均值和方差,以及落在Mean+2方差内的 df_chg = get_money_flow(stocklist, end_date=lastd_date, fields='change_pct', count=1) #log.info(df_chg) chg_med = np.median(df_chg.change_pct) chg_std = np.std(df_chg.change_pct) #log.info(chg_mean,chg_std) df_temp = df_chg[(df_chg.change_pct < (chg_med+chg_std)) & (df_chg.change_pct > (chg_med-chg_std))] num4 = len(df_temp) cosistency_last = num4/num3 mini_cosi_list.append(cosistency_last) print('列表长度'+str(len(mini_cosi_list))) if len(mini_cosi_list) >=120: cosistency_mean = np.mean(mini_cosi_list[-120:]) cosistency_std = np.std(mini_cosi_list[-120:]) mini_cosi_list = mini_cosi_list[-120:] else: cosistency_mean = 0.8 cosistency_std =0.05 cosistency_upper = cosistency_mean+cosistency_std #使用BOLL带判断 if (chg_med <-3 and cosistency_last>=cosistency_upper): #if (chg_med <-3 and cosistency_last>=cosistency_upper):# or (chg_med <-4 and num4/num3>0.84) or (chg_med <-6 and num4/num3>0.82) : print('清仓') return True, mini_cosi_list elif (chg_med >2 and cosistency_last>=cosistency_mean): print('满上') return False, mini_cosi_list else: print('照常,信号为False') return False, mini_cosi_list