量化学习平台
文章
市场宽度
背离图
登录
注册
场内基金定投价值平均增强策略,年化30%+
策略
作者: 水滴
```python # 风险及免责提示:该策略由聚宽用户在聚宽社区分享,仅供学习交流使用。 # 原文一般包含策略说明,如有疑问请到原文和作者交流讨论。 # 原文网址:https://www.joinquant.com/post/39272 # 标题:场内基金定投价值平均增强策略,年化30%+ # 作者:子匀 # 克隆自聚宽文章:https://www.joinquant.com/post/39137 # 原策略使用场外基金,随着场内ETF越来越丰富,改写成场内基金 # 为方便改为场外基金,保留场外基金交易的代码 # 回测的结束日期,应设置此月的最后一天,run_monthly(compute_profit, -1, time = 'close') # 每天检查止赢,1. 赢利超过50%,最大回撤超过10%,则清仓 2.赢利超过80%,止盈 # 上涨50%后,下跌10%止赢后,如何操作?小牛市,即上轮最高点与最低点之差大于50%,不到90%,去半仓; # 大于90%,则大牛市,去全仓。 # 半仓止盈后,为方便计算,采用了先全仓卖出,再买回的方法 # 回测资金需要 1000000 import jqdata from jqlib.technical_analysis import * import datetime as dt import numpy as np # import warnings # warnings.filterwarnings('ignore') def initialize(context): #用来写最开始要初始化的参数 log.set_level('order', 'error') log.set_level('system', 'error') # 开启动态复权模式(真实价格) set_option('use_real_price', True) g.init_status = False # 已经建仓 True 否则 False g.totalmoney = context.portfolio.available_cash # 《价值平均策略》中要规划目标资金和目标日期,在实际应用中,更多是根据行情完成投资目标退出 # g.money = g.totalmoney/months # 月平均投资金额 g.money = g.totalmoney * 0.2 / 8 # 建仓时买入80%,余下20%分为8期 print( '每期投资金额:%.2f' % g.money) # 不用的指数和ETF,可注释掉 g.index = '000300.XSHG' # 参考指数 沪深300 g.security = '510300.XSHG' # 300ETF 场内代码 # g.security = '050002.OF' # 场外基金用此代码代替,博时沪深300指数A g.index = '399006.XSHE' # 创业板指 g.security = '159915.XSHE' #创业板ETF g.index = '399324.XSHE' # 深证红利 g.security = '159905.XSHE' # 深证红利ETF g.r = 0 #基金单位净值收益率 g.cost = 0 #用来计算持有成本 g.count = 0 # 购买交数 g.high = 0.01 # 基金的最高净值 g.down = 0.01 # 基金当前回撤 g.take_profit_flag = 0 #判断当月是否止盈 g.last_month_dwjz = 0 # 月初的单位净值 g.last_month_value = 0 # 月初的标的价值 g.bought_price = 0 # 上次交易价格 这两个价格,用于最基本的策略,低不卖,高不买 g.sold_price = 0 # 上次卖出价格 g.new_dwjz = 0 # 最新单位净值 g.take_profit_value = 0 # 止盈市值 g.take_profit_days = 0 # 止盈天数,中期止赢后,资金到账后,重新买入 g.buy_avg_cost = 0 # 真实买入成本 g.month_growth_rate = 1.005 # 每月价值增长额 g.investments = np.array([]) # 每次投入金额,用于IRR计算回报率 set_benchmark('000300.XSHG') #沪深300指数 #设置基金申购赎回费用均为万分之三 # set_order_cost(OrderCost(open_commission=0.0003, close_commission = 0.0003, min_commission=0), type='stock_fund') set_order_cost(OrderCost(close_tax=0.0, open_commission=0.0003, close_commission=0.0003, min_commission=1), type='fund') # 初始化场外基金仓位 # set_subportfolios([SubPortfolioConfig(context.portfolio.cash, 'open_fund')]) run_daily(init_position, time = 'open') # run_monthly(before_trading, 1, time='open-30m') #每月第一个交易日开盘前输出一些数据,用做检查,可以注释掉 run_daily(take_profit, time = 'open') #每月第一个交易日开盘时运行止盈函数 run_monthly(target_mv, 1, time = 'open+30m') #每月第一个交易日开盘后半小时按照平均市值策略申购基金 # run_monthly(compute_value, 3, time = 'open+30m') #按照申购基金t+2到账,第三个交易日计算本月净值数据,给下个月使用 run_monthly(compute_value, 2, time = 'open') #按上一天的收盘价,计算本月净值数据,给下个月使用 run_monthly(compute_profit, -1, time = 'close') # 最后一个月按IRR计算年化收益率, #def handle_data(context, data): #用来写每天循环要做什么 def before_trading(context): log.info('当前持仓总市值(1st)%.2f'%context.portfolio.positions[g.security].value) # # 获取账户的标的价值,计算方法是: price * total_amount log.info('当前持仓仓位(1st)%.2f'%context.portfolio.positions[g.security].total_amount) #total_amount: 总仓位, 但不包括挂单冻结仓位 # 该内置定时函数,会在每天结束交易后被调用一次 def after_trading_end(context): if g.init_status == False : return if context.portfolio.positions[g.security].total_amount > 0: # 持仓数量>0 dwjz = context.portfolio.positions[g.security].price g.high = max(g.high,dwjz) g.down = 1 - dwjz/g.high if g.buy_avg_cost == 0 : avg_cost = context.portfolio.positions[g.security].avg_cost else : avg_cost = g.buy_avg_cost # log.info('日期:%s ,单位净值:%s ,平均持仓成本:%s' %(context.current_dt.date(),dwjz,avg_cost)) g.r = 100*(dwjz/avg_cost - 1) elif context.portfolio.positions[g.security].total_amount == 0 : g.r = 0 g.high = 0 if g.take_profit_days > 0 : g.take_profit_days +=1 record(return_rate = g.r) # 回测环境/模拟专用API 画图函数 # 止盈 def take_profit(context): date_now = context.previous_date if g.r > 40 and g.down > 0.09: #基金净值收益达到40%以上并且最大回撤9%时,进行止盈赎回操作 g.r = 1 g.down = 0.01 rate0 = max_increase(date_now)[0] log.info('当前持仓总市值(0.40止盈后),基金净值最大增长:%s ,基金持仓成本:%s' %(rate0,context.portfolio.positions[g.security].avg_cost)) take_profit_rate = 1 # 止盈比例 为计算方便,全部卖出,再考虑是否买入 g.high = 0 g.buy_avg_cost = 0 g.last_month_value =0 if rate0 > 90 : # g.take_profit_flag = 1 # 止盈标志 g.init_status = False # 等待建仓 else : g.take_profit_days = 1 amount = take_profit_rate * context.portfolio.positions[g.security].total_amount g.take_profit_value = take_profit_rate * context.portfolio.positions[g.security].value # redeem(g.security, amount) g.sold_price = 10000 g.bought_price = 0 g.take_profit_value = get_cur_money(g.take_profit_value) # 整手买卖 order_value(g.security,-g.take_profit_value) g.investments = np.append(g.investments,g.take_profit_value) g.take_profit_flag = 1 # 止盈标志 log.info('当前持仓总市值(0.40止盈后立刻)%.2f'%context.portfolio.positions[g.security].value) # log.info('当前持仓仓位(0.40止盈后立刻)%.2f'%context.portfolio.positions[g.security].total_amount) elif g.r > 100 or max_increase1y(date_now)>75: g.r = 1 g.down = 0.01 take_profit_rate = 1 # 止盈比例 amount = take_profit_rate * context.portfolio.positions[g.security].total_amount g.take_profit_value = take_profit_rate * context.portfolio.positions[g.security].value g.take_profit_value = get_cur_money(g.take_profit_value) # 整手买卖 order_value(g.security,-g.take_profit_value) # redeem(g.security, amount) g.investments = np.append(g.investments,g.take_profit_value) g.take_profit_flag = 1 # 止盈标志 g.init_status = False # 等待建仓 g.high = 0 g.sold_price = 10000 g.bought_price = 0 log.info('当前持仓总市值(全仓止盈后立刻)%.2f'%context.portfolio.positions[g.security].value) # log.info('当前持仓仓位(全仓止盈后立刻)%.2f'%context.portfolio.positions[g.security].total_amount) # 止损 def stot_lost 价值平均策略,不止损 # 根据A股100为一手,整手交易规则,计算洽当的真实成交金额 def get_cur_money(money): cur_data = get_current_data() price = cur_data[g.security].last_price g.bought_price = price money = money*0.01//price * 100 * price # 整手买卖 return money # 建仓条件 def init_position(context): # 半仓止盈后,第二天买回 if g.take_profit_days > 0 : g.take_profit_days = 0 g.totalmoney = context.portfolio.available_cash g.money = g.totalmoney * 0.5 / 16 # 建仓时买入50%,余下50%分为16期 # print( '每期投资金额:%.2f' % g.money) money = get_cur_money(g.totalmoney * 0.5) log.info('每期投资金额:%.2f,止盈后买入:%.2f' % ( g.money,money)) # purchase(g.security,money) order_value(g.security,money) refresh_trade_price(context.current_dt,'buy') g.init_status = True g.last_month_value = money * g.month_growth_rate # g.investments = np.append(g.investments,-money) # np.append(arr, values,axis=None) 为原始array添加一些values g.count = 1 if g.init_status : return date_now = context.previous_date rate1 = max_increase(date_now)[1] if rate1 < 0.318 : # min_now = round(min1 + (max0-min1) * 0.318,2) # print("建仓点位:%s ,建仓日期:%s" %(min_now,l0)) g.totalmoney = context.portfolio.available_cash g.money = g.totalmoney * 0.2 / 10 # 建仓时买入80%,余下20%分为10期 money = get_cur_money(g.totalmoney * 0.7) # purchase(g.security,money) order_value(g.security,money) # print( '每期投资金额:%.2f' % g.money) refresh_trade_price(context.current_dt,'buy') log.info(' 每期投资金额:%.2f,建仓买入:%.2f' % ( g.money,money)) g.init_status = True g.last_month_value = money * g.month_growth_rate # g.investments = np.append(g.investments,-money) # np.append(arr, values,axis=None) 为原始array添加一些values g.count = 1 # 基金交易 def target_mv(context): if g.init_status == False : return cash = context.portfolio.available_cash value = context.portfolio.positions[g.security].value total_amount = context.portfolio.positions[g.security].total_amount if total_amount>0: # 持仓份额> 0 g.new_dwjz = value/total_amount if g.count == 0: # 首次买入 # purchase(g.security,g.money) # 申购基金 # g.investments = np.append(g.investments,-g.money) # np.append(arr, values,axis=None) 为原始array添加一些values g.count = 1 elif g.count!=0 and g.take_profit_flag == 0 : #当月未止盈的情况下正常使用价值平均策略申购基金 thismonth = g.money - (value - g.last_month_value) if thismonth > 0 and cash > 1000 and context.portfolio.positions[g.security].price < g.sold_price : #净值增长不够平均市值增长 # 避免个别月度买入值过大,实证取5倍月值时,投资业绩变化不大 if thismonth / g.money > 5 : thismonth = 5 * g.money # 超过可用现金,则全部买完 if thismonth > cash : thismonth = cash thismonth= get_cur_money(thismonth) log.info('当月净值:%s涨幅不够平均市值增长%s,应买入%s ' %(value,g.last_month_value,thismonth)) # purchase(g.security,thismonth) order_value(g.security,thismonth) refresh_trade_price(context.current_dt,'buy') g.investments = np.append(g.investments,-thismonth) # 当前价格高于平均持仓成本,并且涨幅高于本月净值增加值时,方才减仓 elif thismonth <= 0 and context.portfolio.positions[g.security].price > context.portfolio.positions[g.security].avg_cost and context.portfolio.positions[g.security].price > g.bought_price : if -thismonth / g.money > 5 : thismonth = -5 * g.money # amount = -thismonth / context.portfolio.positions[g.security].price # redeem(g.security, amount ) # 净值增长超过目标市值增长,则赎回 thismonth= get_cur_money(-thismonth) order_value(g.security,-thismonth) refresh_trade_price(context.current_dt,'sell') g.bought_price = 0 log.info('当月净值:%s涨幅超过市值增长%s,应卖出%s ' %(value,g.last_month_value,thismonth)) g.investments = np.append(g.investments,thismonth) elif g.count!=0 and g.take_profit_flag == 1: # 止盈次月不调整仓位,如需调整仓位,打开以下代码即可 #当月发生止盈情况的申购策略:申购额按照当前持仓数量*(当前单位净值-上月申购后单位净值)计算,扔遵循固定增值额度 # thismonth = g.money - (g.new_dwjz-g.last_month_dwjz)*context.portfolio.positions[g.security].total_amount # if thismonth > 0: # #净值增长不够平均市值增长 # log.info('当月净值涨幅不够平均市值增长222') # purchase(g.security,thismonth) # g.investments = np.append(g.investments,g.take_profit_value-thismonth) # elif thismonth <= 0: # # g.investments = np.append(g.investments,g.take_profit_value) g.take_profit_flag = 0 # T + 3 日,获取标的价值,单位净值 def compute_value(context): if g.init_status == False : return g.last_month_value = context.portfolio.positions[g.security].value * g.month_growth_rate if context.portfolio.positions[g.security].total_amount>0 : g.take_profit = context.portfolio.positions[g.security].value/context.portfolio.positions[g.security].total_amount # log.info('当前持仓总市值(4th)%.2f'%g.last_month_value) # log.info('当前持仓仓位(4th)%.2f'%context.portfolio.positions[g.security].total_amount) def compute_profit(context): if g.init_status == False : return if context.run_params.end_date.year == context.current_dt.year and context.current_dt.month == context.run_params.end_date.month: g.investments = np.append(g.investments,context.portfolio.positions[g.security].value) irr = np.irr(g.investments) log.info(g.investments) log.info(len(g.investments)) log.info('月度irr 为:%.4f'%irr) yearlyreturn = np.power(1+irr,12)-1 log.info('策略年化收益率为:%.4f'%yearlyreturn) # 根据买卖方向,刷新上次交易价格 def refresh_trade_price(datetime1,buy_or_sell): price = get_price(g.security, end_date=datetime1, frequency='1m', fields='close', count=1, panel=False)['close'][-1] if buy_or_sell == 'buy' : g.bought_price = price elif buy_or_sell == 'sell' : g.sold_price = price # 计算指数当前最大涨幅, def max_increase1y(date): days = 250 *1 # 1.5年内的最高点 h = get_price(g.index, end_date=date, frequency='1d', fields='close', count=days, panel=False ) h0 = h['close'].idxmax() max0 = h['close'].max() min0 = h['close'].loc[h0:].min() return (max0/min0-1)*100 # 计算当前向前2年的最高点,以及最高点向前2.5年的最低点之间的最大涨幅 def max_increase(date): date_now = date days = 250 *1.5 # 1.5年内的最高点 h = get_price(g.index, end_date=date, frequency='1d', fields='close', count=250*1.5, panel=False ) h0 = h['close'].idxmax() max0 = h['close'].max() min0 = h['close'].loc[h0:].min() # 高点前的起涨点 h = get_price(g.index, end_date=h0, frequency='1d', fields='close', count=250*2.5, panel=False ) min1 = h['close'].min() # print(min1) l1 = h['close'].idxmin() growth0 = max0 - min1 rate0 = max0/min1 * 100 - 100 down0 = max0 - min0 rate1 = 1- down0 / growth0 return rate0,rate1 ''' ''' ```
文章分类
关于作者
水滴
注册时间: