量化学习平台
文章
市场宽度
背离图
登录
注册
高收益低回撤的小市值策略
策略
作者: 水滴
```python # 风险及免责提示:该策略由聚宽用户分享,仅供学习交流使用。 # 原文一般包含策略说明,如有疑问建议到原文和作者交流讨论。 # 克隆自聚宽文章:https://www.joinquant.com/post/28824 # 标题:高收益低回撤的小市值策略 # 作者:曹经纬 # 导入函数库 from jqdata import * from kuanke.wizard import * # 初始化函数,设定基准等等 def initialize(context): # 设定沪深300作为基准 set_benchmark('000300.XSHG') # 开启动态复权模式(真实价格) set_option('use_real_price', True) # 输出内容到日志 log.info() log.info('初始函数开始运行且全局只运行一次') # 过滤掉order系列API产生的比error级别低的log log.set_level('order', 'error') # 股票池 g.security_universe_index = "399101.XSHE" # 中小板 g.buy_stock_count = 5 g.risk_control = RiskControl('000300.XSHG') ### 股票相关设定 ### # 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱 set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock') ## 运行函数(reference_security为运行时间的参考标的;传入的标的只做种类区分,因此传入'000300.XSHG'或'510300.XSHG'是一样的) # 定时运行 run_daily(my_trade, time='14:40', reference_security='000300.XSHG') # 收盘后运行 run_daily(after_market_close, time='after_close', reference_security='000300.XSHG') ## 开盘时运行函数 def my_trade(context): # 选取中小板中市值最小的若干只 check_out_lists = get_index_stocks(g.security_universe_index) q = query(valuation.code).filter( valuation.circulating_market_cap < 100 ).filter( valuation.code.in_(check_out_lists) ).order_by( valuation.circulating_market_cap.asc() ).limit( int(g.buy_stock_count * 2.0) ) check_out_lists = list(get_fundamentals(q).code) # 过滤: 三停(停牌、涨停、跌停)及st,*st,退市 check_out_lists = filter_st_stock(check_out_lists) check_out_lists = filter_limitup_stock(context, check_out_lists) check_out_lists = filter_limitdown_stock(context, check_out_lists) check_out_lists = filter_paused_stock(check_out_lists) # 取需要的只数 check_out_lists = check_out_lists[:g.buy_stock_count] # 买卖 adjust_position(context, check_out_lists) ## 收盘后运行函数 def after_market_close(context): log.info(str('函数运行时间(after_market_close):' + str(context.current_dt.time()))) # 得到当天所有成交记录 trades = get_trades() for _trade in trades.values(): log.info('成交记录:' + str(_trade)) log.info('一天结束') log.info('##############################################################') # 自定义下单 # 根据Joinquant文档,当前报单函数都是阻塞执行,报单函数(如order_target_value)返回即表示报单完成 # 报单成功返回报单(不代表一定会成交),否则返回None 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)) # 如果股票停牌,创建报单会失败,order_target_value 返回None # 如果股票涨跌停,创建报单会成功,order_target_value 返回Order,但是报单会取消 # 部成部撤的报单,聚宽状态是已撤,此时成交量>0,可通过成交量判断是否有成交 return order_target_value(security, value) # 开仓,买入指定价值的证券 # 报单成功并成交(包括全部成交或部分成交,此时成交量大于0),返回True # 报单失败或者报单成功但被取消(此时成交量等于0),返回False def open_position(security, value): order = order_target_value_(security, value) if order != None and order.filled > 0: return True return False # 平仓,卖出指定持仓 # 平仓成功并全部成交,返回True # 报单失败或者报单成功但被取消(此时成交量等于0),或者报单非全部成交,返回False 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 adjust_position(context, buy_stocks): if not check_for_benchmark(context): for stock in context.portfolio.positions: position = context.portfolio.positions[stock] close_position(position) return for stock in context.portfolio.positions: if stock not in buy_stocks: log.info("stock [%s] in position is not buyable" % (stock)) position = context.portfolio.positions[stock] close_position(position) else: log.info("stock [%s] is already in position" % (stock)) # 根据股票数量分仓 # 此处只根据可用金额平均分配购买,不能保证每个仓位平均分配 position_count = len(context.portfolio.positions) if g.buy_stock_count > position_count: value = context.portfolio.cash / (g.buy_stock_count - position_count * 0.33) #value = context.portfolio.cash / g.buy_stock_count for stock in buy_stocks: if context.portfolio.positions[stock].total_amount == 0: if open_position(stock, value): if len(context.portfolio.positions) == g.buy_stock_count: break # 过滤停牌股票 def filter_paused_stock(stock_list): current_data = get_current_data() return [stock for stock in stock_list if not current_data[stock].paused] # 过滤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] # 过滤涨停的股票 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] # return [stock for stock in stock_list if stock in context.portfolio.positions.keys() # or last_prices[stock][-1] < current_data[stock].high_limit * 0.995] # 过滤跌停的股票 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] #自定义函数 def check_for_benchmark(context): #security = '000300.XSHG' #could_trade1 = RSI_judge_qujian(security, (50,99), 15) #could_trade2 = RSI_judge_qujian(security, (50,99), 90) #could_trade3 = RSI_judge_qujian(security, (47,99), 60) #return (could_trade1 and could_trade2) or could_trade3 return g.risk_control.check_for_benchmark(context) #============================================================================================ class RiskControlStatus(Enum): RISK_WARNING = 1 RISK_NORMAL = 2 class RiskControl(object): def __init__(self, symbol): self.symbol = symbol self.status = RiskControlStatus.RISK_NORMAL def check_for_ma_rate(self, period, ma_rate_min, ma_rate_max, show_ma_rate): ma_rate = self.compute_ma_rate(period, show_ma_rate) return (ma_rate_min < ma_rate < ma_rate_max) def compute_ma_rate(self, period, show_ma_rate): #hst = attribute_history(self.symbol, period, '1d', ['close']) hst = get_bars(self.symbol, period, '1d', ['close']) close_list = hst['close'] if (len(close_list) == 0): return -1.0 if (math.isnan(close_list[0]) or math.isnan(close_list[-1])): return -1.0 period = min(period, len(close_list)) if (period < 2): return -1.0 #ma = close_list.sum() / len(close_list) ma = talib.MA(close_list, timeperiod=period)[-1] ma_rate = hst['close'][-1] / ma if (show_ma_rate): record(mar=ma_rate) return ma_rate def check_for_rsi(self, period, rsi_min, rsi_max, show_rsi): hst = attribute_history(self.symbol, period + 1, '1d', ['close']) close = [float(x) for x in hst['close']] if (math.isnan(close[0]) or math.isnan(close[-1])): return False rsi = talib.RSI(np.array(close), timeperiod=period)[-1] if (show_rsi): record(RSI=max(0,(rsi-50))) return (rsi_min < rsi < rsi_max) def check_for_benchmark_v1(self, context): could_trade_ma_rate = self.check_for_ma_rate(10000, 0.75, 1.50, True) could_trade = False if (could_trade_ma_rate): could_trade = self.check_for_rsi(90, 35, 99, False) else: could_trade = self.check_for_rsi(15, 50, 70, False) return could_trade def check_for_benchmark(self, context): ma_rate = self.compute_ma_rate(1000, False) if (ma_rate <= 0.0): return False if (self.status == RiskControlStatus.RISK_NORMAL): if ((ma_rate > 2.5) or (ma_rate < 0.30)): self.status = RiskControlStatus.RISK_WARNING elif (self.status == RiskControlStatus.RISK_WARNING): if (0.35 <= ma_rate <= 0.7): self.status = RiskControlStatus.RISK_NORMAL could_trade = False if (self.status == RiskControlStatus.RISK_WARNING): #if (self.status == RiskControlStatus.RISK_WARNING) or not(self.check_for_usa_intrest_rate(context)): #could_trade = self.check_for_rsi(15, 55, 90, False) and self.check_for_rsi(90, 50, 90, False) could_trade = self.check_for_rsi(60, 47, 99, False) #record(status=2.5) elif (self.status == RiskControlStatus.RISK_NORMAL): #could_trade = self.check_for_rsi(60, 50, 99, False) could_trade = True #record(status=0.7) return could_trade ```
文章分类
关于作者
水滴
注册时间: