# 克隆自聚宽文章:https://www.joinquant.com/post/50551 # 标题:大小外择时小市值2.0 # 作者:DanD from jqdata import * from jqfactor import * import numpy as np import pandas as pd import pickle import talib import warnings from jqlib.technical_analysis import * warnings.filterwarnings("ignore") # 初始化函数 def initialize(context): # 设定基准 set_benchmark('000300.XSHG') # 用真实价格交易 set_option('use_real_price', True) # 打开防未来函数 set_option("avoid_future_data", True) # 将滑点设置为0.246% set_slippage(PriceRelatedSlippage(0.00246),type='stock') # 设置交易成本万分之三,不同滑点影响可在归因分析中查看 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') # 初始化全局变量 g.no_trading_today_signal = False g.market_temperature = "warm" g.stock_num = 3 g.highest = 50 g.buy_stock_count = 5 g.hold_list = [] # 当前持仓的全部股票 g.yesterday_HL_list = [] # 记录持仓中昨日涨停的股票 g.bought_stocks = {} #记录补跌的股票和金额 g.foreign_ETF = [ '518880.XSHG', # 黄金ETF '513030.XSHG', # 德国ETF '513100.XSHG', # 纳指ETF '164824.XSHE', # 印度LOF '159866.XSHE', # 日经ETF ] # 设置交易运行时间 run_daily(prepare_stock_list, '9:05') run_monthly(singal, 1, '9:00') run_weekly(clear, 1, '9:30') run_weekly(monthly_adjustment, 1, '9:30') run_daily(stop_loss, '14:00') def clear(context):#卖出补跌的仓位 log.info(f"g.bought_stocks: {g.bought_stocks}") if g.bought_stocks!={}: for stock, amount in g.bought_stocks.items(): if stock in context.portfolio.positions: order_value(stock, -amount) # 卖出股票至目标价值为0 log.info("Sell cover stocks: %s, value: %s" % (stock, amount)) # 清空记录 g.bought_stocks.clear() def prepare_stock_list(context): """ 准备每日股票列表,包括持仓股票列表和昨日涨停股票列表。 1. 遍历当前持仓中的所有股票,将其加入到 g.hold_list 中。 2. 如果持仓列表不为空: - 获取持仓股票在前一个交易日的收盘价和涨停价。 - 过滤出收盘价等于涨停价的股票,存入昨日涨停列表 g.yesterday_HL_list。 3. 如果持仓列表为空,昨日涨停列表 g.yesterday_HL_list 也置为空。 返回: - g.hold_list: 持仓股票清单 - g.yesterday_HL_list: 持仓的昨日涨停清单 """ log.info('Daily run is enabled') # 获取已持有列表 g.hold_list = [] for position in list(context.portfolio.positions.values()): stock = position.security g.hold_list.append(stock) log.info(f"Day position {len(g.hold_list)}:{g.hold_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.yesterday_HL_list = list(df.code) else: g.yesterday_HL_list = [] def stop_loss(context): """ 执行止损策略,根据条件卖出股票或进行补仓。 1. 初始化计数器 num 用于记录卖出股票的数量和获取当前时间 now_time。 2. 如果昨日涨停列表 g.yesterday_HL_list 不为空: - 对于每只昨日涨停的股票,获取当前价格和涨停价。 - 如果当前价格低于涨停价,打印日志信息并卖出该股票,计数器 num 加1。 - 如果当前价格等于涨停价,打印日志信息并继续持有该股票。 3. 初始化两个列表 SS 和 S 用于记录持仓股票的跌幅。 4. 遍历持仓列表 g.hold_list: - 如果股票在当前持仓中,并且当前价格低于平均成本价的92%,执行止损卖出操作,计数器 num 加1。 - 否则,将股票加入列表 S,并计算当前价格相对于平均成本价的涨跌幅,存入 SS。 5. 如果有股票被止损卖出(num >= 1),且 SS 列表不为空: - 重置 num 为3。 - 找出 SS 中跌幅最大的 num 支股票。 - 计算每只股票的补仓金额为当前现金除以 num。 - 对于跌幅最大的股票,执行补仓操作,并记录日志信息。如果股票不在已买入列表 g.bought_stocks 中,更新其买入金额。 """ num = 0 now_time = context.current_dt if g.yesterday_HL_list != []: # 对昨日涨停股票观察到尾盘如不涨停则提前卖出,如果涨停即使不在应买入列表仍暂时持有 for stock in g.yesterday_HL_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]Limit ends, sell" % (stock)) position = context.portfolio.positions[stock] close_position(position) num = num+1 else: log.info("[%s]Limit continues, continue to hold" % (stock)) SS=[] S=[] for stock in g.hold_list: if stock in list(context.portfolio.positions.keys()): if context.portfolio.positions[stock].price < context.portfolio.positions[stock].avg_cost * 0.92: order_target_value(stock, 0) log.info("Loss control: Selling out %s" % (stock)) num = num+1 else: S.append(stock) NOW = (context.portfolio.positions[stock].price - context.portfolio.positions[stock].avg_cost)/context.portfolio.positions[stock].avg_cost SS.append(np.array(NOW)) else: log.info(f"stop_loss else after for loop, num: {num}, SS: {len(SS)}") if num >=1: if len(SS) > 0: # 清空记录 num=3 min_values = sorted(SS)[:num] min_indices = [SS.index(value) for value in min_values] min_strings = [S[index] for index in min_indices] log.info(f"Need to cover positions are min_strings: {min_strings}, min_indices: {min_indices}") cash = context.portfolio.cash/num for ss in min_strings: cover_order = order_value(ss, cash) if cover_order: log.info("Cover the n that fell the most with Order %s and %.2f" % (ss, cash)) log.debug(f"cover_order: {cover_order}") amount = cover_order.amount log.debug(f"amount: {type(amount)}, {amount}") if ss not in g.bought_stocks: g.bought_stocks[ss] = amount else: g.bought_stocks[ss] = amount + g.bought_stocks[ss] log.info(f"g.bought_stocks: {g.bought_stocks}") def filter_roic(context,stock_list): """ 根据最近一期的ROIC(投入资本回报率)过滤股票列表。 1. 获取前一个交易日的日期。 2. 遍历输入的股票列表 stock_list,对于每只股票: - 获取该股票最近一期的 ROIC 值。 - 如果 ROIC 大于 0.08,将该股票添加到 list 中。 """ yesterday = context.previous_date list=[] for stock in stock_list: roic=get_factor_values(stock, 'roic_ttm', end_date=yesterday,count=1)['roic_ttm'].iloc[0,0] if roic>0.08: list.append(stock) return list def filter_highprice_stock(context,stock_list): # 过滤出最近一分钟的收盘价低于10元的股票,或当前已持有的股票。 last_prices = history(1, unit='1m', field='close', security_list=stock_list) return [stock for stock in stock_list if stock in context.portfolio.positions.keys() or last_prices[stock][-1] < 10] def filter_highprice_stock2(context,stock_list): # 过滤出最近一分钟的收盘价低于300元的股票,或当前已持有的股票。 last_prices = history(1, unit='1m', field='close', security_list=stock_list) return [stock for stock in stock_list if stock in context.portfolio.positions.keys() or last_prices[stock][-1] < 300] def get_recent_limit_up_stock(context, stock_list, recent_days): # 获取最近指定天数内出现过涨停的股票。 stat_date = context.previous_date new_list = [] for stock in stock_list: df = get_price(stock, end_date=stat_date, frequency='daily', fields=['close','high_limit'], count=recent_days, panel=False, fill_paused=False) df = df[df['close'] == df['high_limit']] if len(df) > 0: new_list.append(stock) return new_list def get_recent_down_up_stock(context, stock_list, recent_days): """获取最近指定天数内出现过跌停的股票。""" stat_date = context.previous_date new_list = [] for stock in stock_list: df = get_price(stock, end_date=stat_date, frequency='daily', fields=['close','low_limit'], count=recent_days, panel=False, fill_paused=False) df = df[df['close'] == df['low_limit']] if len(df) > 0: new_list.append(stock) return new_list #1-2 选股模块 def get_stock_list(context): """ 小市值选股逻辑: 针对399101里的股票,过滤次新、科创北交、st,先获取实质5-30的最小市值100支股票 再过滤掉停牌、当前涨停和跌停的股票 最后获得市值最小的50支股票 """ final_list = [] MKT_index = '399101.XSHE' initial_list = get_index_stocks(MKT_index) initial_list = filter_new_stock(context, initial_list) initial_list = filter_kcbj_stock(initial_list) initial_list = filter_st_stock(initial_list) q = query(valuation.code,valuation.market_cap).filter(valuation.code.in_(initial_list),valuation.market_cap.between(5,30)).order_by(valuation.market_cap.asc()) df_fun = get_fundamentals(q) df_fun = df_fun[:100] initial_list = list(df_fun.code) initial_list = filter_paused_stock(initial_list) initial_list = filter_limitup_stock(context, initial_list) initial_list = filter_limitdown_stock(context, initial_list) #log.info('initial_list has {} stocks'.format(len(initial_list))) q = query(valuation.code,valuation.market_cap).filter(valuation.code.in_(initial_list)).order_by(valuation.market_cap.asc()) df_fun = get_fundamentals(q) df_fun = df_fun[:50] final_list = list(df_fun.code) return final_list #1-2 选股模块 def get_stock_list_2(context): """ 1. 获取综小中指的成分股 initial_list。 2. 对 initial_list 进行一系列过滤操作: - 过滤掉新股。 - 过滤掉科创北交股票。 - 过滤掉ST股票。 5. 构建查询条件 q,筛选出符合以下条件的股票: - 股票代码在 initial_list 中。 - 总市值在5亿到30亿之间。 - 归属于母公司所有者的净利润为正。 - 净利润为正。 - 营业收入大于1亿。 6. 按总市值升序排序,限制返回最多50只股票。 7. 获取基本面数据 df,并从中提取股票代码列表 final_list。 8. 获取 final_list 中股票最近一天的收盘价。 9. 返回符合以下条件的股票列表: - 当前持有的股票。 - 最近一天收盘价不高于全局变量 g.highest 的股票。 """ final_list = [] MKT_index = '399101.XSHE' initial_list = get_index_stocks(MKT_index) initial_list = filter_new_stock(context, initial_list) initial_list = filter_kcbj_stock(initial_list) initial_list = filter_st_stock(initial_list) # 国九更新:过滤近一年净利润为负且营业收入小于1亿的 # 国九更新:过滤近一年期末净资产为负的 (经查询没有为负数的,所以直接pass这条) # 国九更新:过滤近一年审计建议无法出具或者为负面建议的 (经过净利润等筛选,审计意见几乎不会存在异常) q = query( valuation.code, valuation.market_cap, # 总市值 circulating_market_cap/market_cap income.np_parent_company_owners, # 归属于母公司所有者的净利润 income.net_profit, # 净利润 income.operating_revenue # 营业收入 #security_indicator.net_assets ).filter( valuation.code.in_(initial_list), valuation.market_cap.between(5,30), income.np_parent_company_owners > 0, income.net_profit > 0, income.operating_revenue > 1e8 ).order_by(valuation.market_cap.asc()).limit(50) df = get_fundamentals(q) final_list = list(df.code) last_prices = history(1, unit='1d', field='close', security_list=final_list) return [stock for stock in final_list if stock in g.hold_list or last_prices[stock][-1] <= g.highest] def SMALL(context, choice): """ 获取经过多重筛选后的股票列表,并根据财务指标进行进一步筛选。 1. 获取两组初步筛选的股票列表 target_list_1 和 target_list_2。 2. 合并去重这两组股票列表,得到 target_list。 3. 限制 target_list 的长度为全局变量 g.stock_num 的三倍。 4. 构建查询条件,筛选出符合以下条件的股票: - 股票代码在 target_list 中。 - 按总市值升序排序。 5. 获取基本面数据,并提取股票代码列表 final_list。 6. 返回最终筛选的股票列表 final_list。 """ target_list_1 = get_stock_list(context) target_list_2 = get_stock_list_2(context) target_list= list(dict.fromkeys(target_list_1 + target_list_2)) target_list=target_list[:g.stock_num*3] #target_list = get_stock_list_2(context)[:g.stock_num*3] final_list = get_fundamentals(query( valuation.code, indicator.roe, indicator.roa, ).filter( valuation.code.in_(target_list), #valuation.pb_ratio<1 ).order_by( valuation.market_cap.asc() )).set_index('code').index.tolist() return final_list def singal(context): """ 1. 首先获得B_stocks,沪深300指数的成分股和S_stocks,中小综指的成分股,去掉科创北上、st、次新股 2. 从B_stocks当中获得市值最大的20支股,从S_stocks当中获得市值最小的20支股 3. 针对B_stocks和S_stocks,使用最新的价格和过去的价格比值*100,各自获得一个平均值B_mean,S_mean 4. g.signal的4种情况 - B_mean>S_mean且B_mean>5:small - B_mean>S_mean且5>=B_mean>0:big - B_mean0:small - 所有其他:etf (黄金或外盘) 返回: - g.singal: small, big, etf三种投资标的的选择 """ today = context.current_dt dt_last = context.previous_date N=10 B_stocks = get_index_stocks('000300.XSHG', dt_last) B_stocks = filter_kcbj_stock(B_stocks) B_stocks = filter_st_stock(B_stocks) B_stocks = filter_new_stock(context, B_stocks) S_stocks = get_index_stocks('399101.XSHE', dt_last) S_stocks = filter_kcbj_stock(S_stocks) S_stocks = filter_st_stock(S_stocks) S_stocks = filter_new_stock(context, S_stocks) q = query( valuation.code, valuation.circulating_market_cap ).filter( valuation.code.in_(B_stocks) ).order_by( valuation.circulating_market_cap.desc() ) df = get_fundamentals(q, date=dt_last) Blst = list(df.code)[:20] q = query( valuation.code, valuation.circulating_market_cap ).filter( valuation.code.in_(S_stocks) ).order_by( valuation.circulating_market_cap.asc() ) df = get_fundamentals(q, date=dt_last) Slst = list(df.code)[:20] # B_ratio = get_price(Blst, end_date=dt_last, frequency='1d', fields=['close'], count=N, panel=False ).pivot(index='time', columns='code', values='close') change_BIG = (B_ratio.iloc[-1] / B_ratio.iloc[0] - 1) * 100 A1 = np.array(change_BIG) A1 = np.nan_to_num(A1) B_mean = np.mean(A1) # log.info(f"B_ratio: {B_ratio}") # log.info(f"change_BIG: {change_BIG}") # log.info(f"A1: {A1}") # log.info(f"B_mean: {B_mean}") S_ratio = get_price(Slst, end_date=dt_last, frequency='1d', fields=['close'], count=N, panel=False ).pivot(index='time', columns='code', values='close') change_SMALL = (S_ratio.iloc[-1] / S_ratio.iloc[0] - 1) * 100 A1 = np.array(change_SMALL) A1 = np.nan_to_num(A1) S_mean = np.mean(A1) if B_mean>S_mean and B_mean>0: if B_mean>5: g.signal='small' log.info('Big has ended, change to Small') else: g.signal='big' log.info('Big') elif B_mean < S_mean and S_mean > 0: g.signal='small' log.info('Small') else: log.info('Foreign') g.signal='etf' # 1-3 整体调整持仓 def monthly_adjustment(context): """ 每月(目前是每周)进行整体持仓调整,根据市场信号调整股票组合,进行买入和卖出操作。 1. 根据全局信号 g.signal 确定调整策略: - 如果信号为 'big',调用 White_Horse 方法获取大市值股票的目标列表。 - 如果信号为 'small',从中小综指获取成分股,过滤掉科创板、ST和次新股后,调用 SMALL 方法获取小市值股票的目标列表。 - 如果信号为 'etf',使用全局变量 g.foreign_ETF 作为目标列表。 - 如果信号不在预期范围内,打印提示信息。 5. 打印目标股票列表 target_list。 6. 对目标列表进行进一步的过滤: - 使用 filter_limitup_stock 过滤掉涨停的股票。 - 使用 filter_limitdown_stock 过滤掉跌停的股票。 - 使用 filter_paused_stock 过滤掉停牌的股票。 7. 遍历当前持仓的股票 g.hold_list: - 对于不在目标列表和昨日持仓列表 g.yesterday_HL_list 中的股票,平掉其仓位。 8. 获取当前持仓数量 position_count 和目标股票数量 target_num。 9. 如果目标股票数量大于当前持仓数量: - 计算每个新股票的投资金额 value 为当前现金除以新增目标股票数量。 - 遍历目标股票列表 target_list,对于未持有的股票,尝试开仓。 - 如果开仓成功且持仓数量达到目标数量,停止操作。 """ log.info("Make weekly overall position adjustments") today = context.current_dt dt_last = context.previous_date target_list=[] log.info(f"g.signal: {g.signal}") if g.signal=='big': target_list = White_Horse(context) elif g.signal=='small': S_stocks = get_index_stocks('399101.XSHE', dt_last) S_stocks = filter_kcbj_stock(S_stocks) S_stocks = filter_st_stock(S_stocks) S_stocks = filter_new_stock(context, S_stocks) choice = S_stocks target_list = SMALL(context,choice) elif g.signal=='etf': target_list = g.foreign_ETF else: log.info("g.signal is not the one expected") log.info(f"target_list before filter: {target_list}") target_list = filter_limitup_stock(context,target_list) target_list = filter_limitdown_stock(context,target_list) target_list = filter_paused_stock(target_list) log.info(f"target_list after filter: {target_list}") # target_list = target_list[:5] # 可以控制持股数量到5 for stock in g.hold_list: if (stock not in target_list) and (stock not in g.yesterday_HL_list): position = context.portfolio.positions[stock] close_position(position) position_count = len(context.portfolio.positions) target_num = len(target_list) if target_num > position_count: value = context.portfolio.cash / (target_num - position_count) for stock in target_list: if stock not in list(context.portfolio.positions.keys()): if open_position(stock, value): if len(context.portfolio.positions) == target_num: break def boll_filter(stocks,date): """ 使用布林带策略过滤股票列表,返回符合条件的股票。 1. 获取指定日期 date 的股票数据,包括高价、高价和收盘价。 - 使用 get_bars 函数获取 stocks 列表中每只股票的最近一天数据。 - 将数据的索引设置为股票代码。 2. 计算布林带指标: - 使用 Bollinger_Bands 函数计算上轨(upperband)、中轨(middleband)和下轨(lowerband)。 - 参数设置为:时间周期为20,标准差倍数为2,单位为每日。 3. 将布林带指标结果添加到数据框 x 中: - 将 upperband、middleband 和 lowerband 的结果分别存储到 x 数据框中的 'up'、'mid' 和 'lowe' 列。 4. 过滤符合条件的股票: - 筛选出收盘价低于上轨且最低价高于下轨的股票。 - 这些股票符合布林带策略的买入信号。 5. 返回符合条件的股票代码列表。 参数: - stocks: 股票代码列表。 - date: 筛选的日期。 返回: - 符合布林带策略条件的股票代码列表。 """ x=get_bars(stocks, 1, unit='1d', fields=['high','low','close'],end_dt=date,df=True) x.index=stocks upperband, middleband, lowerband=Bollinger_Bands(stocks, date, timeperiod=20, nbdevup=2, nbdevdn=2, unit = '1d', include_now = True, fq_ref_date = None) log.info(f"result for bollinger_bands, upperband: {type(upperband)}, {upperband}; middleband: {type(middleband)}, {middleband}; lowerband: {type(lowerband)}, {lowerband}") x['up']= pd.DataFrame(upperband, index=[0]).T.values x['mid']=pd.DataFrame(middleband, index=[0]).T.values x['lowe']=pd.DataFrame(lowerband, index=[0]).T.values x=x[(x['close'] 0: return True return False # 3-3 交易模块-平仓 def close_position(position): security = position.security order = order_target_value_(security, 0) # 可能会因停牌失败 if order != None: if order.status == OrderStatus.held and order.filled == order.amount: return True return False 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 and 'ST' not in current_data[stock].name and '*' not in current_data[stock].name and '退' not in current_data[stock].name] # 2-3 过滤科创北交股票 def filter_kcbj_stock(stock_list): for stock in stock_list[:]: if stock[0] == '4' or stock[0] == '8' or stock[:2] == '68' or stock[0] == '3': stock_list.remove(stock) return stock_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_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=375)] ## 开盘前运行函数 def White_Horse(context): """ 该方法根据市场温度筛选出符合特定财务指标的股票列表。 1. 首先调用 Market_temperature 函数获取市场温度。 2. 初始化一个空列表 check_out_lists 用于存储筛选出的股票。 3. 获取当前的股票数据 current_data,以及200天前的所有股票列表 all_stocks。 4. 将 all_stocks 更新为沪深300指数的成分股。 5. 根据以下条件过滤股票: - 排除涨停或跌停开盘的股票。 - 排除停牌的股票。 - 排除 ST、*ST、退市风险股。 - 排除创业板、科创板、北交所的股票。 6. 根据市场温度(冷、暖、热)设置不同的筛选条件和排序规则: - 冷:筛选市净率(PB)在0到1之间,经营活动现金流入大于0,调整后利润大于0,现金流入与调整后利润比大于2.0,收益增长率大于1.5,净利润同比增长率大于-15的股票,并按 ROA/PB 降序排列。 - 暖:筛选市净率(PB)在0到1之间,经营活动现金流入大于0,调整后利润大于0,现金流入与调整后利润比大于1.0,收益增长率大于2.0,净利润同比增长率大于0的股票,并按 ROA/PB 降序排列。 - 热:筛选市净率(PB)大于3,经营活动现金流入大于0,调整后利润大于0,现金流入与调整后利润比大于0.5,收益增长率大于3.0,净利润同比增长率大于20的股票,并按 ROA 降序排列。 7. 将符合条件的股票代码存入 check_out_lists。 8. 返回筛选出的股票列表 check_out_lists,并记录日志信息。 """ Market_temperature(context) log.info(f"This month's temperature is:{g.market_temperature}") check_out_lists = [] current_data = get_current_data() check_date = context.previous_date - datetime.timedelta(days=200) # all_stocks = list(get_all_securities(date=check_date).index) # log.info(f"first all_stocks: {len(all_stocks)}, {all_stocks}") all_stocks = get_index_stocks("000300.XSHG") # log.info(f"second all_stocks: {len(all_stocks)}, {all_stocks}") # 过滤创业板、ST、停牌、当日涨停 all_stocks = [stock for stock in all_stocks if not ( (current_data[stock].day_open == current_data[stock].high_limit) or # 涨停开盘 (current_data[stock].day_open == current_data[stock].low_limit) or # 跌停开盘 current_data[stock].paused or # 停牌 current_data[stock].is_st or # ST ('ST' in current_data[stock].name) or ('*' in current_data[stock].name) or ('退' in current_data[stock].name) or (stock.startswith('30')) or # 创业 (stock.startswith('68')) or # 科创 (stock.startswith('8')) or # 北交 (stock.startswith('4')) # 北交 )] if g.market_temperature == "cold": q = query( valuation.code, ).filter( valuation.pb_ratio > 0, valuation.pb_ratio < 1, cash_flow.subtotal_operate_cash_inflow > 0, indicator.adjusted_profit > 0, cash_flow.subtotal_operate_cash_inflow/indicator.adjusted_profit>2.0, indicator.inc_return > 1.5, indicator.inc_net_profit_year_on_year > -15, valuation.code.in_(all_stocks) ).order_by( (indicator.roa/valuation.pb_ratio).desc() ).limit( g.buy_stock_count + 1 ) elif g.market_temperature == "warm": q = query( valuation.code, ).filter( valuation.pb_ratio > 0, valuation.pb_ratio < 1, cash_flow.subtotal_operate_cash_inflow > 0, indicator.adjusted_profit > 0, cash_flow.subtotal_operate_cash_inflow/indicator.adjusted_profit>1.0, indicator.inc_return > 2.0, indicator.inc_net_profit_year_on_year > 0, valuation.code.in_(all_stocks) ).order_by( (indicator.roa/valuation.pb_ratio).desc() ).limit( g.buy_stock_count + 1 ) elif g.market_temperature == "hot": q = query( valuation.code, ).filter( valuation.pb_ratio > 3, cash_flow.subtotal_operate_cash_inflow > 0, indicator.adjusted_profit > 0, cash_flow.subtotal_operate_cash_inflow/indicator.adjusted_profit>0.5, indicator.inc_return > 3.0, indicator.inc_net_profit_year_on_year > 20, valuation.code.in_(all_stocks) ).order_by( indicator.roa.desc() ).limit( g.buy_stock_count + 1 ) check_out_lists = list(get_fundamentals(q).code) # 取需要的只数 #check_out_lists = check_out_lists[:g.buy_stock_count] log.info("Today's stock pool:%s" % check_out_lists) return check_out_lists # tttttttttttt def Market_temperature(context): """ 根据沪深300过去220天的收盘价,计算一个权重market_height: (最新5个的平均值-最小值)/(最大值-最小值) - 冷:market_height小于0.2,temp为200 - 热:market_height大于0.9,temp为400 - 温:最新60个的平均值/最小值>1.2,temp为300 """ index300 = attribute_history('000300.XSHG', 220, '1d', ('close'), df=False)['close'] market_height = (mean(index300[-5:]) - min(index300)) / (max(index300) - min(index300)) if market_height < 0.20: g.market_temperature = "cold" elif market_height > 0.90: g.market_temperature = "hot" elif max(index300[-60:]) / min(index300) > 1.20: g.market_temperature = "warm" if g.market_temperature == "cold": temp = 200 elif g.market_temperature == "warm": temp = 300 else: temp = 400 if context.run_params.type != 'sim_trade': # 不是模拟交易 record(temp=temp)