量化学习平台
文章
市场宽度
背离图
登录
注册
北向Boll带_ETF组合宝付费策略
策略
作者: 水滴
```python # 风险及免责提示:该策略由聚宽用户在聚宽社区分享,仅供学习交流使用。 # 原文一般包含策略说明,如有疑问请到原文和作者交流讨论。 # 原文网址:https://www.joinquant.com/post/30461 # 标题:北向Boll带_ETF组合宝付费策略 # 作者:Funine # 克隆自聚宽文章:https://www.joinquant.com/post/27351 # 标题:6年14倍的etf分级基金的轮动策略 # 作者:大吃一鲸 from jqdata import * import pandas as pd import talib ''' 原理:在8个种类的ETF中,持仓三个,ETF池相应的指数分别是 '159915.XSHE' #创业板、 '159949.XSHE' #创业板50 '510300.XSHG' #沪深300 '510500.XSHG' #中证500 '510880.XSHG' #红利ETF '159905.XSHE' #深红利 '510180.XSHG' #上证180 '510050.XSHG' #上证50 持仓原则: 1、对泸深指数的成交量进行统计,如果连续6(lag)天成交量小于7(lag0)天成交量的,空仓处理(购买货币基金511880 银华日利或国债 511010 ) 2、13个交易日内(lag1)涨幅大于1的,并且“均线差值”大于0的才进行考虑。 3、对符合考虑条件的ETF的涨幅进行排序,买涨幅最高的三个。 ''' def initialize(context): set_params() # set_option("avoid_future_data",True) set_option('use_real_price', True) # 用真实价格交易 set_benchmark('000300.XSHG') log.set_level('order', 'error') # # 将滑点设置为0 set_slippage(FixedSlippage(0.001)) # 手续费: 采用系统默认设置 set_order_cost(OrderCost(close_tax=0.00, open_commission=0.0001, close_commission=0.0001, min_commission=5), type='stock') # 开盘前运行 run_daily(before_market_open, time='before_open', reference_security='000300.XSHG') # 11:30 计算大盘信号 run_daily(get_signal, time='14:10') # 获取北向资金 run_daily(trade,time='11:30') # 14:40 进行交易 run_daily(ETFtrade, time='14:11') # 1 设置参数 def set_params(): g.use_dynamic_target_market = True # 是否动态改变大盘热度参考指标 # g.target_market = '000300.XSHG' g.target_market = '000300.XSHG' g.empty_keep_stock = '511880.XSHG' # 闲时买入的标的 # g.empty_keep_stock = '601318.XSHG'#闲时买入的标的 g.signal = 'BUY' # 交易信号初始化 g.emotion_rate = 0 # 市场热度q g.lag = 6 # 大盘成交量连续跌破均线的天数,发出空仓信号 g.lag0 = 7 # 大盘成交量监控周期 g.lag1 = 15 # 比价均线周期 g.lag2 = 15 # 价格涨幅计算周期 g.north_money = 0 # g.buy = [] # 购买股票列表 g.ETFList = [] g.boll252 = [] g.boll150 = [] g.boll80 = [] g.boll20 = [] def get_before_after_trade_days(date, count, is_before=True): """ 来自: https://www.joinquant.com/view/community/detail/c9827c6126003147912f1b47967052d9?type=1 date :查询日期 count : 前后追朔的数量 is_before : True , 前count个交易日 ; False ,后count个交易日 返回 : 基于date的日期, 向前或者向后count个交易日的日期 ,一个datetime.date 对象 """ all_date = pd.Series(get_all_trade_days()) if isinstance(date, str): date = datetime.datetime.strptime(date, '%Y-%m-%d').date() if isinstance(date, datetime.datetime): date = date.date() if is_before: return all_date[all_date <= date].tail(count).values[0] else: return all_date[all_date >= date].head(count).values[-1] def before_market_open(context): # 确保交易标的已经上市g.lag1个交易日以上 ETF_targets = [ #'399001.XSHE' :'150019.XSHE',#银华锐进 #'159902.XSHE',#中小板指 #'512880.XSHG',#券商B '159901.XSHE',#深100etf '162605.XSHE',#景顺鼎益 '510050.XSHG',#上证50 #'510180.XSHG',#上证180 '510880.XSHG',#红利ETF '159905.XSHE',#深红利 '159915.XSHE',#创业板 '510300.XSHG',#沪深300 '510500.XSHG',#中证500 '159949.XSHE',#创业板50 # '515700.XSHG',# 新能车etf # '512660.XSHG',# 军工etf # '512010.XSHG',# 医药etf # '512290.XSHG',# 生物医药etf #'518800.XSHG',# 黄金基金 # '512690.XSHG',#白酒 # '159928.XSHE',#消费 '161903.XSHE',#万家 '161005.XSHE',#富国 # '163417.XSHE',#兴全合一 # '163402.XSHE',#兴全 #'163415.XSHE',#兴全模式 #'512760.XSHG',#半导体50 #'159996.XSHE',#家用电器 #'159995.XSHE',#芯片 #'161226.XSHE',#白银 #'515000.XSHG',#科技 #'512800.XSHG',#银行 #'512720.XSHG',#计算机 #'512400.XSHG',#有色 #'515050.XSHG',#通信 #'588000.XSHG',#科创50 #'501054.XSHG',#东征睿泽 #'510900.XSHG',#H股ETF #'162703.XSHE',#广发小盘 #'159920.XSHE',#恒生 #'513500.XSHG',#标普500 #'515220.XSHG',#煤炭 #'159966.XSHE',#创蓝筹 #'159941.XSHE',#纳指 # '512200.XSHG',#房地产 # '512170.XSHG',#医疗 #'515900.XSHG',#央创 #'512960.XSHG',#央调 #'512980.XSHG',#传媒 #'159967.XSHE',#创成长 #'159997.XSHE',#电子 #'159959.XSHE',#央企 #'159819.XSHE',#人工智能 # '515210.XSHG',#钢铁 # '159807.XSHE',#科技 ] yesterday = context.previous_date list_date = get_before_after_trade_days(yesterday, g.lag1) # 今天的前g.lag1个交易日的日期 g.ETFList = [] all_funds = get_all_securities(types='fund', date=yesterday) # 上个交易日之前上市的所有基金 for symbol in ETF_targets: if symbol in all_funds.index: if all_funds.loc[symbol].start_date <= list_date: # 对应的基金也已经在要求的日期前上市 g.ETFList.append(symbol) # 则列入可交易对象中 # 创建保持计算结果的DataFrame df_etf = pd.DataFrame(columns=['基金代码', '对应名称', '周期涨幅', '均线差值']) current_data = get_current_data() for mkt_idx in g.ETFList: security = mkt_idx # 指数对应的基金 # 获取股票的收盘价 close_data = attribute_history(security, g.lag1, '1d', ['close'], df=False) # 获取股票现价 current_price = current_data[security].last_price #current_price = attribute_history(security, 1 , '1m', ['close'], df=False)[security].last_price # 获取股票的阶段收盘价涨幅 cp_increase = (current_price / close_data['close'][g.lag2 - g.lag1] - 1) * 100 # 取得平均价格 ma_n1 = close_data['close'].mean() #log.info("当前价格:%s,%s" % (security,current_price)) # 计算前一收盘价与均值差值 info = get_security_info(security) pre_price = (current_price / ma_n1 - 1) * 100 df_etf = df_etf.append({'基金代码': security, '对应名称': info.display_name, '周期涨幅': cp_increase, '均线差值': pre_price}, ignore_index=True) df_etf.sort_values(by='周期涨幅', ascending=False, inplace=True) log.info("盘前信号:%s" % (df_etf)) send_message("盘前信号:"+str(df_etf), channel='weixin') # return # 每日交易时 def ETFtrade(context): if g.signal == 'CLEAR': for stock in context.portfolio.positions: if stock == g.empty_keep_stock: continue log.info("清仓: %s" % stock) order_target(stock, 0) elif g.signal == 'BUY': if g.empty_keep_stock in context.portfolio.positions: order_target(g.empty_keep_stock, 0) # holdings = set(context.portfolio.positions.keys()) # 现在持仓的 targets = set(g.buy) # 想买的目标 # # 1. 卖出不在targets中的 sells = holdings - targets for code in sells: log.info("卖出: %s" % code) order_target(code, 0) # ratio = len(targets) if ratio >0: cash = context.portfolio.total_value / ratio # 2. 交集部分调仓 adjusts = holdings & targets for code in adjusts: # 手续费最低5元,只有交易5000元以上时,交易成本才会低于千分之一,才去调仓 if abs(cash - context.portfolio.positions[code].value) > 5000: log.info('调仓: %s' % code) order_target_value(code, cash) # 3. 新的,买入 purchases = targets - holdings for code in purchases: log.info('买入: %s' % code) order_target_value(code, cash) # current_returns = 100 * context.portfolio.returns log.info("当前收益:%.2f%%,当前持仓: %s", current_returns, list(context.portfolio.positions.keys())) if len(context.portfolio.positions) == 0: order_target_value(g.empty_keep_stock, context.portfolio.available_cash) def trade(context): today = context.current_dt # print(today.date(),'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@') n_sh = finance.run_query(query(finance.STK_ML_QUOTA).filter(finance.STK_ML_QUOTA.day <= today.date(), finance.STK_ML_QUOTA.link_id == 310001).order_by( finance.STK_ML_QUOTA.day.desc()).limit(252)) n_sz = finance.run_query(query(finance.STK_ML_QUOTA).filter(finance.STK_ML_QUOTA.day <= today.date(), finance.STK_ML_QUOTA.link_id == 310002).order_by( finance.STK_ML_QUOTA.day.desc()).limit(252)) money_north = [] g.boll252 = [] g.boll150 = [] g.boll80 = [] g.boll20 = [] for i in range(0, 252): sh_in = n_sh['buy_amount'][i] - n_sh['sell_amount'][i] sz_in = n_sz['buy_amount'][i] - n_sz['sell_amount'][i] amount = sh_in + sz_in money_north.append(amount) g.north_money = money_north[0] mid252 = np.mean(money_north) sted252 = np.std(money_north) up252 = mid252+1.5*sted252 low252 = mid252-1.5*sted252 g.boll252.append(up252) g.boll252.append(low252) mid150 = np.mean(money_north[0:150]) sted150 = np.std(money_north[0:150]) up150 = mid150+1.5*sted150 low150 = mid150-1.5*sted150 g.boll150.append(up150) g.boll150.append(low150) mid80 = np.mean(money_north[0:80]) sted80 = np.std(money_north[0:80]) up80 = mid80+2*sted80 low80 = mid80-2*sted80 g.boll80.append(up80) g.boll80.append(low80) mid20 = np.mean(money_north[0:20]) sted20 = np.std(money_north[0:20]) up20 = mid20+2*sted20 low20 = mid20-2*sted20 g.boll20.append(up20) g.boll20.append(low20) log.info(str(up252)+","+str(low252)) # 获取信号 def get_signal(context): # 创建保持计算结果的DataFrame df_etf = pd.DataFrame(columns=['基金代码', '对应名称', '周期涨幅', '均线差值']) current_data = get_current_data() for mkt_idx in g.ETFList: security = mkt_idx # 指数对应的基金 # 获取股票的收盘价 close_data = attribute_history(security, g.lag1, '1d', ['close'], df=False) # 获取股票现价 current_price = current_data[security].last_price # 获取股票的阶段收盘价涨幅 cp_increase = (current_price / close_data['close'][g.lag2 - g.lag1] - 1) * 100 # 取得平均价格 ma_n1 = close_data['close'].mean() info = get_security_info(security) # 计算前一收盘价与均值差值 pre_price = (current_price / ma_n1 - 1) * 100 df_etf = df_etf.append({'基金代码': security, '对应名称': info.display_name, '周期涨幅': cp_increase, '均线差值': pre_price}, ignore_index=True) df_etf.sort_values(by='周期涨幅', ascending=False, inplace=True) send_message("交易信号:"+str(df_etf), channel='weixin') # 按照涨幅降序排列 if len(df_etf) == 0: log.info("大盘信号:没有可以交易的品种,清仓") g.signal = 'CLEAR' return # if g.use_dynamic_target_market: # g.target_market = df_etf['对应指数'].iloc[-1] # 用涨幅最小的指数来处理 # log.info("\n行情统计,%s 热度%f%%:\n%s" % (g.target_market, g.emotion_rate, df_etf)) # if EmotionMonitor() == -1 and g.north_money<5000: # 大盘情绪不好发出空仓信号 # log.info("交易信号:大盘成交量持续低均线,空2") # g.signal = 'CLEAR' # return buyNum = 0 sellNum = 0 if g.north_money - g.boll252[0]>0: buyNum+=1 if g.north_money - g.boll150[0]>0: buyNum+=1 if g.north_money - g.boll80[0]>0: buyNum+=1 if g.north_money -g.boll20[0]>0: buyNum+=1 if g.north_money -g.boll252[1]<0: sellNum+=1 if g.north_money -g.boll150[1]<0: sellNum+=1 if g.north_money -g.boll80[1]<0: sellNum+=1 if g.north_money -g.boll20[1]<0: sellNum+=1 if sellNum>=2: log.info("依据北向资金流入%s\n"%(round(g.north_money,1))) g.signal = 'CLEAR' return elif buyNum>=3: index = 2 g.buy = df_etf['基金代码'].iloc[0:index] log.info("交易信号:持有 %s" % g.buy) g.signal = 'BUY' return # 大盘行情监控函数 def EmotionMonitor(): _cnt = g.lag0 + max(g.lag, 3) volume = attribute_history(security=g.target_market, count=_cnt, unit='1d', fields='volume')['volume'] v_ma_lag0 = talib.MA(volume, g.lag0) # 前 g.lag0 - 1 个会变成nan # g.emotion_rate = round((volume[-1] / v_ma_lag0[-1] - 1) * 100, 2) # 最后一天的成交量比成交量均值高% # vol_diff = (volume - v_ma_lag0) if vol_diff[-1] >= 0: ret_val = 1 if (vol_diff[-3:] >= 0).all() else 0 # 大盘成交量,最近3天都站在均线之上 else: ret_val = -1 if (vol_diff[-g.lag:] < 0).all() else 0 # 大盘成交量,最近g.lag天都在均线之下 # return ret_val ```
文章分类
关于作者
水滴
注册时间: