林奇PEG选股轮动,十年20倍,有止损模块 - 春秋金经
策略思路:
选股:林奇PEG,采用量化课堂的G=eps增长率,PEG=pe/(g*100)
择时:大盘现价大于大盘ma60买入,否则清仓
持仓:轮动
后续优化思路:
在回测后观察归因分析,发现一些股票买入后亏损巨大。可能过滤掉周期性行业之后会好一些。股票池目前是从所有股票里面筛选,我没有测试如果在沪深300或者中证500里面筛选会不会变好。
择时也仅仅用了一个最简单的大盘MA60判断,比较僵硬。各位看官可以修改成其他的止损模块试试。或者对个股进行分别止损,或者对个股进行均线回归。
资金管理方面,现在是对股票池中的股票平均买入,也许可以把前3名多买一点,后7名少买一点可以提高收益?买入的金额可以套一下凯利公式?或者套用一下CAPM模型?
希望和各位一起探讨。
林奇PEG简介
任何一家公司股票如果定价合理的话,市盈率就会与收益增长率相等。这就是PEG估值法,PEG在综合考虑了低风险以及未来成长性的因素,可用于股票价值评估。
PE:市盈率
EPS:每股收益
G=(EPS this year−EPS last year)/EPS last year
PEG=PE/(G∗100)
详见量化课堂https://xueqiu.com/8287840120/74917276
源码:
'''
策略思路:
选股:林奇PEG,PE/G排序,G=EPS增长率
择时:无
持仓:轮动
'''
# 导入函数库
import statsmodels.api as sm
from pandas.stats.api import ols
# 初始化函数,设定基准等等
def initialize(context):
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉order系列API产生的比error级别低的log
# log.set_level('order', 'error')
### 股票相关设定 ###
set_parameter(context)
# 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣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(before_market_open, time='before_open', reference_security='000300.XSHG')
# 开盘时运行
# run_daily(market_open, time='open', reference_security='000300.XSHG')
# 收盘后运行
run_daily(after_market_close, time='after_close', reference_security='000300.XSHG')
trade_func(context)
#每月轮动
# run_monthly(trade_func, 1, "09:30")
#每周轮动
run_weekly(trade_func, 1, "09:30")
'''
==============================参数设置部分================================
'''
def set_parameter(context):
#持仓股票数
g.stock_num = 10
g.stock_pos = 0
g.danger = False
g.danger_days = 0
g.maxCash = 0
#风险参考基准
g.security = '000300.XSHG'
# 设定策略运行基准
set_benchmark(g.security)
#记录策略运行天数
g.days = 0
## 开盘前运行函数
def before_market_open(context):
# 输出运行时间
#log.info('函数运行时间(before_market_open):'+str(context.current_dt.time()))
g.days += 1
# 给微信发送消息(添加模拟交易,并绑定微信生效)
log.info('策略正常,运行第%s天~'%g.days)
send_message('策略正常,运行第%s天~'%g.days)
## 开盘时运行函数
def handle_data(context, data):
record(cash=context.portfolio.cash)
record(cash=context.portfolio.cash)
ma1 = data['000001.XSHG'].mavg(1, 'close')
ma5 = data['000001.XSHG'].mavg(5, 'close')
ma10 = data['000001.XSHG'].mavg(10, 'close')
ma20 = data['000001.XSHG'].mavg(20, 'close')
ma30 = data['000001.XSHG'].mavg(30, 'close')
ma60 = data['000001.XSHG'].mavg(60, 'close')
if ma1 > ma60:
g.danger = False
# order_target_value('511880.XSHG',0)
elif ma1 < ma60:
g.danger = True
#清仓
for security,v in context.portfolio.positions.items():
order_target(security, 0)
#策略选股买卖部分
def trade_func(context):
#大盘风险
if g.danger:
return
#获取股票池
df = get_fundamentals(
query(
valuation.code,
valuation.pb_ratio,
indicator.roe,
valuation.pe_ratio,
indicator.eps
)
.filter(
indicator.eps > 0,
valuation.pb_ratio > 0,
valuation.pe_ratio > 0
)
)
df.index = df['code'].values
#上一年的EPS
current_dt = context.current_dt
last_year_date = current_dt + timedelta(days=-365)
last_year_df = get_fundamentals(
query(
valuation.code,
valuation.pb_ratio,
indicator.roe,
valuation.pe_ratio,
indicator.eps
)
.filter(
indicator.eps > 0,
valuation.pb_ratio > 0,
valuation.pe_ratio > 0
)
,date=last_year_date
)
last_year_df.index = last_year_df['code'].values
df['last_year_eps']=last_year_df['eps']
df['eps_grouth']=df['eps'] - df['last_year_eps']
#进行盈利>0筛选
df = df[df['eps_grouth']>0]
df = df[(df['eps']>0) & (df['pe_ratio']>0)]
print df
#G=eps增长率
df['g']=df['eps_grouth'] / df['last_year_eps']
df['peg']=df['pe_ratio'] / df['g'] / 100
#取排名top N的股票 进行轮动
df = df.sort('peg', ascending=True)[:g.stock_num]
#过滤停牌 ST
pool = df.index
pool = paused_filter(pool)
pool = delisted_filter(pool)
pool = st_filter(pool)
log.info('总共选出%s只股票'%len(pool))
if len(pool) == 0:
return;
#得到每只股票应该分配的资金
cash = context.portfolio.total_value/len(pool)
#获取已经持仓列表
hold_stock = context.portfolio.positions.keys()
#卖出不在持仓中的股票
for s in hold_stock:
if s not in pool:
order_target(s,0)
#买入股票
for s in pool:
log.info("买入股票:"+s)
order_target_value(s,cash)
#打分工具
def f_sum(x):
point = sum(x)
return point
## 收盘后运行函数
def after_market_close(context):
#得到当天所有成交记录
trades = get_trades()
for _trade in trades.values():
log.info('成交记录:'+str(_trade))
#打印账户总资产
log.info('今日账户总资产:%s'%round(context.portfolio.total_value,2))
log.info('##############################################################')
# 过滤停牌、退市、ST股票
def paused_filter(security_list):
current_data = get_current_data()
security_list = [stock for stock in security_list if not current_data[stock].paused]
return security_list
def delisted_filter(security_list):
current_data = get_current_data()
security_list = [stock for stock in security_list if not '退' in current_data[stock].name]
return security_list
def st_filter(security_list):
current_data = get_current_data()
security_list = [stock for stock in security_list if not current_data[stock].is_st]
return security_list