# 开始时间
start_date ='2013-01-01'
# 结束时间
end_date = '2017-06-01'
# 15,14,13三年的年终财报时间
quarters = ['20161231', '20151231', '20141231'];
instruments = D.instruments(start_date, end_date)
# 代码,日期,净资产收益率, 归属母公司股东的净利润同比增长率,财报季度时间,财报对应的季度取值 1/2/3/4
# 参见 https://bigquant.com/docs/data_financial_statements.html
fields = ['instrument', 'date', 'fs_roe_ttm', 'fs_net_profit_yoy', 'fs_quarter' ,'fs_quarter_index']
# 获取以上字段的财报数据
financial_data = D.financial_statements(instruments, start_date, end_date, fields)
# 筛选出第四季度财报数据
financial_data = financial_data[financial_data['fs_quarter_index'] == 4]
# 获取市盈率历史数据
pe_data = D.history_data(instruments, start_date, end_date, ['name', 'pe_ttm'])
financial_data = financial_data.drop_duplicates(['instrument', 'fs_quarter']);
financial_data.sort_values(by='date', ascending=False, inplace=True)
stocks = pd.DataFrame()
def good_stock(df):
global stocks
instrument = df.iloc[0]['instrument']
for q in quarters:
# 找出该股票年报的数据,q in ['20151231', '20141231', '20131231']
cur_df = df[df['fs_quarter'] == q]
# 没有该年的财报数据
if cur_df.empty:
return
# 连续三年净资产收益率 > 15
if np.isnan(cur_df.iloc[0]['fs_roe_ttm']) or cur_df.iloc[0]['fs_roe_ttm'] <= 15:
return
# 最近一年财报净利润同比增长率 > 15
latest_financial = df[df['fs_quarter'] == quarters[0]]
if np.isnan(latest_financial.iloc[0]['fs_net_profit_yoy']) or latest_financial.iloc[0]['fs_net_profit_yoy'] <= 15:
return
# 找到年度财报日或者之前最近一天pe数据
pe_history = pe_data[(pe_data['instrument'] == instrument) & (pe_data['date'] <= latest_financial.iloc[0]['date']) & (~np.isnan(pe_data['pe_ttm']))];
pe_history.sort_values(by='date', ascending=False, inplace=True)
if pe_history.shape[0] == 0:
print ('no pe data of ' + instrument)
# 市盈率 < 35
if np.isnan(pe_history.iloc[0]['pe_ttm']) or pe_history.iloc[0]['pe_ttm'] >= 35:
return
# 找到一只股票,添加到result中
stocks = stocks.append(pe_history.iloc[0][['instrument', 'name']], ignore_index=True)
financial_data.groupby('instrument').apply(good_stock)
print("共找到" + str(stocks.shape[0]) + "支好股票:")
print(stocks)
# 初始化虚拟账户状态,只在第一个交易日运行
def initialize(context):
# 设置手续费,买入时万3,卖出是千分之1.3,不足5元以5元计
context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
# 策略交易逻辑,每个交易日运行一次
def handle_data(context, data):
for index, row in stocks.iterrows():
# 字符型股票代码转化成BigQuant回测引擎所需的股票代码
instrument = context.symbol(row['instrument'])
# 目前持仓数量
curr_position = context.portfolio.positions[instrument].amount
# 第一个能买入的时间买入股票
if curr_position == 0 and data.can_trade(instrument):
# 买入一万元股票
order_value(instrument, 10000)
# 策略比较参考标准,以沪深300为例
benchmark = '000300.INDX'
# 策略回测接口: https://bigquant.com/docs/strategy_backtest.html
# 回测最近一年数据,2016-06-01起的第一个工作日买入这些股票
m = M.backtest.v5(
instruments=instruments,
start_date="2017-05-01",
end_date='2017-06-15',
initialize=initialize,
handle_data=handle_data,
# 买入订单以开盘价成交
order_price_field_buy='open',
# 卖出订单以开盘价成交
order_price_field_sell='open',
# 初始资金
capital_base=stocks.shape[0] * 10000,
benchmark=benchmark,
)