# 风险及免责提示:该策略由聚宽用户分享,仅供学习交流使用。
# 原文一般包含策略说明,如有疑问建议到原文和作者交流讨论。
# 克隆自聚宽文章:https://www.joinquant.com/post/24432
# 标题:基本不耍六毛的ETF轮动策略
# 作者:jqz1226
from jqdata import *
import pandas as pd
import talib
'''
原理:每月动态筛选基金, 选择范围包括ETF和LOF,选择条件是:1)已经上市交易15天以上,2)有一定的成交量。
每月动态选择1只收益率最高的场内货币基金。
持仓原则:
1、对泸深指数的成交量进行统计,如果连续6(lag)天成交量小于7(lag0)天成交量,空仓
2、13个交易日内(lag1)涨幅大于1的,并且“均线差值”大于0的才进行考虑。
3、对符合考虑条件的ETF的涨幅进行排序,按涨幅依次买入,买入的每只ETF不超过其全天成交量的千分之2。
4、闲钱时买入货币基金
'''
def initialize(context):
set_params()
#
# set_option("avoid_future_data", True)
set_option('order_volume_ratio', 0.002) # 成交量不得超过标的日成交量的千分之2
set_option('use_real_price', True) # 用真实价格交易
set_benchmark('000300.XSHG')
log.set_level('order', 'info')
# 滑点设置:按系统默认
# 设置手续费: 按系统默认
choice_etfs(context)
choice_mmf(context)
# ------------- 每月 ----------------
# run_weekly(choice_etfs, weekday=1, time='before_open', reference_security='000300.XSHG')
# run_weekly(choice_mmf, weekday=1, time='before_open', reference_security='000300.XSHG')
run_monthly(choice_etfs, monthday=1, time='before_open', reference_security='000300.XSHG')
run_monthly(choice_mmf, monthday=1, time='before_open', reference_security='000300.XSHG')
# ------------- 每天 ----------------
# 11:30 计算大盘信号
run_daily(get_signal, time='11:30')
# 14:40 进行交易
run_daily(ETFtrade, time='14:40')
# 1 设置参数
def set_params():
g.target_market = '399001.XSHE'
g.empty_keep_stock = '' # 闲时买入的标的
g.ETFList = [] # 目标ETFs
#
g.emotion_rate = 0 # 市场热度
g.signal = 'BUY' # 交易信号初始化
g.buy = [] # 购买股票列表
#
g.lag = 6 # 大盘成交量连续跌破均线的天数,发出空仓信号
g.lag0 = 7 # 大盘成交量监控周期
g.lag1 = 13 # 比价均线周期
g.lag2 = 13 # 价格涨幅计算周期
# 每日交易时
def ETFtrade(context):
# type: (Context) -> NoReturn
# 先卖掉货币基金
if g.empty_keep_stock != '':
if g.empty_keep_stock in context.portfolio.positions:
order_target(g.empty_keep_stock, 0)
#
if g.signal == 'CLEAR':
for stock in context.portfolio.positions:
log.info("清仓: %s" % stock)
order_target(stock, 0)
elif g.signal == 'BUY':
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)
# 2. 按顺序买入g.buy中的, 受交易量的限制, 超出部分不会下单
for code in g.buy:
val = context.portfolio.available_cash
if val > 500:
log.info('买入:%s' % code)
order_value(code, val)
else:
break
#
current_returns = 100 * context.portfolio.returns
log.info("当前权益:%.2f,收益:%.2f%%,当前持仓: %s", context.portfolio.total_value, current_returns,
list(context.portfolio.positions.keys()))
#
if g.empty_keep_stock != '':
if context.portfolio.available_cash > 500:
order_target_value(g.empty_keep_stock, context.portfolio.available_cash)
# 获取信号
def get_signal(context):
# type: (Context) -> NoReturn
if EmotionMonitor() == -1: # 大盘情绪不好发出空仓信号
log.info("交易信号:大盘成交量持续低均线,空仓")
g.signal = 'CLEAR'
return
#
log.info("\n行情统计:%s 热度%f%%" % (g.target_market, g.emotion_rate))
# 创建保持计算结果的DataFrame
df_etf = pd.DataFrame(columns=['基金代码', '周期涨幅', '均线差值'])
current_data = get_current_data()
for security in g.ETFList:
# 获取股票的收盘价
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()
# 计算前一收盘价与均值差值
pre_price = (current_price / ma_n1 - 1) * 100
df_etf = df_etf.append({'基金代码': security, '周期涨幅': cp_increase, '均线差值': pre_price},
ignore_index=True)
if len(df_etf) == 0:
log.info("交易信号:没有可以交易的品种,清仓")
g.signal = 'CLEAR'
return
# 按照涨幅降序排列
df_etf.sort_values(by='周期涨幅', ascending=False, inplace=True)
df_etf.reset_index(drop=True, inplace=True) # 重新设置索引
log.info("ETF热度:\n%s" % df_etf)
#
if df_etf['周期涨幅'].iloc[0] < 0.1 or df_etf['均线差值'].iloc[0] < 0: log.info('交易信号:最热的品种都不符合均线差值的要求,空仓') g.signal = 'CLEAR' return # 过滤出符合要求的 df_etf = df_etf[(df_etf['周期涨幅'] >= 0.1) & (df_etf['均线差值'] >= 0)]
g.buy = list(df_etf['基金代码']) # 所有符合要求的ETF
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
⚠️
本站资源大多来自网络,仅供网友学习交流,未经作者或上传书面授权,请勿作他用。
站长 vx: xiangyin615 或者 留言反馈 ,我们将尽快处理。
Notice: When you of the legal rights be violate, please stir to vx: xiangyin615
站长 vx: xiangyin615 或者 留言反馈 ,我们将尽快处理。
Notice: When you of the legal rights be violate, please stir to vx: xiangyin615
