Python量化交易系统实战--设计交易策略:选股策略

 作者:麦克煎蛋   出处:https://www.cnblogs.com/mazhiyong/ 转载请保留这段声明,谢谢!

 

这一节主要是了解基于“动量因子”的选股策略。
动量因子指的是股票在一段周期内的涨跌幅度 ,其本质是追涨杀跌。而选股策略,指的是基于这个因子的表现进行股票筛选,以及买入、卖出的操作。

该文章的策略和方法非常简单。仅适用于入门了解。

一、筛选股票池

考虑到成交活跃以及买入卖出的顺畅,这里选择的是沪深300持有个股。

def get_index_list(index_symbol='000300.XSHG'):
    """
    获取指数成分股,指数代码查询:https://www.joinquant.com/indexData
    :param index_symbol: 指数的代码,默认沪深300
    :return: list,成分股代码
    """
    stocks = get_index_stocks(index_symbol, '2023-01-09')
    return stocks
def get_data(start_date, end_date, use_cols, index_symbol='000300.XSHG'):
    """
    获取股票收盘价数据,并拼接为一个df
    :param start_date: str
    :param end_date: str
    :param use_cols: list
    :param index_symbol: str
    :return data_concat: df,拼接后的数据表
    """
    # 获取股票列表代码:沪深300持有个股、创业板、上证
    stocks = st.get_index_list(index_symbol)
    # 拼接收盘价数据
    data_concat = pd.DataFrame()
    # 获取股票数据,这里为了测试方便取前10条
    for code in stocks[0:10]:
        data = st.get_csv_price(code, start_date, end_date, use_cols)
    return data

二、计算动量因子

1、计算策略

① 确定交易对象:股票池、考虑流动性(沪深300、创业板)
② 选定业绩评价周期:过去1~12个月
③ 计算形成期收益率:过去N个月的收益率 ---> 生成交易信号
④ 对收益率进行排序:最佳~赢家组合、最差~输家组合
⑤ 确定持仓/换仓周期: 1个月、可自定义测算
⑥ 连续或间隔一-段时期 ,不断重复②- -⑤行为
⑦ 计算动量/反向策略各持有期的回报率
⑧ 计算t/p统计值,判断是否存在动量效应

2、数据源

拼接股票池的数据为一张大表:

def get_data(start_date, end_date, use_cols, index_symbol='000300.XSHG'):
    """
    获取股票收盘价数据,并拼接为一个df
    :param start_date: str
    :param end_date: str
    :param use_cols: list
    :param index_symbol: str
    :return data_concat: df,拼接后的数据表
    """
    # 获取股票列表代码:沪深300持有个股、创业板、上证
    stocks = st.get_index_list(index_symbol)
    # 拼接收盘价数据
    data_concat = pd.DataFrame()
    # 获取股票数据,这里为了测试方便取前10条
    for code in stocks[0:10]:
        data = st.get_csv_price(code, start_date, end_date, use_cols)
        # 拼接多个股票的收盘价:日期 股票A收盘价 股票B收盘价 ...
        data.columns = [code]
        data_concat = pd.concat([data_concat, data], axis=1)
    # 预览股票数据
    # print(data_concat.tail())
    return data_concat

3、具体计算过程

  • 按月计算收益率。
  • 根据收益率生成交易信号(这里的策略简化为买入排名靠前的,卖出排名靠后的)。
  • 根据交易信号计算投资组合收益率。
  • 评估策略结果。
def momentum(data_concat, shift_n=1, top_n=4):
    """
    :param data_concat: df
    :param shift_n: int,表示业绩统计周期(单位:月)
    :return:
    """
    # 转换时间频率:日->月
    data_concat.index = pd.to_datetime(data_concat.index)
    data_month = data_concat.resample('ME').last()

    # 计算过去N个月的收益率 = 期末值/期初值 - 1 =(期末-期初)/ 期初
    shift_return = data_month / data_month.shift(shift_n) - 1
    # print(shift_return.head())
    # print(shift_return.shift(-1))

    # 生成交易信号:收益率排前n的>赢家组合>买入1,排最后n个>输家>卖出-1
    buy_signal = get_top_stocks(shift_return, top_n)
    sell_signal = get_top_stocks(-1 * shift_return, top_n)
    signal = buy_signal - sell_signal
    # print(signal.head())

    # 计算投资组合收益率
    returns = base.caculate_portfolio_return(shift_return, signal, top_n * 2)
    print(returns.head())

    # 评估策略效果:总收益率、年化收益率、最大回撤、夏普比
    returns = base.evaluate_strategy(returns)

    # 数据预览
    # print(data_month.head())
    return returns

关键函数:

def caculate_portfolio_return(data, signal, n):
    """
    计算组合收益率
    :param data: dataframe
    :param signal: dataframe
    :param n: int
    :return returns: dataframe
    """
    returns = data.copy()
    # 投组收益率(等权重)= 收益率之和 / 股票个数
    # 信号发出的指令是针对的下一个月的指令,所以数据要后移
    returns['profit_pct'] = (signal * returns.shift(-1)).T.sum() / n
    returns = calculate_cum_prof(returns)

    return returns.shift(1)  # 匹配对应的交易月份

策略评估函数:

def evaluate_strategy(data):
    """
    评估策略收益表现
    :param data: dataframe, 包含单次收益率数据
    :return results: dict, 评估指标数据
    """
    # 评估策略效果:总收益率、年化收益率、最大回撤、夏普比
    data = calculate_cum_prof(data)

    # 获取总收益率
    total_return = data['cum_profit'].iloc[-1]
    # 计算年化收益率(每月开仓)
    annual_return = data['profit_pct'].mean() * 12

    # 计算近一年最大回撤
    data = caculate_max_drawdown(data, window=12)
    # print(data)
    # 获取近一年最大回撤
    max_drawdown = data['max_dd'].iloc[-1]

    # 计算夏普比率
    sharpe, annual_sharpe = calculate_sharpe(data)

    # 放到dict中
    results = {'总收益率': total_return, '年化收益率': annual_return,
               '最大回撤': max_drawdown, '夏普比率': annual_sharpe}

    # 打印评估指标
    for key, value in results.items():
        print(key, value)

    return data

 

 

posted on 2024-04-18 12:08  麦克煎蛋  阅读(464)  评论(0编辑  收藏  举报