打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
股票因子扩展1(涨停因子计算)

前文介绍了股票日线数据下载,从本文起开始记录一些股票因子的计算方法,这些因子将用于后续策略的编写。

我们将实现双神穿多线策略,策略的选股条件是,股票当日形成双神(间隔的2个涨停),K线同时上穿5、10、20、30日均线,30日线在60日线上方,把当日涨停收盘价格定义为买点buy_point。买入价格为后续日期开盘价与buy_point的较小值,卖出止盈价格为buy_point*(1+6.18%),止损价格为buy_point*(1-16.18%)。

在写本系列文章之前,尚未对该策略进行参数调整、胜率统计、回测分析,就目前观察的几只个股来看,都有不错的涨幅。读者可以参与一起实现和优化,共同打造成一个实盘策略。

该策略在2018年至2020年3年周期回测后,年化收益为41.7%,最大回撤为25.8%。

本文首先计算涨停因子。

主要代码分析

新建源文件,命名为data_center_v3.py,全部内容见文末,v3主要涉及3个方面的改动:

新增计算涨停因子函数

def zt(df):

该函数用于计算涨停因子,其中:

  • 参数df为待计算扩展因子的DataFrame
  • 返回值为包含扩展因子的DataFrame

这里以当日收盘价较前一日收盘价上涨9.8%及以上作为涨停判断标准。若涨停,则因子为True,否则为False。

    df['zt'] = np.where((df['close'].values >= 1.098 * df['preclose'].values), True, False)

计算涨停因子,考虑到复权以及创业板和科创板涨停为涨幅20%,这里把当日收盘价较前一日收盘价上涨9.8%及以上都作为涨停。

    return df

返回包含扩展因子的DataFrame

新增计算扩展因子

def extend_factor(df):

该函数用于计算扩展因子,其中:

  • 参数df为待计算扩展因子的DataFrame
  • 返回值为包含扩展因子的DataFrame

在v3中只计算涨停因子,后续会添加双神等因子的计算。

    df = df.pipe(zt)

使用pipe调用函数zt,计算涨停因子

    return df

返回包含扩展因子的DataFrame。

修改创建数据函数

def create_data(stock_codes, from_date='1990-12-19', to_date=datetime.date.today().strftime('%Y-%m-%d'), adjustflag='2'):
    """
    下载指定日期内,指定股票的日线数据,计算扩展因子

    :param stock_codes: 待下载数据的股票代码
    :param from_date: 日线开始日期
    :param to_date: 日线结束日期
    :param adjustflag: 复权选项 1:后复权  2:前复权  3:不复权  默认为前复权
    :return: None
    """

    # 下载股票循环
    for code in stock_codes:
        print('正在下载{}...'.format(code))

        # 登录BaoStock
        bs.login()

        # 下载日线数据
        out_df = bs.query_history_k_data_plus(code, g_baostock_data_fields, start_date=from_date, end_date=to_date,
                                              frequency='d', adjustflag=adjustflag).get_data()

        # 注销登录
        bs.logout()

        # 剔除停盘数据
        if out_df.shape[0]:
            out_df = out_df[(out_df['volume'] != '0') & (out_df['volume'] != '')]

以上内容与v2相同,可参考v2分析内容

        if not out_df.shape[0]:
            continue

如果数据为空,则不进行后续过滤及扩展因子计算。

        out_df.drop_duplicates(['date'], inplace=True)

曾遇到过出现重复数据的情况,加一道去重过滤。

        if out_df.shape[0] < g_available_days_limit:
            continue

这里设置只处理已有多于等于g_available_days_limit根日线数据的股票,如果可用的日线数据少于g_available_days_limit根,则不创建数据,来确保后续可以有效计算扩展因子。
在文件开头我们设置了全局变量:

g_available_days_limit = 250
        convert_list = ['open', 'high', 'low', 'close', 'preclose', 'volume', 'amount', 'turn', 'pctChg']
        out_df[convert_list] = out_df[convert_list].astype(float)

把相关字段类型转化为float类型,BaoStock下载得到的这些字段默认为str类型,需要转化为float类型,才能用于后续指标计算。

        out_df.reset_index(drop=True, inplace=True)

重置索引,由于我们进行了去重、剔除停盘数据等操作,需要对索引进行重置,来保持索引的连续性。

        out_df = extend_factor(out_df)

调用函数extend_factor计算扩展因子。

        print(out_df)

打印数据创建结果,我们来看一下三美股份sh.603379的打印结果:

           date       open       high  ...   pcfNcfTTM  isST     zt
0    2019-04-02  32.652593  32.652593  ...   76.815822     0   True
1    2019-04-03  35.917853  35.917853  ...   84.497404     0   True
2    2019-04-04  39.511735  39.511735  ...   92.952079     0   True
3    2019-04-08  43.462210  43.462210  ...  102.245642     0   True
4    2019-04-09  47.755292  47.755292  ...   97.278109     0  False
..          ...        ...        ...  ...         ...   ...    ...
598  2021-09-13  31.580000  33.380000  ...  -70.841885     0  False
599  2021-09-14  32.520000  35.000000  ...  -71.822773     0  False
600  2021-09-15  33.020000  36.250000  ...  -79.015949     0   True
601  2021-09-16  37.900000  38.000000  ...  -77.381136     0  False
602  2021-09-17  35.510000  39.050000  ...  -85.119250     0   True

