将不同股票的相同因子按照它们的升序/逆序排列起来,根据股票的数量给这些因子进行打分(因子升序的,值越小越好,即值越小,分越高;因子降序的,值越大越好,即值越大,分数越高),打完分后,计算每一只股票的总得分,按照从高到底排列,选取排名靠前的股票。
示例:
# 可以自己import我们平台支持的第三方python模块,比如pandas、numpy等。
import pandas as pd
# 在这个方法中编写任何的初始化逻辑。context对象将会在你的算法策略的任何方法之间做传递。
def init(context):
# 1、定义选股的数量
context.stocks_num = 20
# 2、定义分组的组数
context.groups_num = 10
# 3、定义月定时器
scheduler.run_monthly(score_select, tradingday=1)
# 实现打分法选股策略
def score_select(context, bar_dict):
# 1、获取因子数据
q = query(fundamentals.eod_derivative_indicator.market_cap,
fundamentals.eod_derivative_indicator.pe_ratio,
fundamentals.eod_derivative_indicator.pb_ratio,
fundamentals.financial_indicator.return_on_invested_capital,
fundamentals.financial_indicator.inc_revenue,
fundamentals.financial_indicator.inc_profit_before_tax)
fund = get_fundamentals(q)
factor_data = fund.T
# print(factor_data)
# 不需要进行去极值、标准化、市值中性化(打分法选股只需知道排名)
# 处理缺失值
factor_data = factor_data.dropna()
# 2、进行打分,得出股票列表
select_stocks(context, factor_data)
# 3、每月调仓
rebalance(context)
def select_stocks(context, factor_data):
# 分组打分
for factor in factor_data.columns:
# 根据因子方向进行不同处理
# 越小越好:市值、市盈率、市净率
if factor in ["market_cap", "pe_ratio", "pb_ratio"]:
sorted_factor = factor_data.sort_values(by=factor)[factor]
# print("sorted_factor:\n", sorted_factor)
# print("sorted_factor类型:\n", type(sorted_factor))
# 越大越好:ROIC、inc_revenue营业总收入和inc_profit_before_tax利润增长率
else:
sorted_factor = factor_data.sort_values(by=factor, ascending=False)[factor]
# print("sorted_factor:\n", sorted_factor)
# 分组打分
# 将sorted_factor转换成dataframe方便我们打分
sorted_factor = pd.DataFrame(sorted_factor)
sorted_factor[factor+"_score"] = 0
# print(sorted_factor)
# 计算每组的股票数量
stock_count = len(sorted_factor) // context.groups_num
for i in range(context.groups_num):
if i == context.groups_num - 1:
sorted_factor[factor+"_score"][i*stock_count:] = i+1
else:
sorted_factor[factor+"_score"][i*stock_count:(i+1)*stock_count] = i+1
# 合并所有因子的分数
factor_data = pd.concat([factor_data, sorted_factor[factor+"_score"]], axis=1)
# print("合并后的表:\n", factor_data)
# 分数加和
sum_score = factor_data.iloc[:, 6:].sum(1).sort_values()
# 选股结果
context.stocks = sum_score[:context.stocks_num].index
# print(sum_score)
# print(context.stocks)
def rebalance(context):
# 卖出
for stock in context.portfolio.positions.keys():
if context.portfolio.positions[stock].quantity > 0:
if stock not in context.stocks:
order_target_percent(stock, 0)
# 买入
for stock in context.stocks:
order_target_percent(stock, 1.0/context.stocks_num)
# before_trading此函数会在每天策略交易开始前被调用,当天只会被调用一次
def before_trading(context):
pass
# 你选择的证券的数据更新将会触发此段逻辑,例如日或分钟历史数据切片或者是实时数据切片更新
def handle_bar(context, bar_dict):
pass
# after_trading函数会在每天交易结束后被调用,当天只会被调用一次
def after_trading(context):
pass
流程分析:
示例:
# 可以自己import我们平台支持的第三方python模块,比如pandas、numpy等。
import numpy as np
from sklearn.linear_model import LinearRegression
# 在这个方法中编写任何的初始化逻辑。context对象将会在你的算法策略的任何方法之间做传递。
# 9个因子——9个回归系数
# (300,9)* (9,1) = (300, 1)
# 流程分析:
# 确定回测区间:
# 20160201~20180501
# 确定选股范围:沪深300
# 确定选股个数:20
# 要进行数据处理:处理缺失值、去极值、标准化、市值中性化
# 进行矩阵相乘得到预测的收益率,排名,取前20——拿到股票池
# 调仓:每月调仓
def init(context):
# 定义选股个数
context.stocks_num = 20
# 定义股票池
context.hs300 = index_components("000300.XSHG")
# print(context.hs300)
# 定义回归系数
context.weights = np.array([0.00173715, -0.00883514, -0.02254567, 0.00599249, -0.00484171,
0.01718375, -0.00531301, 0.07165389, -0.05540408])
# 定义月定时器
scheduler.run_monthly(regression_select, tradingday=1)
# 回归法选股逻辑
def regression_select(context, bar_dict):
# 1、获取因子值
q = query(fundamentals.eod_derivative_indicator.pe_ratio,
fundamentals.eod_derivative_indicator.pb_ratio,
fundamentals.eod_derivative_indicator.market_cap,
fundamentals.financial_indicator.ev,
fundamentals.financial_indicator.return_on_asset_net_profit,
fundamentals.financial_indicator.du_return_on_equity,
fundamentals.financial_indicator.earnings_per_share,
fundamentals.income_statement.revenue,
fundamentals.income_statement.total_expense).filter(
fundamentals.stockcode.in_(context.hs300))
fund = get_fundamentals(q)
context.factor_data = fund.T
# print(context.factor_data)
# 2、因子数据处理:缺失值处理、去极值、标准化、市值中性化
dealwith_data(context)
# 3、回归选股
select_stocks(context)
# 4、调仓
rebalance(context)
def dealwith_data(context):
# 1)缺失值处理
context.factor_data = context.factor_data.dropna()
# 2)去极值、标准化、市值中性化
# 保留市值
x = context.factor_data["market_cap"].reshape(-1, 1)
# 循环进行数据处理
for factor in context.factor_data.columns:
# print(factor)
# 去极值
context.factor_data[factor] = med_method(context.factor_data[factor])
# 标准化
context.factor_data[factor] = stand_method(context.factor_data[factor])
# 市值中性化
if factor == "market_cap":
continue
y = context.factor_data[factor]
# 线性回归预估器流程
estimator = LinearRegression()
estimator.fit(x, y)
y_predict = estimator.predict(x)
context.factor_data[factor] = y - y_predict
def select_stocks(context):
# 看一下样本量
# print(context.factor_data.shape)
# 方法1:矩阵相乘 (300, 9) * (9, 1) = (300, 1)
# 方法2:数组相乘
# print(context.weights.shape)
sum = np.dot(context.factor_data, context.weights)
context.factor_data["return"] = sum
# print(context.factor_data)
# 排序选股
context.factor_data = context.factor_data.sort_values(by="return", ascending=False)
# print(context.factor_data)
# 拿到股票池
context.stocks = context.factor_data.index[:context.stocks_num]
def rebalance(context):
print(context.stocks)
# 卖出
for stock in context.portfolio.positions.keys():
if context.portfolio.positions[stock].quantity > 0:
if stock not in context.stocks:
order_target_percent(stock, 0)
# 买入
for stock in context.stocks:
order_target_percent(stock, 1.0/context.stocks_num)
# before_trading此函数会在每天策略交易开始前被调用,当天只会被调用一次
def before_trading(context):
pass
# 你选择的证券的数据更新将会触发此段逻辑,例如日或分钟历史数据切片或者是实时数据切片更新
def handle_bar(context, bar_dict):
pass
# after_trading函数会在每天交易结束后被调用,当天只会被调用一次
def after_trading(context):
pass
def med_method(factor):
# 1、找到MAD值
med = np.median(factor)
distance = abs(factor - med)
MAD = np.median(distance)
# 2、求出MAD_e
MAD_e = 1.4826 * MAD
# 3、求出正常值范围的边界
up_scale = med + 3 * MAD_e
down_scale = med - 3 * MAD_e
# 4、替换
factor = np.where(factor > up_scale, up_scale, factor)
factor = np.where(factor < down_scale, down_scale, factor)
return factor
# 自实现标准化
# (x - mean) / std
def stand_method(factor):
mean = np.mean(factor)
std = np.std(factor)
factor = (factor - mean) / std
return factor