量化交易_4

概要

  • 选股的时候需要有权重的参考来选择,所以确定权重也是最终进行选股的依据
  • 确定权重的方法:
    • 打分法选股策略
    • 回归法选股策略
  • 模拟交易

多因子策略的流程

  • 1.准备数据,确定因子所需数据
  • 2.单因子的有效性分析
  • 3.多因子组合
  • 4.确定因子权重
  • 5.确定股票池,以排序选股
  • 6.确定调仓周期
  • 7.计算组合业绩

打分法选股策略

  • 将不同股票的相同因子按照它们的升序/逆序排列起来,根据股票的数量给这些因子进行打分(因子升序的,值越小越好,即值越小,分越高;因子降序的,值越大越好,即值越大,分数越高),打完分后,计算每一只股票的总得分,按照从高到底排列,选取排名靠前的股票。

  • 示例:

# 可以自己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


回归法选股策略

  • 通过已经筛选出来的多个因子暴露值与收益率建立回归
  • 1.回归训练确定回归系数
  • 2.利用回归系数进行回测
  • 流程分析:

    • 1.确定回测区间
    • 2.确定选股范围
    • 3.确定选股个数
    • 4.进行数据处理:处理缺失值,去极值,标准化,市值中性化
    • 5.进行矩阵相乘得到预测的收益率,排名,取前20-拿到股票池
    • 6.调仓
  • 示例:

  # 可以自己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


模拟交易

  • 必须先进行一次分钟回测,然后在进行模拟交易
  • 可以设置微信通知交易信号进行真实股票的买卖

你可能感兴趣的:(学习日志)