[603 rows x 18 columns]

倒数第三行和最后一行显示2021年9月15日和17日为涨停,对应看一下K线图:

也可以看到2021年9月15日和17日均为涨停,计算结果正确。

小结

本文主要介绍了要实现的策略的思路,完成了涨停因子的计算,后续继续介绍策略所需的其他因子的实现方式。

到目前为止,创建的数据只是用于打印,未实现存储。因此只要确保程序能正常运行即可,不需要等待程序运行结束。等后续文章所有因子都介绍完成后,我们会进行多线程计算,并将结果保存到MySQL中。


data_center_v3.py的全部代码如下:

import baostock as bs
import datetime
import sys
import numpy as np

# 可用日线数量约束
g_available_days_limit = 250

# BaoStock日线数据字段
g_baostock_data_fields = 'date,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,peTTM,pbMRQ, psTTM,pcfNcfTTM,isST'


def get_stock_codes(date=None):
    """
    获取指定日期的A股代码列表

    若参数date为空,则返回最近1个交易日的A股代码列表
    若参数date不为空,且为交易日,则返回date当日的A股代码列表
    若参数date不为空,但不为交易日,则打印提示非交易日信息,程序退出

    :param date: 日期
    :return: A股代码的列表
    """

    # 登录baostock
    bs.login()

    # 从BaoStock查询股票数据
    stock_df = bs.query_all_stock(date).get_data()

    # 如果获取数据长度为0,表示日期date非交易日
    if 0 == len(stock_df):

        # 如果设置了参数date,则打印信息提示date为非交易日
        if date is not None:
            print('当前选择日期为非交易日或尚无交易数据,请设置date为历史某交易日日期')
            sys.exit(0)

        # 未设置参数date,则向历史查找最近的交易日,当获取股票数据长度非0时,即找到最近交易日
        delta = 1
        while 0 == len(stock_df):
            stock_df = bs.query_all_stock(datetime.date.today() - datetime.timedelta(days=delta)).get_data()
            delta += 1

    # 注销登录
    bs.logout()

    # 筛选股票数据,上证和深证股票代码在sh.600000与sz.39900之间
    stock_df = stock_df[(stock_df['code'] >= 'sh.600000') & (stock_df['code'] < 'sz.399000')]

    # 返回股票列表
    return stock_df['code'].tolist()


def create_data(stock_codes, from_date='1990-12-19', to_date=datetime.date.today().strftime('%Y-%m-%d'),
                adjustflag='2'):
    """
    下载指定日期内,指定股票的日线数据,计算扩展因子

    :param stock_codes: 待下载数据的股票代码
    :param from_date: 日线开始日期
    :param to_date: 日线结束日期
    :param adjustflag: 复权选项 1:后复权  2:前复权  3:不复权  默认为前复权
    :return: None
    """

    # 下载股票循环
    for code in stock_codes:
        print('正在下载{}...'.format(code))

        # 登录BaoStock
        bs.login()

        # 下载日线数据
        out_df = bs.query_history_k_data_plus(code, g_baostock_data_fields, start_date=from_date, end_date=to_date,
                                              frequency='d', adjustflag=adjustflag).get_data()

        # 注销登录
        bs.logout()

        # 剔除停盘数据
        if out_df.shape[0]:
            out_df = out_df[(out_df['volume'] != '0') & (out_df['volume'] != '')]

        # 如果数据为空,则不创建
        if not out_df.shape[0]:
            continue

        # 删除重复数据
        out_df.drop_duplicates(['date'], inplace=True)

        # 日线数据少于g_available_days_limit,则不创建
        if out_df.shape[0] < g_available_days_limit:
            continue

        # 将数值数据转为float型,便于后续处理
        convert_list = ['open', 'high', 'low', 'close', 'preclose', 'volume', 'amount', 'turn', 'pctChg']
        out_df[convert_list] = out_df[convert_list].astype(float)

        # 重置索引
        out_df.reset_index(drop=True, inplace=True)

        # 计算扩展因子
        out_df = extend_factor(out_df)

        print(out_df)


def extend_factor(df):
    """
    计算扩展因子

    :param df: 待计算扩展因子的DataFrame
    :return: 包含扩展因子的DataFrame
    """

    # 使用pipe计算涨停因子
    df = df.pipe(zt)

    return df


def zt(df):
    """
    计算涨停因子

    若涨停,则因子为True,否则为False
    以当日收盘价较前一日收盘价上涨9.8%及以上作为涨停判断标准

    :param df: 待计算扩展因子的DataFrame
    :return: 包含扩展因子的DataFrame
    """

    df['zt'] = np.where((df['close'].values >= 1.098 * df['preclose'].values), True, False)

    return df


if __name__ == '__main__':
    stock_codes = get_stock_codes()
    create_data(stock_codes)

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
使用baostock获取可转债指数数据
【python】baostock包:股票历史数据下载
量化投资 | ETF二八轮动策略,稳赢大盘指数
使用Python的mplfinance绘制line_K_BOLL_CCI
python 数据错位相减,上下两行相减
Pandas个人操作练习(1)创建dataframe及插入列、行操作
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服