组合优化器使用文档
由small_q创建,最终由small_q 被浏览 26 用户
组合优化器是宽邦科技为满足机构投资者对于股票组合优化、绩效归因、风险控制和指数增强需求而提供的一款优化器。
使用概览
- 调用接口:T.PORTFOLIO_OPTIMIZERS
- 每日初始化:T.PORTFOLIO_OPTIMIZERS.get_today_factor_data
- 权重优化:T.PORTFOLIO_OPTIMIZERS.optimize
\
调用接口
opt=T.PORTFOLIO_OPTIMIZERS(stock_pool, start_date, end_date, model_type='daily', benchmark='000905.HIX')
该命令是整个组合优化器的初始化接口,即使用组合优化进行权重选择之前,必须得先运行此行命令并赋值于一个变量
字段解释:
-
stock_pool: 标的池数据(比如中证500成份股数据,需包含字段:date, instrument, weight/score)
-
start_date: 标的池中数据的起始日期
-
end_date: 标的池中数据的结束日期
-
model_type: 因子收益协方差矩阵和特意收益率矩阵的数据类型,三选一:daily, short, long(默认为daily)
-
benchmark: 基准数据代码(默认为’000905.HIX’)
\
输出定义为opt的方法,可继续调用函数有:opt.get_today_factor_data, opt.optimize, 以及其余所有的目标函数和约束条件等
\
每日初始化接口
opt.get_today_factor_data(init_pool,current_date) (无需定义变量赋值)
该命令的用法是在整体初始化之后,进行每日权重分配以及约束条件和目标函数确定之前调用该接口
字段解释:
- init_pool: 每日标的池数据(比如中证500成份股数据,需包含字段:date, instrument, weight/score)
- current_date: 当前初始化日期
无输出结果,仅作每日初始化使用
\
权重优化接口
weights = opt.optimize(target_func, current_date, cons, stock_count=None, response=True, hard=True, verbose=False)
字段解释:
- target_func: 目标函数(类型: method)
- current_date: 当前日期(类型: string)
- cons: 约束条件,其中包含边界约束bounds(类型: methods)
- stock_count: 权重优化最大股票数量,若为None则表示没有设定限制(类型: int),默认为None
- response: 优化错误时,设置为True则返回0值,设置为False则不返回值(类型: bool),默认为True
- hard: 软硬约束定义,设置为True的话则为软约束,为False则为硬约束(类型: bool),默认为True
- verbose: 是否需要输出优化日志(类型: bool),默认为False
输出结果为每天优化后的组合权重结果,主要列名有【date, instrument, weights】
目标函数 & 约束条件
目标函数target_func和约束条件constraints会以方法的形式传入权重优化接口opt.optimize,所以需要在传入之前进行方法的定义
目标函数 | 接口 | 可调参数 |
---|---|---|
最大化风险调整后收益 | MaxReturn | 风险厌恶指数lam,默认为0 |
最小化风险 | MinRisk | 无 |
最小化风格偏离 | MinStyleDeviation | target_function: style - 风格因子名称以及偏离值(类型:dict),例如 {‘size‘:1} 表达的是将size因子暴露于其均值+1倍标准差之上 \n if_pred - 是否为预测数据(类型:bool),默认为False \n relative - 是否相对于基准(类型:bool),默认为False |
最大化预测得分 | MaxScore | 无 |
约束条件or边界条件 | 接口 | 可调参数 |
---|---|---|
总预算权重约束 | TotalWeightsConstraint | upper_limit - 资金组合总权重上限(类型:int / float) |
个股权重边界 | Bounds | lower_limit - 个股权重下限(类型:int / float) \n upper_limit - 个股权重上限(类型:int / float) \n relative - 是否基于基准(类型:bool;默认为False) |
个股风格约束 | StyleConstraint | style - 约束风格名称(类型:str / list)- 可使用风格因子列表见后表 \n lower_limit - 风格约束下限(单位为均值加n倍标准差,类型:int / float) \n upper_limit - 风格约束上限(单位为均值加n倍标准差,类型:int / float) \n relative - 是否基于基准(类型:bool;默认为False) \n priority - 软约束优先级(类型:int) |
个股风格除外约束 | ExcludeStyleConstraint | exclude_style - 除外风格名称(类型:str / list) \n lower_limit - 风格约束下限(单位为均值加n倍标准差,类型:int / float) \n upper_limit - 风格约束上限(单位为均值加n倍标准差,类型:int / float) \n relative - 是否基于基准(类型:bool;默认为False) \n priority - 软约束优先级(类型:int) |
个股行业约束 | IndustryWeigtedConstraint | style - 约束行业名称(类型:str / list)- 可使用行业因子列表见后表 \n lower_limit - 行业约束下限(单位为均值加n倍标准差,类型:int / float) \n upper_limit - 行业约束上限(单位为均值加n倍标准差,类型:int / float) \n relative - 是否基于基准(类型:bool;默认为False) \n priority - 软约束优先级(类型:int) |
个股行业除外约束 | ExcludeIndustryWeigtedConstraint | industry - 除外行业(类型:str / list) \n lower_limit - 除外行业约束下限(单位为均值加n倍标准差,类型:int / float) \n upper_limit - 除外行业约束上限(单位为均值加n倍标准差,类型:int / float) \n relative - 是否基于基准(类型:bool;默认为False) \n priority - 软约束优先级(类型:int) |
预期收益约束 | PredictReturnConstraint | lower_limit - 收益约束下限(类型:int / float) \n priority - 软约束优先级(类型:int) |
波动率约束 | VolatilityConstraint | upper_limit - 约束上限(类型:int / float) \n relative - 是否基于基准(类型:bool;默认为False) \n priority - 软约束优先级(类型:int) |
换手率约束 | TurnoverConstraint | turnrate - 换手率约束(类型:int / float) \n priority - 软约束优先级(类型:int) |
追踪误差上限约束 | TrackingError | upper_limit - 追踪误差上限(类型:int / float) \n priority - 软约束优先级(类型:int) |
基准成份股权重约束 | BenchmarkWeightedConstraint | lower_limit - 最低基准成份占比(类型:int / float) \n priority - 软约束优先级(类型:int) |
行业内个股权重约束 | IndustryComponentConstraint | industry - 行业名称(类型:int / list) \n limit - 最低行业内个股占比(类型:int / float) \n priority - 软约束优先级(类型:int) |
可用风格因子&行业因子
- 风格因子
- leverage
- beta
- momentum
- growth
- nonlinear_size
- liquidity
- size
- residual_volatility
- value
- 行业因子
- industry_prefix_* → 其中星号为申万一级行业code,具体code可见:
DataSource("basic_info_IndustrySw").read()
使用方法示例
目标函数&约束条件定义方法
目标函数只能有一个,约束条件可以通过列表的方式进行多个方法的存入
## 定义多个约束条件(list / str)
constraints = [
opt.StyleConstraint('beta', lower_limit=0.1, upper_limit=1, relative=True, priority=1), ## 风格约束
opt.ExcludeStyleConstraint('beta', lower_limit=-0.1, upper_limit=0.1, relative=True, priority=0), ## 风格除外约束
opt.TotalWeightsConstraint(upper_limit=1), ## 总权重约束
opt.Bounds(lower_limit=0, upper_limit=0.04, relative=True) ## 个股边界约束
]
## 定义目标函数
objective= opt.MaxReturn(lam=0.1)
## 权重优化
weights = opt.optimize(objective, current_date, constraints, stock_count=50, hard=False)
软硬约束定义:
其中,priority为当optimize中的hard=False时,即定义优化约束为软约束的时候,优化失败时会优先去掉priority值越小的约束。比如约束A的参数priority=1,约束B的参数priority=0,则在hard=False的时候,首次优化失败则会删除约束B进行第二次约束,若再次优化失败则删掉约束A,依次类推。约束条件中的TotalWeightsConstraint和Bounds是不带priority参数的,也就是说其不参与软硬约束的判断。
\
基于成长因子的中证500指数增强策略示例
# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
def m2_run_bigquant_run(input_1, input_2, input_3):
start_date = '2020-01-01'
end_date = '2020-10-16'
index_cons = DataSource('index_element_weight').read(start_date=start_date, end_date=end_date)
pred_data = index_cons[index_cons.instrument_index=='000905.HIX'][['instrument','weight','date']].reset_index(drop=True)
pred_df = DataSource.write_df(pred_data)
## instruments
ins = {}
stock_list = pred_data.instrument.unique().tolist()
ins['instruments'] = [x for x in stock_list if str(x) != 'nan']
ins['start_date'] = start_date
ins['end_date'] = end_date
ins = DataSource.write_pickle(ins)
return Outputs(data_1=ins, data_2=pred_df, data_3=None)
# 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。
def m2_post_run_bigquant_run(outputs):
return outputs
# 回测引擎:初始化函数,只执行一次
def m1_initialize_bigquant_run(context):
# 加载预测数据
context.stock_pools = context.options['data'].read()
context.show_debug_info = False
# 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
context.set_commission(PerOrder(buy_cost=0.0001, sell_cost=0.0001, min_cost=5))
context.options['hold_days'] = 22
context.stock_count = 100
context.trade_index = 0
context.opt = T.PORTFOLIO_OPTIMIZERS(context.stock_pools, context.start_date, context.end_date, model_type='daily', benchmark='000905.HIX')
# 回测引擎:每日数据处理函数,每天执行一次
def m1_handle_data_bigquant_run(context, data):
context.trade_index += 1 # 交易日历递增1
today = data.current_dt.strftime("%Y-%m-%d")
context.stock_pool = context.stock_pools[context.stock_pools.date == today]
if context.trade_index == 1: # 第一天建仓
try:
context.opt.get_today_factor_data(context.stock_pool, today) ##当日数据初始化
tf = context.opt.MinStyleDeviation({"growth":1}, if_pred=False, relative=False)
objective = tf[0]
cons = tf[1:]
# objective = context.opt.MaxReturn()
constraints = [context.opt.TotalWeightsConstraint(upper_limit=1), context.opt.Bounds(lower_limit=0, upper_limit=0.03),
context.opt.ExcludeStyleConstraint("growth", lower_limit=-0.1, upper_limit=0.1, relative=False, priority=0),
# context.opt.StyleConstraint("size", lower_limit=-0.1, upper_limit=0.1, relative=False, priority=0)
]
constraints.append(cons)
weights_data = context.opt.optimize(objective, today, constraints, stock_count=context.stock_count, verbose=False, response=True, hard=False)
def buy_1(df):
target = df["instrument"]
weight = df["weight"]
sid = context.symbol(target)
if data.can_trade(sid):
context.order_target_percent(sid, weight)
weights_data.apply(buy_1, axis=1)
except Exception as e:
print(today, "当前日期建仓失败! except:", e)
context.trade_index -= 1 # 交易日历索引保持不变,以便当日优化失败后次日接着优化
print('----------------------date {} over----------------------'.format(today))
if context.trade_index % context.options["hold_days"] == 0 and context.trade_index != 1: # 每隔调仓日进行调仓
positions_weight = {e.symbol: p.amount * p.last_sale_price / context.portfolio.portfolio_value for e, p in context.portfolio.positions.items()} # 持仓权重
equities = [e.symbol for e, p in context.portfolio.positions.items()] # 持仓股票列表
w0 = pd.Series(positions_weight, index=equities)
w0 = pd.DataFrame({'pre_weight': w0.values, 'instrument': w0.index})
context.stock_pool = pd.merge(context.stock_pool, w0, on=['instrument'], how='left').fillna(0)
context.opt.get_today_factor_data(context.stock_pool, today)
try:
tf = context.opt.MinStyleDeviation({"growth":1}, if_pred=False, relative=False)
objective = tf[0]
cons = tf[1:]
# objective = context.opt.MaxReturn()
constraints = [context.opt.TotalWeightsConstraint(upper_limit=1), context.opt.Bounds(lower_limit=0, upper_limit=0.03),
context.opt.ExcludeStyleConstraint("growth", lower_limit=-0.1, upper_limit=0.1, relative=False, priority=0),
# context.opt.StyleConstraint("size", lower_limit=-0.1, upper_limit=0.1, relative=False, priority=0)
]
constraints.append(cons)
weights_data = context.opt.optimize(objective, today, constraints, stock_count=context.stock_count, verbose=False, response=True, hard=False)
# 卖出逻辑
need_hold_stocks = set(weights_data.instrument)
for sx in equities:
if sx not in need_hold_stocks: # 无法交易的持仓、优化股票之外的持仓 直接卖出
order_target_percent(context.symbol(sx), 0)
equities.remove(sx)
positions_weight = {e:p for e, p in positions_weight.items() if e != sx}
# 买入逻辑
def buy_2(df):
target = df["instrument"]
weight = df["weight"]
sid = context.symbol(target)
if data.can_trade(sid):
context.order_target_percent(sid, weight)
weights_data.apply(buy_2, axis=1)
except Exception as e:
print(today, "当前日期调仓失败! except:", e)
print('----------------------date {} over----------------------'.format(today))
# 回测引擎:准备数据,只执行一次
def m1_prepare_bigquant_run(context):
pass
# 回测引擎:每个单位时间开始前调用一次,即每日开盘前调用一次。
def m1_before_trading_start_bigquant_run(context, data):
pass
m2 = M.cached.v3(
run=m2_run_bigquant_run,
post_run=m2_post_run_bigquant_run,
input_ports='',
params='{}',
output_ports=''
)
m1 = M.trade.v4(
instruments=m2.data_1,
options_data=m2.data_2,
start_date='',
end_date='',
initialize=m1_initialize_bigquant_run,
handle_data=m1_handle_data_bigquant_run,
prepare=m1_prepare_bigquant_run,
before_trading_start=m1_before_trading_start_bigquant_run,
volume_limit=0.025,
order_price_field_buy='open',
order_price_field_sell='open',
capital_base=100000000,
auto_cancel_non_tradable_orders=True,
data_frequency='daily',
price_type='真实价格',
product_type='股票',
plot_charts=True,
backtest_only=False,
benchmark='000905.HIX'
)
m3 = M.strategy_ret_risk_analysis.v2(
input_1=m1.raw_perf,
analysis_flag='relative',
benchmark_index='000905.HIX',
terms='daily'
)
基于动量因子的中证500指数增强策略示例
# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
def m1_run_bigquant_run(input_1, input_2, input_3):
start_date = '2020-01-01'
end_date = '2020-10-16'
index_cons = DataSource('index_element_weight').read(start_date=start_date, end_date=end_date)
pred_data = index_cons[index_cons.instrument_index=='000905.HIX'][['instrument','weight','date']].reset_index(drop=True)
pred_df = DataSource.write_df(pred_data)
## instruments
ins = {}
stock_list = pred_data.instrument.unique().tolist()
ins['instruments'] = [x for x in stock_list if str(x) != 'nan']
ins['start_date'] = start_date
ins['end_date'] = end_date
ins = DataSource.write_pickle(ins)
return Outputs(data_1=ins, data_2=pred_df, data_3=None)
# 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。
def m1_post_run_bigquant_run(outputs):
return outputs
# 回测引擎:初始化函数,只执行一次
def m2_initialize_bigquant_run(context):
# 加载预测数据
context.stock_pools = context.options['data'].read()
context.show_debug_info = False
# 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
context.set_commission(PerOrder(buy_cost=0.0001, sell_cost=0.0001, min_cost=5))
context.options['hold_days'] = 22
context.stock_count = 100
context.trade_index = 0
context.opt = T.PORTFOLIO_OPTIMIZERS(context.stock_pools, context.start_date, context.end_date, model_type='daily', benchmark='000905.HIX')
# 回测引擎:每日数据处理函数,每天执行一次
def m2_handle_data_bigquant_run(context, data):
context.trade_index += 1 # 交易日历递增1
today = data.current_dt.strftime("%Y-%m-%d")
context.stock_pool = context.stock_pools[context.stock_pools.date == today]
if context.trade_index == 1: # 第一天建仓
try:
context.opt.get_today_factor_data(context.stock_pool, today) ##当日数据初始化
tf = context.opt.MinStyleDeviation({"momentum":1})
objective = tf[0]
cons = tf[1:]
# objective = context.opt.MaxReturn()
constraints = [context.opt.TotalWeightsConstraint(upper_limit=1), context.opt.Bounds(lower_limit=0, upper_limit=0.03),
context.opt.ExcludeStyleConstraint("momentum", lower_limit=-0.1, upper_limit=0.1, priority=0),
]
constraints.append(cons)
weights_data = context.opt.optimize(objective, today, constraints, stock_count=context.stock_count, verbose=False, response=True, hard=False)
def buy_1(df):
target = df["instrument"]
weight = df["weight"]
sid = context.symbol(target)
if data.can_trade(sid):
context.order_target_percent(sid, weight)
weights_data.apply(buy_1, axis=1)
except Exception as e:
print(today, "当前日期建仓失败! except:", e)
context.trade_index -= 1 # 交易日历索引保持不变,以便当日优化失败后次日接着优化
print('----------------------date {} over----------------------'.format(today))
if context.trade_index % context.options["hold_days"] == 0 and context.trade_index != 1: # 每隔调仓日进行调仓
positions_weight = {e.symbol: p.amount * p.last_sale_price / context.portfolio.portfolio_value for e, p in context.portfolio.positions.items()} # 持仓权重
equities = [e.symbol for e, p in context.portfolio.positions.items()] # 持仓股票列表
w0 = pd.Series(positions_weight, index=equities)
w0 = pd.DataFrame({'pre_weight': w0.values, 'instrument': w0.index})
context.stock_pool = pd.merge(context.stock_pool, w0, on=['instrument'], how='left').fillna(0)
context.opt.get_today_factor_data(context.stock_pool, today)
try:
tf = context.opt.MinStyleDeviation({"momentum":1})
objective = tf[0]
cons = tf[1:]
constraints = [context.opt.TotalWeightsConstraint(upper_limit=1), context.opt.Bounds(lower_limit=0, upper_limit=0.03),
context.opt.ExcludeStyleConstraint("momentum", lower_limit=-0.1, upper_limit=0.1, priority=0),
]
constraints.append(cons)
weights_data = context.opt.optimize(objective, today, constraints, stock_count=context.stock_count, verbose=False, response=True, hard=False)
# 卖出逻辑
need_hold_stocks = set(weights_data.instrument)
for sx in equities:
if sx not in need_hold_stocks: # 无法交易的持仓、优化股票之外的持仓 直接卖出
order_target_percent(context.symbol(sx), 0)
equities.remove(sx)
positions_weight = {e:p for e, p in positions_weight.items() if e != sx}
# 买入逻辑
def buy_2(df):
target = df["instrument"]
weight = df["weight"]
sid = context.symbol(target)
if data.can_trade(sid):
context.order_target_percent(sid, weight)
weights_data.apply(buy_2, axis=1)
except Exception as e:
print(today, "当前日期调仓失败! except:", e)
print('----------------------date {} over----------------------'.format(today))
# 回测引擎:准备数据,只执行一次
def m2_prepare_bigquant_run(context):
pass
# 回测引擎:每个单位时间开始前调用一次,即每日开盘前调用一次。
def m2_before_trading_start_bigquant_run(context, data):
pass
m1 = M.cached.v3(
run=m1_run_bigquant_run,
post_run=m1_post_run_bigquant_run,
input_ports='',
params='{}',
output_ports='',
m_cached=False
)
m2 = M.trade.v4(
instruments=m1.data_1,
options_data=m1.data_2,
start_date='',
end_date='',
initialize=m2_initialize_bigquant_run,
handle_data=m2_handle_data_bigquant_run,
prepare=m2_prepare_bigquant_run,
before_trading_start=m2_before_trading_start_bigquant_run,
volume_limit=0.025,
order_price_field_buy='open',
order_price_field_sell='open',
capital_base=100000000,
auto_cancel_non_tradable_orders=True,
data_frequency='daily',
price_type='真实价格',
product_type='股票',
plot_charts=True,
backtest_only=False,
benchmark='000905.HIX'
)
m4 = M.strategy_ret_risk_analysis.v2(
input_1=m2.raw_perf,
analysis_flag='relative',
benchmark_index='000905.HIX',
terms='daily',
m_cached=False
)
基于AI模型预测结果的指数增强策略
# 回测引擎:初始化函数,只执行一次
def m19_initialize_bigquant_run(context):
context.stock_pools = context.options['data'].read()
context.show_debug_info = False
context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
context.options['hold_days'] = 5
context.stock_count = 5
context.trade_index = 0
context.opt = T.PORTFOLIO_OPTIMIZERS(context.stock_pools, context.start_date, context.end_date, model_type='daily', benchmark='000905.HIX')
# 回测引擎:每日数据处理函数,每天执行一次
def m19_handle_data_bigquant_run(context, data):
context.trade_index += 1 # 交易日历递增1
today = data.current_dt.strftime("%Y-%m-%d")
print('current_date is:', today)
context.stock_pool = context.stock_pools[context.stock_pools.date == today]
if context.trade_index == 1: # 第一天建仓
try:
context.opt.get_today_factor_data(context.stock_pool, today) ##当日数据初始化
objective = context.opt.MaxScore()
constraints = [
context.opt.TotalWeightsConstraint(upper_limit=1), context.opt.Bounds(lower_limit=0, upper_limit=0.2, relative=True),
context.opt.ExcludeStyleConstraint("size",lower_limit=-0.1,upper_limit=0.1,relative=True, priority=1)
]
weights_data = context.opt.optimize(objective, today, constraints, stock_count=context.stock_count, verbose=False, response=True, hard=False)
def buy_1(df):
target = df["instrument"]
weight = df["weight"]
sid = context.symbol(target)
if data.can_trade(sid):
context.order_target_percent(sid, weight)
else:
print(f"{today} {target} 无法交易")
weights_data.apply(buy_1, axis=1)
except Exception as e:
print(today, "当前日期建仓失败! except:", e)
context.trade_index -= 1 # 交易日历索引保持不变,以便当日优化失败后次日接着优化
if context.trade_index % context.options["hold_days"] == 0 and context.trade_index != 1: # 每隔调仓日进行调仓
positions_weight = {e.symbol: p.amount * p.last_sale_price / context.portfolio.portfolio_value for e, p in context.portfolio.positions.items()} # 持仓权重
equities = [e.symbol for e, p in context.portfolio.positions.items()] # 持仓股票列表
w0 = pd.Series(positions_weight, index=equities)
w0 = pd.DataFrame({'pre_weight': w0.values, 'instrument': w0.index})
context.stock_pool = pd.merge(context.stock_pool, w0, on=['instrument'], how='left').fillna(0)
context.opt.get_today_factor_data(context.stock_pool, today)
try:
objective = context.opt.MaxScore()
constraints = [
context.opt.TotalWeightsConstraint(upper_limit=1), context.opt.Bounds(lower_limit=0, upper_limit=0.2, relative=True),
context.opt.ExcludeStyleConstraint("size",lower_limit=-0.1,upper_limit=0.1,relative=True, priority=1),
context.opt.TurnoverConstraint(turnrate=0.2, priority=0)
]
weights_data = context.opt.optimize(objective, today, constraints, stock_count=context.stock_count, verbose=False, response=True, hard=False)
# 卖出逻辑
need_hold_stocks = set(weights_data.instrument)
for sx in equities:
if sx not in need_hold_stocks: # 无法交易的持仓、优化股票之外的持仓 直接卖出
order_target_percent(context.symbol(sx), 0)
equities.remove(sx)
positions_weight = {e:p for e, p in positions_weight.items() if e != sx}
# 买入逻辑
def buy_2(df):
target = df["instrument"]
weight = df["weight"]
sid = context.symbol(target)
if data.can_trade(sid):
context.order_target_percent(sid, weight)
else:
print(f"{today} {target} 无法交易")
weights_data.apply(buy_2, axis=1)
except Exception as e:
print(today, "当前日期调仓失败! except:", e)
print('----------------------------------------------------------------------------------------date {} over----------------------------------------------------------------------------------------'.format(today))
# 回测引擎:准备数据,只执行一次
def m19_prepare_bigquant_run(context):
pass
m1 = M.instruments.v2(
start_date='2010-01-01',
end_date='2016-01-01',
market='CN_STOCK_A',
instrument_list='',
max_count=0
)
m2 = M.advanced_auto_labeler.v2(
instruments=m1.data,
label_expr="""# #号开始的表示注释
# 0. 每行一个,顺序执行,从第二个开始,可以使用label字段
# 1. 可用数据字段见 https://bigquant.com/docs/develop/datasource/deprecated/history_data.html
# 添加benchmark_前缀,可使用对应的benchmark数据
# 2. 可用操作符和函数见 `表达式引擎 <https://bigquant.com/docs/develop/bigexpr/usage.html>`_
# 计算收益:5日收盘价(作为卖出价格)除以明日开盘价(作为买入价格)
shift(close, -5) / shift(open, -1)
# 极值处理:用1%和99%分位的值做clip
clip(label, all_quantile(label, 0.01), all_quantile(label, 0.99))
# 将分数映射到分类,这里使用20个分类
all_wbins(label, 20)
# 过滤掉一字涨停的情况 (设置label为NaN,在后续处理和训练中会忽略NaN的label)
where(shift(high, -1) == shift(low, -1), NaN, label)
""",
start_date='',
end_date='',
benchmark='000300.SHA',
drop_na_label=True,
cast_label_int=True
)
m3 = M.input_features.v1(
features="""# #号开始的表示注释
# 多个特征,每行一个,可以包含基础特征和衍生特征
return_5
return_10
return_20
avg_amount_0/avg_amount_5
avg_amount_5/avg_amount_20
rank_avg_amount_0/rank_avg_amount_5
rank_avg_amount_5/rank_avg_amount_10
rank_return_0
rank_return_5
rank_return_10
rank_return_0/rank_return_5
rank_return_5/rank_return_10
pe_ttm_0
"""
)
m15 = M.general_feature_extractor.v7(
instruments=m1.data,
features=m3.data,
start_date='',
end_date='',
before_start_days=90
)
m16 = M.derived_feature_extractor.v3(
input_data=m15.data,
features=m3.data,
date_col='date',
instrument_col='instrument',
drop_na=False,
remove_extra_columns=False
)
m7 = M.join.v3(
data1=m2.data,
data2=m16.data,
on='date,instrument',
how='inner',
sort=False
)
m13 = M.dropnan.v1(
input_data=m7.data
)
m6 = M.stock_ranker_train.v5(
training_ds=m13.data,
features=m3.data,
learning_algorithm='排序',
number_of_leaves=30,
minimum_docs_per_leaf=1000,
number_of_trees=20,
learning_rate=0.1,
max_bins=1023,
feature_fraction=1,
m_lazy_run=False
)
m9 = M.instruments.v2(
start_date=T.live_run_param('trading_date', '2016-01-01'),
end_date=T.live_run_param('trading_date', '2016-12-31'),
market='CN_STOCK_A',
instrument_list='',
max_count=0
)
m17 = M.general_feature_extractor.v7(
instruments=m9.data,
features=m3.data,
start_date='',
end_date='',
before_start_days=90
)
m18 = M.derived_feature_extractor.v3(
input_data=m17.data,
features=m3.data,
date_col='date',
instrument_col='instrument',
drop_na=False,
remove_extra_columns=False
)
m14 = M.dropnan.v1(
input_data=m18.data
)
m8 = M.stock_ranker_predict.v5(
model=m6.model,
data=m14.data,
m_lazy_run=False
)
m19 = M.trade.v4(
instruments=m9.data,
options_data=m8.predictions,
start_date='',
end_date='',
initialize=m19_initialize_bigquant_run,
handle_data=m19_handle_data_bigquant_run,
prepare=m19_prepare_bigquant_run,
volume_limit=0.025,
order_price_field_buy='open',
order_price_field_sell='close',
capital_base=1000000,
auto_cancel_non_tradable_orders=True,
data_frequency='daily',
price_type='真实价格',
product_type='股票',
plot_charts=True,
backtest_only=False,
benchmark='000905.HIX'
)
m4 = M.barra_risk_factor_analysis1.v8(
input_1=m19.raw_perf,
analysis_flag='relative',
benchmark_index='000905.HIX',
terms='daily'
)
\