量化学习平台
文章
市场宽度
背离图
登录
注册
挖掘特色估值体系因子,把握投资机会,年化150%+
策略
作者: 水滴
```python # 风险及免责提示:该策略由聚宽用户在聚宽社区分享,仅供学习交流使用。 # 原文一般包含策略说明,如有疑问请到原文和作者交流讨论。 # 原文网址:https://www.joinquant.com/post/41763 # 标题:挖掘中国特色的估值体系投资机会,年化150%+ # 作者:子匀 # 回测资金 500000 #导入函数库 from jqdata import * from jqfactor import get_factor_values import numpy as np import pandas as pd def initialize(context): # 设定基准 set_benchmark('000300.XSHG') # 用真实价格交易 set_option('use_real_price', True) # 打开防未来函数 set_option("avoid_future_data", True) # 将滑点设置为0 set_slippage(FixedSlippage(0)) # 设置交易成本万分之三,不同滑点影响可在归因分析中查看 set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5),type='stock') # 过滤order中低于error级别的日志 log.set_level('order', 'error') log.set_level('system', 'error') #初始化全局变量 g.stock_num = 4 #最大持仓数 g.limit_up_list = [] #记录持仓中涨停的股票 g.hold_list = [] #当前持仓的全部股票 g.limit_days = 20 #不再买入的时间段天数 g.target_list = [] #开盘前预操作股票池 do_schedule(context) def after_code_changed(context): # 取消所有定时运行 unschedule_all() do_schedule(context) def do_schedule(context): # 设置交易运行时间 run_daily(get_stock_list, time='8:00', reference_security='000300.XSHG') #准备预操作股票池 run_daily(prepare_trade, time='8:05', reference_security='000300.XSHG') #准备预操作股票池 run_daily(check_limit_up, time='14:00', reference_security='000300.XSHG') #检查持仓中的涨停股是否需要卖出 run_weekly(weekly_adjustment, weekday=1, time='9:30', reference_security='000300.XSHG') #默认周一开盘调仓,收益最高 run_weekly(print_position_info, weekday=1, time='15:10', reference_security='000300.XSHG') #打印复盘信息 #1-1 选股模块 def get_stock_list(context): yesterday = context.previous_date # 直属国企,央企 stocklists = ['601919.XSHG', '300073.XSHE', '600536.XSHG', '000951.XSHE', '601628.XSHG', '600036.XSHG', \ '601818.XSHG', '001289.XSHE', '601111.XSHG', '600787.XSHG', '688396.XSHG', '601611.XSHG', '600795.XSHG',\ '601390.XSHG', '600489.XSHG', '600007.XSHG', '600938.XSHG', '688187.XSHG', '600026.XSHG', '601898.XSHG', \ '000066.XSHE', '600862.XSHG', '601658.XSHG', '300374.XSHE', '600900.XSHG', '601881.XSHG', '000999.XSHE', \ '000009.XSHE', '601106.XSHG', '000928.XSHE', '000797.XSHE', '003816.XSHE', '688779.XSHG', '000807.XSHE', \ '600845.XSHG', '601965.XSHG', '600158.XSHG', '601319.XSHG', '601989.XSHG', '600916.XSHG', '601668.XSHG',\ '600760.XSHG', '601398.XSHG', '600905.XSHG', '600176.XSHG', '000996.XSHE', '601766.XSHG', '601328.XSHG', \ '600028.XSHG', '601808.XSHG', '600150.XSHG', '601800.XSHG', '600875.XSHG', '600486.XSHG', '600030.XSHG', \ '600685.XSHG', '000777.XSHE', '600970.XSHG', '000617.XSHE', '601336.XSHG', '600019.XSHG', '001979.XSHE', \ '000733.XSHE', '002080.XSHE', '002013.XSHE', '601318.XSHG', '601117.XSHG', '000927.XSHE', '600705.XSHG', \ '600737.XSHG', '600977.XSHG', '601857.XSHG', '600372.XSHG', '600061.XSHG', '600025.XSHG', '601995.XSHG', \ '601618.XSHG', '600730.XSHG', '000877.XSHE', '600406.XSHG', '601888.XSHG', '601006.XSHG', '000786.XSHE',\ '000166.XSHE', '601985.XSHG', '601601.XSHG', '601816.XSHG', '601179.XSHG', '600050.XSHG', '000758.XSHE', \ '601088.XSHG', '601868.XSHG', '601598.XSHG', '601698.XSHG', '000625.XSHE', '000629.XSHE', '601186.XSHG', \ '000768.XSHE', '002401.XSHE', '601858.XSHG', '000069.XSHE', '600999.XSHG', '002179.XSHE', '601872.XSHG', \ '000799.XSHE', '601728.XSHG', '601600.XSHG', '601788.XSHG', '600764.XSHG', '600886.XSHG', '000708.XSHE',\ '600056.XSHG', '600011.XSHG', '600893.XSHG', '600941.XSHG', '002268.XSHE', '601236.XSHG', '002415.XSHE', \ '600048.XSHG', '600027.XSHG', '601939.XSHG', '600118.XSHG', '002116.XSHE', '601988.XSHG', '002051.XSHE', \ '000800.XSHE', '601998.XSHG', '600765.XSHG', '300140.XSHE', '603126.XSHG', '601288.XSHG', '600115.XSHG', \ '601669.XSHG', '600029.XSHG', '002916.XSHE', '301269.XSHE', '600482.XSHG'] stocklists = filter_st_stock(stocklists) # 2. 剔除预期增长的后15% factor_data = get_factor_values(securities=stocklists, factors=['growth'], end_date=yesterday,count=1)['growth'].iloc[0] growth_list = factor_data.sort_values(ascending=False).index.tolist() growth_list = growth_list[:int(len(growth_list)*0.80)] # 3.按PE、PB复合排序 df=get_valuation(growth_list, end_date=yesterday, fields=['pe_ratio','pb_ratio'], count=1).set_index('code') # 4.行业比重 df['sw_code']= '' dict1=get_industry(security=growth_list, date=context.previous_date) for stock in growth_list : df.loc[stock,'sw_code'] = dict1[stock].get('sw_l1')['industry_code'] # 5 只留下前五年表现极差的四傻 801180 房地产I 801780 银行I 801790 非银金融I 801720 建筑装饰I df = df[df['sw_code'].isin(['801180','801780','801790','801720'])] df['dense']= df.groupby('sw_code')['pb_ratio'].rank(method='min',ascending=True,pct=True) df['score']=df['dense'] * 0.8+df.pe_ratio.rank(method='min',ascending=True,pct=True)*0.2 pb_list = (df.sort_values('score',ascending=True)).index.tolist() g.target_list = pb_list[:g.stock_num+2] return g.target_list #1-3 准备交易,推送信息 def prepare_trade(context): #1.获取已持有列表 g.hold_list= list(context.portfolio.positions.keys()) #2.获取昨日涨停列表 g.high_limit_list = [] if g.hold_list != []: df = get_price(g.hold_list, end_date=context.previous_date, frequency='daily', fields=['close','high_limit'], count=1, panel=False, fill_paused=False) df = df[df['close'] == df['high_limit']] g.high_limit_list = list(df.code) #1-4 整体调整持仓 def weekly_adjustment(context): g.target_list = filter_paused_stock(g.target_list) g.target_list = filter_limitup_stock(context, g.target_list) g.target_list = filter_limitdown_stock(context, g.target_list) #过滤最近买过且涨停过的股票 black_list = get_recent_limit_up_stock(context, g.target_list, g.limit_days) g.target_list = [stock for stock in g.target_list if stock not in black_list] #调仓卖出 for stock in g.hold_list: if (stock not in g.target_list) and (stock not in g.high_limit_list): close_position(stock) #调仓买入 position_count = len(context.portfolio.positions) # target_num = len(g.target_list) if position_count < g.stock_num: value = context.portfolio.cash / (g.stock_num - position_count) for stock in g.target_list: if stock not in context.portfolio.positions.keys(): if open_position(stock, value): if len(context.portfolio.positions) >= g.stock_num: break #1-5 调整昨日涨停股票 def check_limit_up(context): now_time = context.current_dt if g.high_limit_list != []: #对昨日涨停股票观察到尾盘如不涨停则提前卖出,如果涨停即使不在应买入列表仍暂时持有 for stock in g.high_limit_list: current_data = get_price(stock, end_date=now_time, frequency='1m', fields=['close','high_limit'], skip_paused=False, fq='pre', count=1, panel=False, fill_paused=True) if current_data.iloc[0,0] < current_data.iloc[0,1]: log.info("[%s]涨停打开,卖出" % (stock)) close_position(stock) else: log.info("[%s]涨停,继续持有" % (stock)) #2-1 过滤停牌股票 def filter_paused_stock(stock_list): current_data = get_current_data() return [stock for stock in stock_list if not current_data[stock].paused] #2-2 过滤ST及其他具有退市标签的股票 def filter_st_stock(stock_list): current_data = get_current_data() return [stock for stock in stock_list if not current_data[stock].is_st] #2-3 获取最近N个交易日内有涨停的股票 def get_recent_limit_up_stock(context, stock_list, recent_days): stat_date = context.previous_date new_list = [] new_list = get_price(stock_list, end_date=stat_date, frequency='daily', fields=['close','high_limit'], count=recent_days, panel=False, fill_paused=False).query('close==high_limit').code.tolist() return new_list #2-4 过滤涨停的股票 def filter_limitup_stock(context, stock_list): last_prices = history(1, unit='1m', field='close', security_list=stock_list) current_data = get_current_data() return [stock for stock in stock_list if stock in context.portfolio.positions.keys() or last_prices[stock][-1] < current_data[stock].high_limit] #2-5 过滤跌停的股票 def filter_limitdown_stock(context, stock_list): last_prices = history(1, unit='1m', field='close', security_list=stock_list) current_data = get_current_data() return [stock for stock in stock_list if stock in context.portfolio.positions.keys() or last_prices[stock][-1] > current_data[stock].low_limit] #2-6 过滤科创板 def filter_kcb_stock(context, stock_list): return [stock for stock in stock_list if stock[0:3] != '688'] #2-7 过滤次新股 def filter_new_stock(context,stock_list): yesterday = context.previous_date return [stock for stock in stock_list if not yesterday - get_security_info(stock).start_date < datetime.timedelta(days=250)] #3-1 交易模块-自定义下单 def order_target_value_(security, value): if value == 0: log.debug("Selling out %s" % (security)) else: log.debug("Order %s to value %f" % (security, value)) return order_target_value(security, value) #3-2 交易模块-开仓 def open_position(security, value): order = order_target_value_(security, value) if order != None and order.filled > 0: return True return False #3-3 交易模块-平仓 def close_position(position): # security = position.security order = order_target_value_(position, 0) if order != None: if order.status == OrderStatus.held and order.filled == order.amount: return True return False #5-1 复盘模块-打印 def print_position_info(context): trades = get_trades() for _trade in trades.values(): print('成交记录:'+str(_trade)) for position in list(context.portfolio.positions.values()): securities=position.security cost=position.avg_cost price=position.price ret=100*(price/cost-1) value=position.value amount=position.total_amount msg = '代码:{}'.format(securities) msg2= ' 成本价:{}'.format(format(cost,'.2f')) msg3= ' 现价:{}'.format(price) msg4= ' 收益率:{}%'.format(format(ret,'.2f')) msg5= ' 持仓(股):{}'.format(amount) msg6= ' 市值:{}'.format(format(value,'.2f')) print(msg + msg2+ msg3+msg4+msg5+msg6) print('———————————————————————————————————————分割线————————————————————————————————————————') """ todo: """ ```
文章分类
关于作者
水滴
注册时间: