Created
January 27, 2018 14:53
-
-
Save ShawnRong/8350b3d91fc94f80604e2d8d390d0eca to your computer and use it in GitHub Desktop.
stock strategy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import talib | |
import pandas | |
import scipy as sp | |
import scipy.optimize | |
import datetime as dt | |
from scipy import linalg as sla | |
from scipy import spatial | |
from jqdata import gta | |
def initialize(context): | |
#用沪深 300 做回报基准 | |
set_benchmark('000300.XSHG') | |
set_slippage(FixedSlippage(0.002)) | |
set_option('use_real_price', True) | |
# 关闭部分log | |
log.set_level('order', 'error') | |
# 定义策略占用仓位比例 | |
context.lowPEG_ratio = 1.0 | |
# for lowPEG algorithms | |
# 正态分布概率表,标准差倍数以及置信率 | |
# 1.96, 95%; 2.06, 96%; 2.18, 97%; 2.34, 98%; 2.58, 99%; 5, 99.9999% | |
context.lowPEG_confidencelevel = 1.96 | |
context.lowPEG_hold_periods, context.lowPEG_hold_cycle = 0, 30 | |
context.lowPEG_stock_list = [] | |
context.lowPEG_position_price = {} | |
g.quantlib = quantlib() | |
run_daily(fun_main, '10:30') | |
def fun_main(context): | |
lowPEG_trade_ratio = lowPEG_algo(context, context.lowPEG_ratio, context.portfolio.portfolio_value) | |
# 调仓,执行交易 | |
g.quantlib.fun_do_trade(context, lowPEG_trade_ratio, context.lowPEG_moneyfund) | |
def lowPEG_algo(context, lowPEG_ratio, portfolio_value): | |
''' | |
low PEG algorithms | |
输入参数:lowPEG_ratio, protfolio_value | |
输出参数:lowPEG_trade_ratio | |
自有类 : lowPEG_lib | |
调用类 : quantlib | |
''' | |
# 引用 lib | |
g.lowPEG = lowPEG_lib() | |
# 引用 quantlib | |
g.quantlib = quantlib() | |
g.lowPEG.fun_initialize(context) | |
recal_flag = False | |
if g.lowPEG.fun_needRebalance(context): | |
recal_flag = True | |
# 配仓,分配持股比例 | |
equity_ratio = {} | |
if recal_flag: | |
context.lowPEG_stock_list = g.lowPEG.fun_get_stock_list(context) | |
equity_ratio, bonds_ratio = g.lowPEG.fun_assetAllocationSystem(context, context.lowPEG_stock_list) | |
else: | |
equity_ratio = context.lowPEG_equity_ratio | |
bonds_ratio = context.lowPEG_bonds_ratio | |
context.lowPEG_equity_ratio = equity_ratio | |
context.lowPEG_bonds_ratio = bonds_ratio | |
# 分配头寸,配置市值 | |
trade_ratio = {} | |
if recal_flag: | |
trade_ratio = g.lowPEG.fun_calPosition(context, equity_ratio, bonds_ratio, lowPEG_ratio, portfolio_value) | |
stock_list = list(get_all_securities(['stock']).index) | |
for stock in context.portfolio.positions.keys(): | |
if stock not in trade_ratio and stock in stock_list: | |
trade_ratio[stock] = 0 | |
else: | |
trade_ratio = context.lowPEG_trade_ratio | |
context.lowPEG_trade_ratio = trade_ratio | |
return trade_ratio | |
class lowPEG_lib(): | |
def __init__(self, _period = '1d'): | |
pass | |
def fun_initialize(self, context): | |
# 定义股票池 | |
lowPEG_equity = context.lowPEG_stock_list | |
lowPEG_moneyfund = ['511880.XSHG'] | |
# 上市不足 60 天的剔除掉 | |
context.lowPEG_equity = g.quantlib.fun_delNewShare(context, lowPEG_equity, 60) | |
context.lowPEG_moneyfund = g.quantlib.fun_delNewShare(context, lowPEG_moneyfund, 60) | |
context.lowPEG_hold_num = 5 | |
context.lowPEG_risk_ratio = 0.03 / context.lowPEG_hold_num | |
def fun_needRebalance(self, context): | |
if len(context.lowPEG_stock_list) == 0: | |
context.lowPEG_hold_periods = context.lowPEG_hold_cycle | |
return True | |
if context.lowPEG_hold_periods == 0: | |
context.lowPEG_hold_periods = context.lowPEG_hold_cycle | |
return True | |
else: | |
context.lowPEG_hold_periods -= 1 | |
return False | |
# 取得净利润增长率参数 | |
def fun_get_inc(self, context, stock_list): | |
# 取最近的四个季度财报的日期 | |
def __get_quarter(stock_list): | |
''' | |
输入 stock_list | |
返回最近 n 个财报的日期 | |
返回每个股票最近一个财报的日期 | |
''' | |
# 取最新一季度的统计日期 | |
q = query(indicator.code, indicator.statDate | |
).filter(indicator.code.in_(stock_list)) | |
df = get_fundamentals(q) | |
stock_last_statDate = {} | |
tmpDict = df.to_dict() | |
for i in range(len(tmpDict['statDate'].keys())): | |
# 取得每个股票的代码,以及最新的财报发布日 | |
stock_last_statDate[tmpDict['code']] = tmpDict['statDate'] | |
df = df.sort(columns='statDate', ascending=False) | |
# 取得最新的财报日期 | |
last_statDate = df.iloc[0,1] | |
this_year = int(str(last_statDate)[0:4]) | |
this_month = str(last_statDate)[5:7] | |
if this_month == '12': | |
last_quarter = str(this_year) + 'q4' | |
last_two_quarter = str(this_year) + 'q3' | |
last_three_quarter = str(this_year) + 'q2' | |
last_four_quarter = str(this_year) + 'q1' | |
last_five_quarter = str(this_year - 1) + 'q4' | |
elif this_month == '09': | |
last_quarter = str(this_year) + 'q3' | |
last_two_quarter = str(this_year) + 'q2' | |
last_three_quarter = str(this_year) + 'q1' | |
last_four_quarter = str(this_year - 1) + 'q4' | |
last_five_quarter = str(this_year - 1) + 'q3' | |
elif this_month == '06': | |
last_quarter = str(this_year) + 'q2' | |
last_two_quarter = str(this_year) + 'q1' | |
last_three_quarter = str(this_year - 1) + 'q4' | |
last_four_quarter = str(this_year - 1) + 'q3' | |
last_five_quarter = str(this_year - 1) + 'q2' | |
else: #this_month == '03': | |
last_quarter = str(this_year) + 'q1' | |
last_two_quarter = str(this_year - 1) + 'q4' | |
last_three_quarter = str(this_year - 1) + 'q3' | |
last_four_quarter = str(this_year - 1) + 'q2' | |
last_five_quarter = str(this_year - 1) + 'q1' | |
return last_quarter, last_two_quarter, last_three_quarter, last_four_quarter, last_five_quarter, stock_last_statDate | |
# 查财报,返回指定值 | |
def __get_fundamentals_value(stock_list, myDate): | |
''' | |
输入 stock_list, 查询日期 | |
返回指定的财务数据,格式 dict | |
''' | |
q = query(indicator.code, indicator.inc_net_profit_year_on_year, indicator.statDate | |
).filter(indicator.code.in_(stock_list)) | |
df = get_fundamentals(q, statDate = myDate).fillna(value=0) | |
tmpDict = df.to_dict() | |
stock_dict = {} | |
for i in range(len(tmpDict['statDate'].keys())): | |
tmpList = [] | |
tmpList.append(tmpDict['statDate']) | |
tmpList.append(tmpDict['inc_net_profit_year_on_year']) | |
stock_dict[tmpDict['code']] = tmpList | |
return stock_dict | |
# 对净利润增长率进行处理 | |
def __cal_net_profit_inc(inc_list): | |
inc = inc_list | |
for i in range(len(inc)): # 约束在 +- 100 之内,避免失真 | |
if inc > 100: | |
inc = 100 | |
if inc < -100: | |
inc = -100 | |
avg_inc = np.mean(inc[:4]) | |
last_inc = inc[0] | |
inc_std = np.std(inc) | |
return avg_inc, last_inc, inc_std | |
# 得到最近 n 个季度的统计时间 | |
last_quarter, last_two_quarter, last_three_quarter, last_four_quarter, last_five_quarter, stock_last_statDate = __get_quarter(stock_list) | |
last_quarter_dict = __get_fundamentals_value(stock_list, last_quarter) | |
last_two_quarter_dict = __get_fundamentals_value(stock_list, last_two_quarter) | |
last_three_quarter_dict = __get_fundamentals_value(stock_list, last_three_quarter) | |
last_four_quarter_dict = __get_fundamentals_value(stock_list, last_four_quarter) | |
last_five_quarter_dict = __get_fundamentals_value(stock_list, last_five_quarter) | |
stock_dict = {} | |
for stock in stock_list: | |
inc_list = [] | |
if stock in stock_last_statDate: | |
if stock in last_quarter_dict: | |
if stock_last_statDate[stock] == last_quarter_dict[stock][0]: | |
inc_list.append(last_quarter_dict[stock][1]) | |
if stock in last_two_quarter_dict: | |
inc_list.append(last_two_quarter_dict[stock][1]) | |
else: | |
inc_list.append(0) | |
if stock in last_three_quarter_dict: | |
inc_list.append(last_three_quarter_dict[stock][1]) | |
else: | |
inc_list.append(0) | |
if stock in last_four_quarter_dict: | |
inc_list.append(last_four_quarter_dict[stock][1]) | |
else: | |
inc_list.append(0) | |
if stock in last_five_quarter_dict: | |
inc_list.append(last_five_quarter_dict[stock][1]) | |
else: | |
inc_list.append(0) | |
else: | |
inc_list = [0, 0, 0, 0] | |
# 取得过去4个季度的平均增长,最后1个季度的增长,增长标准差 | |
avg_inc, last_inc, inc_std = __cal_net_profit_inc(inc_list) | |
stock_dict[stock] = {} | |
stock_dict[stock]['avg_inc'] = avg_inc | |
stock_dict[stock]['last_inc'] = last_inc | |
stock_dict[stock]['inc_std'] = inc_std | |
return stock_dict | |
def fun_cal_stock_PEG(self, context, stock_list, stock_dict): | |
if not stock_list: | |
PEG = {} | |
return PEG | |
q = query(valuation.code, valuation.pe_ratio | |
).filter(valuation.code.in_(stock_list)) | |
df = get_fundamentals(q).fillna(value=0) | |
tmpDict = df.to_dict() | |
pe_dict = {} | |
tmp_dict = {} | |
for i in range(len(tmpDict['code'].keys())): | |
pe_dict[tmpDict['code']] = tmpDict['pe_ratio'] | |
df = g.quantlib.fun_get_Divid_by_year(context, stock_list) | |
tmpDict = df.to_dict() | |
stock_interest = {} | |
for stock in tmpDict['divpercent']: | |
stock_interest[stock] = tmpDict['divpercent'][stock] | |
h = history(1, '1d', 'close', stock_list, df=False) | |
PEG = {} | |
for stock in stock_list: | |
avg_inc = stock_dict[stock]['avg_inc'] | |
last_inc = stock_dict[stock]['last_inc'] | |
inc_std = stock_dict[stock]['inc_std'] | |
pe = -1 | |
if stock in pe_dict: | |
pe = pe_dict[stock] | |
interest = 0 | |
if stock in stock_interest: | |
interest = stock_interest[stock] | |
PEG[stock] = -1 | |
''' | |
原话大概是: | |
1、增长率 > 50 的公司要小心,高增长不可持续,一旦转差就要卖掉;实现的时候,直接卖掉增长率 > 50 个股票 | |
2、增长平稳,不知道该怎么表达,用了 inc_std < last_inc。有思路的同学请告诉我 | |
''' | |
if pe > 0 and last_inc <= 50 and last_inc > 0 and inc_std < last_inc: | |
PEG[stock] = (pe / (last_inc + interest*100)) | |
return PEG | |
def fun_get_stock_list(self, context): | |
def fun_get_stock_market_cap(stock_list): | |
q = query(valuation.code, valuation.market_cap | |
).filter(valuation.code.in_(stock_list)) | |
df = get_fundamentals(q).fillna(value=0) | |
tmpDict = df.to_dict() | |
stock_dict = {} | |
for i in range(len(tmpDict['code'].keys())): | |
# 取得每个股票的 market_cap | |
stock_dict[tmpDict['code']] = tmpDict['market_cap'] | |
return stock_dict | |
today = context.current_dt | |
stock_list = list(get_all_securities(['stock'], today).index) | |
stock_list = g.quantlib.unpaused(stock_list) | |
stock_list = g.quantlib.fun_remove_cycle_industry(stock_list) | |
stock_dict = self.fun_get_inc(context, stock_list) | |
old_stocks_list = [] | |
for stock in context.portfolio.positions.keys(): | |
if stock in stock_list: | |
old_stocks_list.append(stock) | |
stock_PEG = self.fun_cal_stock_PEG(context, stock_list, stock_dict) | |
stock_list = [] | |
buydict = {} | |
for stock in stock_PEG.keys(): | |
if stock_PEG[stock] < 0.5 and stock_PEG[stock] > 0: | |
stock_list.append(stock) | |
buydict[stock] = stock_PEG[stock] | |
cap_dict = fun_get_stock_market_cap(stock_list) | |
buydict = sorted(cap_dict.items(), key=lambda d:d[1], reverse=False) | |
buylist = [] | |
i = 0 | |
for idx in buydict: | |
if i < context.lowPEG_hold_num: | |
stock = idx[0] | |
buylist.append(stock) # 候选 stocks | |
print stock + ", PEG = "+ str(stock_PEG[stock]) | |
i += 1 | |
if len(buylist) < context.lowPEG_hold_num: | |
old_stocks_PEG = self.fun_cal_stock_PEG(context, old_stocks_list, stock_dict) | |
tmpDict = {} | |
tmpList = [] | |
for stock in old_stocks_PEG.keys(): | |
if old_stocks_PEG[stock] < 1.0 and old_stocks_PEG[stock] > 0: | |
tmpDict[stock] = old_stocks_PEG[stock] | |
tmpDict = sorted(tmpDict.items(), key=lambda d:d[1], reverse=False) | |
i = len(buylist) | |
for idx in tmpDict: | |
if i < context.lowPEG_hold_num and idx[0] not in buylist: | |
buylist.append(idx[0]) | |
i += 1 | |
print str(len(stock_list)) + " / " + str(len(buylist)) | |
print buylist | |
return buylist | |
def fun_assetAllocationSystem(self, context, buylist): | |
def __fun_getEquity_ratio(context, __stocklist): | |
__ratio = {} | |
# 按风险平价配仓 | |
if __stocklist: | |
__ratio = g.quantlib.fun_calStockWeight_by_risk(context, 2.58, __stocklist) | |
return __ratio | |
equity_ratio = __fun_getEquity_ratio(context, buylist) | |
bonds_ratio = __fun_getEquity_ratio(context, context.lowPEG_moneyfund) | |
return equity_ratio, bonds_ratio | |
def fun_calPosition(self, context, equity_ratio, bonds_ratio, lowPEG_ratio, portfolio_value): | |
risk_ratio = len(equity_ratio.keys()) | |
risk_money = context.portfolio.portfolio_value * risk_ratio * context.lowPEG_ratio * context.lowPEG_risk_ratio | |
maxrisk_money = risk_money * 1.7 | |
equity_value = 0 | |
if equity_ratio: | |
equity_value = g.quantlib.fun_getEquity_value(equity_ratio, risk_money, maxrisk_money, context.lowPEG_confidencelevel) | |
value_ratio = 0 | |
total_value = portfolio_value * lowPEG_ratio | |
if equity_value > total_value: | |
bonds_value = 0 | |
value_ratio = 1.0 * lowPEG_ratio | |
else: | |
value_ratio = (equity_value / total_value) * lowPEG_ratio | |
bonds_value = total_value - equity_value | |
trade_ratio = {} | |
equity_list = equity_ratio.keys() | |
for stock in equity_list: | |
if stock in trade_ratio: | |
trade_ratio[stock] += round((equity_ratio[stock] * value_ratio), 3) | |
else: | |
trade_ratio[stock] = round((equity_ratio[stock] * value_ratio), 3) | |
for stock in bonds_ratio.keys(): | |
if stock in trade_ratio: | |
trade_ratio[stock] += round((bonds_ratio[stock] * bonds_value / total_value) * lowPEG_ratio, 3) | |
else: | |
trade_ratio[stock] = round((bonds_ratio[stock] * bonds_value / total_value) * lowPEG_ratio, 3) | |
return trade_ratio | |
class quantlib(): | |
def __init__(self, _period = '1d'): | |
pass | |
# 剔除周期性行业 | |
def fun_remove_cycle_industry(self, stock_list): | |
cycle_industry = [#'A01', # 农业 1993-09-17 | |
#'A02', # 林业 1996-12-06 | |
#'A03', # 畜牧业 1997-06-11 | |
#'A04', # 渔业 1993-05-07 | |
#'A05', # 农、林、牧、渔服务业 1997-05-30 | |
'B06', # 煤炭开采和洗选业 1994-01-06 | |
'B07', # 石油和天然气开采业 1996-06-28 | |
'B08', # 黑色金属矿采选业 1997-07-08 | |
'B09', # 有色金属矿采选业 1996-03-20 | |
'B11', # 开采辅助活动 2002-02-05 | |
#'C13', # 农副食品加工业 1993-12-15 | |
#C14 食品制造业 1994-08-18 | |
#C15 酒、饮料和精制茶制造业 1992-10-12 | |
#C17 纺织业 1992-06-16 | |
#C18 纺织服装、服饰业 1993-12-31 | |
#C19 皮革、毛皮、羽毛及其制品和制鞋业 1994-04-04 | |
#C20 木材加工及木、竹、藤、棕、草制品业 2005-05-10 | |
#C21 家具制造业 1996-04-25 | |
#C22 造纸及纸制品业 1993-03-12 | |
#C23 印刷和记录媒介复制业 1994-02-24 | |
#C24 文教、工美、体育和娱乐用品制造业 2007-01-10 | |
'C25', # 石油加工、炼焦及核燃料加工业 1993-10-25 | |
'C26', # 化学原料及化学制品制造业 1990-12-19 | |
#C27 医药制造业 1993-06-29 | |
'C28', # 化学纤维制造业 1993-07-28 | |
'C29', # 橡胶和塑料制品业 1992-08-28 | |
'C30', # 非金属矿物制品业 1992-02-28 | |
'C31', # 黑色金属冶炼及压延加工业 1994-01-06 | |
'C32', # 有色金属冶炼和压延加工业 1996-02-15 | |
'C33', # 金属制品业 1993-11-30 | |
'C34', # 通用设备制造业 1992-03-27 | |
'C35', # 专用设备制造业 1992-07-01 | |
'C36', # 汽车制造业 1992-07-24 | |
'C37', # 铁路、船舶、航空航天和其它运输设备制造业 1992-03-31 | |
'C38', # 电气机械及器材制造业 1990-12-19 | |
#C39 计算机、通信和其他电子设备制造业 1990-12-19 | |
#C40 仪器仪表制造业 1993-09-17 | |
'C41', # 其他制造业 1992-08-14 | |
#C42 废弃资源综合利用业 2012-10-26 | |
'D44', # 电力、热力生产和供应业 1993-04-16 | |
#D45 燃气生产和供应业 2000-12-11 | |
#D46 水的生产和供应业 1994-02-24 | |
'E47', # 房屋建筑业 1993-04-29 | |
'E48', # 土木工程建筑业 1994-01-28 | |
'E50', # 建筑装饰和其他建筑业 1997-05-22 | |
#F51 批发业 1992-05-06 | |
#F52 零售业 1992-09-02 | |
'G53', # 铁路运输业 1998-05-11 | |
'G54', # 道路运输业 1991-01-14 | |
'G55', # 水上运输业 1993-11-19 | |
'G56', # 航空运输业 1997-11-05 | |
'G58', # 装卸搬运和运输代理业 1993-05-05 | |
#G59 仓储业 1996-06-14 | |
#H61 住宿业 1993-11-18 | |
#H62 餐饮业 1997-04-30 | |
#I63 电信、广播电视和卫星传输服务 1992-12-02 | |
#I64 互联网和相关服务 1992-05-07 | |
#I65 软件和信息技术服务业 1992-08-20 | |
'J66', # 货币金融服务 1991-04-03 | |
'J67', # 资本市场服务 1994-01-10 | |
'J68', # 保险业 2007-01-09 | |
'J69', # 其他金融业 2012-10-26 | |
'K70', # 房地产业 1992-01-13 | |
#L71 租赁业 1997-01-30 | |
#L72 商务服务业 1996-08-29 | |
#M73 研究和试验发展 2012-10-26 | |
'M74', # 专业技术服务业 2007-02-15 | |
#N77 生态保护和环境治理业 2012-10-26 | |
#N78 公共设施管理业 1992-08-07 | |
#P82 教育 2012-10-26 | |
#Q83 卫生 2007-02-05 | |
#R85 新闻和出版业 1992-12-08 | |
#R86 广播、电视、电影和影视录音制作业 1994-02-24 | |
#R87 文化艺术业 2012-10-26 | |
#S90 综合 1990-12-10 | |
] | |
for industry in cycle_industry: | |
stocks = get_industry_stocks(industry) | |
stock_list = list(set(stock_list).difference(set(stocks))) | |
return stock_list | |
def fun_do_trade(self, context, trade_ratio, moneyfund): | |
def __fun_tradeStock(context, stock, ratio): | |
total_value = context.portfolio.portfolio_value | |
if stock in moneyfund: | |
self.fun_tradeBond(context, stock, total_value * ratio) | |
else: | |
curPrice = history(1,'1d', 'close', stock, df=False)[stock][-1] | |
curValue = context.portfolio.positions[stock].total_amount * curPrice | |
Quota = total_value * ratio | |
if Quota: | |
if abs(Quota - curValue) / Quota >= 0.25: | |
if Quota > curValue: | |
cash = context.portfolio.cash | |
if cash >= Quota * 0.25: | |
self.fun_trade(context, stock, Quota) | |
else: | |
self.fun_trade(context, stock, Quota) | |
else: | |
self.fun_trade(context, stock, Quota) | |
trade_list = trade_ratio.keys() | |
myholdstock = context.portfolio.positions.keys() | |
total_value = context.portfolio.portfolio_value | |
# 已有仓位 | |
holdDict = {} | |
h = history(1, '1d', 'close', myholdstock, df=False) | |
for stock in myholdstock: | |
tmpW = round((context.portfolio.positions[stock].total_amount * h[stock])/total_value, 2) | |
holdDict[stock] = float(tmpW) | |
# 对已有仓位做排序 | |
tmpDict = {} | |
for stock in holdDict: | |
if stock in trade_ratio: | |
tmpDict[stock] = round((trade_ratio[stock] - holdDict[stock]), 2) | |
tradeOrder = sorted(tmpDict.items(), key=lambda d:d[1], reverse=False) | |
_tmplist = [] | |
for idx in tradeOrder: | |
stock = idx[0] | |
__fun_tradeStock(context, stock, trade_ratio[stock]) | |
_tmplist.append(stock) | |
# 交易其他股票 | |
for i in range(len(trade_list)): | |
stock = trade_list | |
if len(_tmplist) != 0 : | |
if stock not in _tmplist: | |
__fun_tradeStock(context, stock, trade_ratio[stock]) | |
else: | |
__fun_tradeStock(context, stock, trade_ratio[stock]) | |
def fun_getEquity_value(self, equity_ratio, risk_money, maxrisk_money, confidence_ratio): | |
def __fun_getdailyreturn(stock, freq, lag): | |
hStocks = history(lag, freq, 'close', stock, df=True) | |
dailyReturns = hStocks.resample('D',how='last').pct_change().fillna(value=0, method=None, axis=0).values | |
return dailyReturns | |
def __fun_get_portfolio_dailyreturn(ratio, freq, lag): | |
__portfolio_dailyreturn = [] | |
for stock in ratio.keys(): | |
if ratio[stock] != 0: | |
__dailyReturns = __fun_getdailyreturn(stock, freq, lag) | |
__tmplist = [] | |
for i in range(len(__dailyReturns)): | |
__tmplist.append(__dailyReturns * ratio[stock]) | |
if __portfolio_dailyreturn: | |
__tmplistB = [] | |
for i in range(len(__portfolio_dailyreturn)): | |
__tmplistB.append(__portfolio_dailyreturn+__tmplist) | |
__portfolio_dailyreturn = __tmplistB | |
else: | |
__portfolio_dailyreturn = __tmplist | |
return __portfolio_dailyreturn | |
def __fun_get_portfolio_ES(ratio, freq, lag, confidencelevel): | |
if confidencelevel == 1.96: | |
a = (1 - 0.95) | |
elif confidencelevel == 2.06: | |
a = (1 - 0.96) | |
elif confidencelevel == 2.18: | |
a = (1 - 0.97) | |
elif confidencelevel == 2.34: | |
a = (1 - 0.98) | |
elif confidencelevel == 2.58: | |
a = (1 - 0.99) | |
else: | |
a = (1 - 0.95) | |
dailyReturns = __fun_get_portfolio_dailyreturn(ratio, freq, lag) | |
dailyReturns_sort = sorted(dailyReturns) | |
count = 0 | |
sum_value = 0 | |
for i in range(len(dailyReturns_sort)): | |
if i < (lag * a): | |
sum_value += dailyReturns_sort | |
count += 1 | |
if count == 0: | |
ES = 0 | |
else: | |
ES = -(sum_value / (lag * a)) | |
return ES | |
def __fun_get_portfolio_VaR(ratio, freq, lag, confidencelevel): | |
__dailyReturns = __fun_get_portfolio_dailyreturn(ratio, freq, lag) | |
__portfolio_VaR = 1.0 * confidencelevel * np.std(__dailyReturns) | |
return __portfolio_VaR | |
# 每元组合资产的 VaR | |
__portfolio_VaR = __fun_get_portfolio_VaR(equity_ratio, '1d', 180, confidence_ratio) | |
__equity_value_VaR = 0 | |
if __portfolio_VaR: | |
__equity_value_VaR = risk_money / __portfolio_VaR | |
__portfolio_ES = __fun_get_portfolio_ES(equity_ratio, '1d', 180, confidence_ratio) | |
__equity_value_ES = 0 | |
if __portfolio_ES: | |
__equity_value_ES = maxrisk_money / __portfolio_ES | |
if __equity_value_VaR == 0: | |
equity_value = __equity_value_ES | |
elif __equity_value_ES == 0: | |
equity_value = __equity_value_VaR | |
else: | |
equity_value = min(__equity_value_VaR, __equity_value_ES) | |
return equity_value | |
def fun_get_Divid_by_year(self, context, stocks): | |
year = context.current_dt.year - 1 | |
#将当前股票池转换为国泰安的6位股票池 | |
stocks_symbol=[] | |
for s in stocks: | |
stocks_symbol.append(s[0:6]) | |
df = gta.run_query(query( | |
gta.STK_DIVIDEND.SYMBOL, # 股票代码 | |
gta.STK_DIVIDEND.DECLAREDATE, # 分红消息的时间 | |
).filter( | |
gta.STK_DIVIDEND.ISDIVIDEND == 'Y', #有分红的股票 | |
gta.STK_DIVIDEND.DIVDENDYEAR == year, | |
gta.STK_DIVIDEND.TERMCODE == 'P2702', # 年度分红 | |
gta.STK_DIVIDEND.SYMBOL.in_(stocks_symbol) | |
)).fillna(value=0, method=None, axis=0) | |
# 转换时间格式 | |
df['pubtime'] = map(lambda x: int(x.split('-')[0]+x.split('-')[1]+x.split('-')[2]),df['DECLAREDATE']) | |
# 取得当前时间 | |
currenttime = int(str(context.current_dt)[0:4]+str(context.current_dt)[5:7]+str(context.current_dt)[8:10]) | |
# 选择在当前时间能看到的记录 | |
df = df[(df.pubtime < currenttime)] | |
# 得到目前看起来,有上一年度年度分红的股票 | |
stocks_symbol_this_year = list(df['SYMBOL']) | |
# 得到目前看起来,上一年度没有年度分红的股票 | |
stocks_symbol_past_year = list(set(stocks_symbol) - set(stocks_symbol_this_year)) | |
# 查有上一年度年度分红的 | |
df1 = gta.run_query(query( | |
gta.STK_DIVIDEND.SYMBOL, # 股票代码 | |
gta.STK_DIVIDEND.DIVIDENTBT, # 股票分红 | |
gta.STK_DIVIDEND.DECLAREDATE, # 分红消息的时间 | |
gta.STK_DIVIDEND.DISTRIBUTIONBASESHARES # 分红时的股本基数 | |
).filter( | |
gta.STK_DIVIDEND.ISDIVIDEND == 'Y', #有分红的股票 | |
gta.STK_DIVIDEND.DIVDENDYEAR == year, | |
gta.STK_DIVIDEND.SYMBOL.in_(stocks_symbol_this_year) | |
)).fillna(value=0, method=None, axis=0) | |
df1['pubtime'] = map(lambda x: int(x.split('-')[0]+x.split('-')[1]+x.split('-')[2]),df1['DECLAREDATE']) | |
currenttime = int(str(context.current_dt)[0:4]+str(context.current_dt)[5:7]+str(context.current_dt)[8:10]) | |
df1 = df1[(df1.pubtime < currenttime)] | |
# 求上上年的年度分红 | |
df2 = gta.run_query(query( | |
gta.STK_DIVIDEND.SYMBOL, # 股票代码 | |
gta.STK_DIVIDEND.DIVIDENTBT, # 股票分红 | |
gta.STK_DIVIDEND.DECLAREDATE, # 分红消息的时间 | |
gta.STK_DIVIDEND.DISTRIBUTIONBASESHARES # 分红时的股本基数 | |
).filter( | |
gta.STK_DIVIDEND.ISDIVIDEND == 'Y', #有分红的股票 | |
gta.STK_DIVIDEND.DIVDENDYEAR == (year - 1), | |
gta.STK_DIVIDEND.SYMBOL.in_(stocks_symbol_past_year) | |
)).fillna(value=0, method=None, axis=0) | |
df2['pubtime'] = map(lambda x: int(x.split('-')[0]+x.split('-')[1]+x.split('-')[2]),df2['DECLAREDATE']) | |
currenttime = int(str(context.current_dt)[0:4]+str(context.current_dt)[5:7]+str(context.current_dt)[8:10]) | |
df2 = df2[(df2.pubtime < currenttime)] | |
df= pd.concat((df2,df1)) | |
df['SYMBOL']=map(normalize_code,list(df['SYMBOL'])) | |
df.index=list(df['SYMBOL']) | |
# 获取最新股本 | |
q = query(valuation.code, valuation.capitalization | |
).filter(valuation.code.in_(list(df.index))) | |
df3 = get_fundamentals(q).fillna(value=0) | |
df3['SYMBOL'] = df3['code'] | |
df3 = df3.drop(['code'], axis=1) | |
# 合并成一个 dataframe | |
df = df.merge(df3,on='SYMBOL') | |
df.index = list(df['SYMBOL']) | |
# 转换成 float | |
df['DISTRIBUTIONBASESHARES'] = map(float, df['DISTRIBUTIONBASESHARES']) | |
# 计算股份比值 | |
df['CAP_RATIO'] = df['DISTRIBUTIONBASESHARES'] / (df['capitalization'] * 10000) | |
df['DIVIDENTBT'] = map(float, df['DIVIDENTBT']) | |
# 计算相对于目前股份而言的分红额度 | |
df['DIVIDENTBT'] = df['DIVIDENTBT'] * df['CAP_RATIO'] | |
df = df.drop(['SYMBOL','DECLAREDATE','DISTRIBUTIONBASESHARES','capitalization','CAP_RATIO'], axis=1) | |
#接下来这一步是考虑多次分红的股票,因此需要累加股票的多次分红 | |
df = df.groupby(df.index).sum() | |
#得到当前股价 | |
Price=history(1, unit='1d', field='close', security_list=list(df.index), df=True, skip_paused=False, fq='pre') | |
Price=Price.T | |
df['pre_close']=Price | |
#计算股息率 = 股息/股票价格,* 10 是因为取到的是每 10 股分红 | |
df['divpercent']=df['DIVIDENTBT']/(df['pre_close'] * 10) | |
df['code'] = np.array(df.index) | |
return df | |
def fun_calStockWeight_by_risk(self, context, confidencelevel, stocklist): | |
def __fun_calstock_risk_ES(stock, lag, confidencelevel): | |
hStocks = history(lag, '1d', 'close', stock, df=True) | |
dailyReturns = hStocks.resample('D',how='last').pct_change().fillna(value=0, method=None, axis=0).values | |
if confidencelevel == 1.96: | |
a = (1 - 0.95) | |
elif confidencelevel == 2.06: | |
a = (1 - 0.96) | |
elif confidencelevel == 2.18: | |
a = (1 - 0.97) | |
elif confidencelevel == 2.34: | |
a = (1 - 0.98) | |
elif confidencelevel == 2.58: | |
a = (1 - 0.99) | |
elif confidencelevel == 5: | |
a = (1 - 0.99999) | |
else: | |
a = (1 - 0.95) | |
dailyReturns_sort = sorted(dailyReturns) | |
count = 0 | |
sum_value = 0 | |
for i in range(len(dailyReturns_sort)): | |
if i < (lag * a): | |
sum_value += dailyReturns_sort | |
count += 1 | |
if count == 0: | |
ES = 0 | |
else: | |
ES = -(sum_value / (lag * a)) | |
if isnan(ES): | |
ES = 0 | |
return ES | |
def __fun_calstock_risk_VaR(stock): | |
hStocks = history(180, '1d', 'close', stock, df=True) | |
dailyReturns = hStocks.resample('D',how='last').pct_change().fillna(value=0, method=None, axis=0).values | |
VaR = 1 * 2.58 * np.std(dailyReturns) | |
return VaR | |
__risk = {} | |
stock_list = [] | |
for stock in stocklist: | |
curRisk = __fun_calstock_risk_ES(stock, 180, confidencelevel) | |
if curRisk <> 0.0: | |
__risk[stock] = curRisk | |
__position = {} | |
for stock in __risk.keys(): | |
__position[stock] = 1.0 / __risk[stock] | |
total_position = 0 | |
for stock in __position.keys(): | |
total_position += __position[stock] | |
__ratio = {} | |
for stock in __position.keys(): | |
tmpRatio = __position[stock] / total_position | |
if isnan(tmpRatio): | |
tmpRatio = 0 | |
__ratio[stock] = round(tmpRatio, 4) | |
return __ratio | |
def fun_tradeBond(self, context, stock, Value): | |
hStocks = history(1, '1d', 'close', stock, df=False) | |
curPrice = hStocks[stock] | |
curValue = float(context.portfolio.positions[stock].total_amount * curPrice) | |
deltaValue = abs(Value - curValue) | |
if deltaValue > (curPrice*100): | |
if Value > curValue: | |
cash = context.portfolio.cash | |
if cash > (curPrice*100): | |
self.fun_trade(context, stock, Value) | |
else: | |
# 如果是银华日利,多卖 100 股,避免个股买少了 | |
if stock == '511880.XSHG': | |
Value -= curPrice*100 | |
self.fun_trade(context, stock, Value) | |
# 剔除上市时间较短的产品 | |
def fun_delNewShare(self, context, equity, deltaday): | |
deltaDate = context.current_dt.date() - dt.timedelta(deltaday) | |
tmpList = [] | |
for stock in equity: | |
if get_security_info(stock).start_date < deltaDate: | |
tmpList.append(stock) | |
return tmpList | |
def unpaused(self, _stocklist): | |
current_data = get_current_data() | |
return [s for s in _stocklist if not current_data[s].paused] | |
def fun_trade(self, context, stock, value): | |
self.fun_setCommission(context, stock) | |
order_target_value(stock, value) | |
def fun_setCommission(self, context, stock): | |
if stock in context.lowPEG_moneyfund: | |
set_order_cost(OrderCost(open_tax=0, close_tax=0, open_commission=0, close_commission=0, close_today_commission=0, min_commission=0), type='stock') | |
else: | |
set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='stock')/* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match *//* bbscode i not match */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment